blob: 095912a200945e196a8c3fe0c0675c050fae2abd [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.JavaErrorMessages;
import com.intellij.codeInsight.daemon.impl.*;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.colors.TextAttributesScheme;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTagValue;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.MostlySingularMultiMap;
import gnu.trove.THashMap;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil.Feature;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HighlightVisitorImpl extends JavaElementVisitor implements HighlightVisitor {
@NotNull
private final PsiResolveHelper myResolveHelper;
private HighlightInfoHolder myHolder;
private RefCountHolder myRefCountHolder;
// map codeBlock->List of PsiReferenceExpression of uninitialized final variables
private final Map<PsiElement, Collection<PsiReferenceExpression>> myUninitializedVarProblems = new THashMap<PsiElement, Collection<PsiReferenceExpression>>();
// map codeBlock->List of PsiReferenceExpression of extra initialization of final variable
private final Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> myFinalVarProblems = new THashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>();
// value==1: no info if the parameter was reassigned (but the parameter is present in current file), value==2: parameter was reassigned
private final TObjectIntHashMap<PsiParameter> myReassignedParameters = new TObjectIntHashMap<PsiParameter>();
private final Map<String, Pair<PsiImportStaticReferenceElement, PsiClass>> mySingleImportedClasses = new THashMap<String, Pair<PsiImportStaticReferenceElement, PsiClass>>();
private final Map<String, Pair<PsiImportStaticReferenceElement, PsiField>> mySingleImportedFields = new THashMap<String, Pair<PsiImportStaticReferenceElement, PsiField>>();
private PsiFile myFile;
private final PsiElementVisitor REGISTER_REFERENCES_VISITOR = new PsiRecursiveElementWalkingVisitor() {
@Override public void visitElement(PsiElement element) {
super.visitElement(element);
for (PsiReference reference : element.getReferences()) {
PsiElement resolved = reference.resolve();
if (resolved instanceof PsiNamedElement) {
myRefCountHolder.registerLocallyReferenced((PsiNamedElement)resolved);
}
}
}
};
private final Map<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>> myDuplicateMethods = new THashMap<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>>();
private LanguageLevel myLanguageLevel;
private JavaSdkVersion myJavaSdkVersion;
private static final boolean CHECK_ELEMENT_LEVEL = ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isInternal();
public HighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) {
myResolveHelper = resolveHelper;
}
@NotNull
private MostlySingularMultiMap<MethodSignature, PsiMethod> getDuplicateMethods(@NotNull PsiClass aClass) {
MostlySingularMultiMap<MethodSignature, PsiMethod> signatures = myDuplicateMethods.get(aClass);
if (signatures == null) {
signatures = new MostlySingularMultiMap<MethodSignature, PsiMethod>();
for (PsiMethod method : aClass.getMethods()) {
if (method instanceof ExternallyDefinedPsiElement) continue; // ignore aspectj-weaved methods; they are checked elsewhere
MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY);
signatures.add(signature, method);
}
myDuplicateMethods.put(aClass, signatures);
}
return signatures;
}
@Override
@NotNull
public HighlightVisitorImpl clone() {
return new HighlightVisitorImpl(myResolveHelper);
}
@Override
public int order() {
return 0;
}
@Override
public boolean suitableForFile(@NotNull PsiFile file) {
return !InjectedLanguageManager.getInstance(file.getProject()).isInjectedFragment(file);
}
@Override
public void visit(@NotNull PsiElement element) {
if (CHECK_ELEMENT_LEVEL) {
((CheckLevelHighlightInfoHolder)myHolder).enterLevel(element);
element.accept(this);
((CheckLevelHighlightInfoHolder)myHolder).enterLevel(null);
}
else {
element.accept(this);
}
}
private void registerReferencesFromInjectedFragments(@NotNull PsiElement element) {
InjectedLanguageManager.getInstance(myFile.getProject()).enumerateEx(element, myFile, false,
new PsiLanguageInjectionHost.InjectedPsiVisitor() {
@Override
public void visit(@NotNull final PsiFile injectedPsi,
@NotNull final List<PsiLanguageInjectionHost.Shred> places) {
injectedPsi.accept(REGISTER_REFERENCES_VISITOR);
}
}
);
}
@Override
public boolean analyze(@NotNull final PsiFile file,
final boolean updateWholeFile,
@NotNull final HighlightInfoHolder holder,
@NotNull final Runnable action) {
myFile = file;
myHolder = CHECK_ELEMENT_LEVEL ? new CheckLevelHighlightInfoHolder(file, holder) : holder;
boolean success = true;
try {
myLanguageLevel = PsiUtil.getLanguageLevel(file);
myJavaSdkVersion = ObjectUtils.notNull(JavaVersionService.getInstance().getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel));
if (updateWholeFile) {
Project project = file.getProject();
DaemonCodeAnalyzerEx daemonCodeAnalyzer = DaemonCodeAnalyzerEx.getInstanceEx(project);
FileStatusMap fileStatusMap = daemonCodeAnalyzer.getFileStatusMap();
ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator == null) throw new IllegalStateException("Must be run under progress");
RefCountHolder refCountHolder = RefCountHolder.startUsing(file, indicator);
myRefCountHolder = refCountHolder;
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
TextRange dirtyScope = document == null ? file.getTextRange() : fileStatusMap.getFileDirtyScope(document, Pass.UPDATE_ALL);
success = refCountHolder.analyze(file, dirtyScope, action, indicator);
}
else {
myRefCountHolder = null;
action.run();
}
}
finally {
myUninitializedVarProblems.clear();
myFinalVarProblems.clear();
mySingleImportedClasses.clear();
mySingleImportedFields.clear();
myReassignedParameters.clear();
myRefCountHolder = null;
myFile = null;
myHolder = null;
myDuplicateMethods.clear();
}
return success;
}
@Override
public void visitElement(final PsiElement element) {
if (myRefCountHolder != null && myFile instanceof ServerPageFile) {
// in jsp XmlAttributeValue may contain java references
try {
for (PsiReference reference : element.getReferences()) {
if(reference instanceof PsiJavaReference){
final PsiJavaReference psiJavaReference = (PsiJavaReference)reference;
myRefCountHolder.registerReference(psiJavaReference, psiJavaReference.advancedResolve(false));
}
}
}
catch (IndexNotReadyException ignored) {
}
}
}
@Override
public void visitAnnotation(PsiAnnotation annotation) {
super.visitAnnotation(annotation);
if (!myHolder.hasErrorResults()) myHolder.add(checkFeature(annotation, Feature.ANNOTATIONS));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkApplicability(annotation, myLanguageLevel, myFile));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkAnnotationType(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkMissingAttributes(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkTargetAnnotationDuplicates(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkDuplicateAnnotations(annotation, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkForeignInnerClassesUsed(annotation));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkFunctionalInterface(annotation, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(AnnotationsHighlightUtil.checkRepeatableAnnotation(annotation));
}
@Override
public void visitAnnotationArrayInitializer(PsiArrayInitializerMemberValue initializer) {
PsiMethod method = null;
PsiElement parent = initializer.getParent();
if (parent instanceof PsiNameValuePair) {
method = (PsiMethod)parent.getReference().resolve();
}
else if (PsiUtil.isAnnotationMethod(parent)) {
method = (PsiMethod)parent;
}
if (method != null) {
PsiType type = method.getReturnType();
if (type instanceof PsiArrayType) {
type = ((PsiArrayType)type).getComponentType();
PsiAnnotationMemberValue[] initializers = initializer.getInitializers();
for (PsiAnnotationMemberValue initializer1 : initializers) {
myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(initializer1, type));
}
}
}
}
@Override
public void visitAnnotationMethod(PsiAnnotationMethod method) {
PsiType returnType = method.getReturnType();
PsiAnnotationMemberValue value = method.getDefaultValue();
if (returnType != null && value != null) {
myHolder.add(AnnotationsHighlightUtil.checkMemberValueType(value, returnType));
}
myHolder.add(AnnotationsHighlightUtil.checkValidAnnotationType(method.getReturnTypeElement()));
final PsiClass aClass = method.getContainingClass();
myHolder.add(AnnotationsHighlightUtil.checkCyclicMemberType(method.getReturnTypeElement(), aClass));
myHolder.add(AnnotationsHighlightUtil.checkClashesWithSuperMethods(method));
if (!myHolder.hasErrorResults() && aClass != null) {
myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass)));
}
}
@Override
public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
super.visitArrayInitializerExpression(expression);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkArrayInitializerApplicable(expression));
if (!(expression.getParent() instanceof PsiNewExpression)) {
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, expression.getType()));
}
}
@Override
public void visitAssignmentExpression(PsiAssignmentExpression assignment) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssignmentCompatibleTypes(assignment));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssignmentOperatorApplicable(assignment, myFile));
if (!myHolder.hasErrorResults()) visitExpression(assignment);
}
@Override
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
super.visitPolyadicExpression(expression);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkPolyadicOperatorApplicable(expression));
}
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
myHolder.add(checkFeature(expression, Feature.LAMBDA_EXPRESSIONS));
if (!myHolder.hasErrorResults()) {
if (LambdaUtil.isValidLambdaContext(expression.getParent())) {
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
final String notFunctionalMessage = LambdaHighlightingUtil.checkInterfaceFunctional(functionalInterfaceType);
if (notFunctionalMessage != null) {
HighlightInfo result =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(notFunctionalMessage)
.create();
myHolder.add(result);
}
else {
if (!LambdaUtil.isLambdaFullyInferred(expression, functionalInterfaceType) && !expression.hasFormalParameterTypes()) {
HighlightInfo result =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Cyclic inference")
.create();
myHolder.add(result); //todo[ann] append not inferred type params info
}
else {
final String incompatibleReturnTypesMessage = LambdaHighlightingUtil
.checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType));
if (incompatibleReturnTypesMessage != null) {
HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(incompatibleReturnTypesMessage).create();
myHolder.add(result);
}
else {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod != null) {
final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
PsiElement incompatibleElt = LambdaHighlightingUtil
.checkParametersCompatible(expression, parameters, LambdaUtil.getSubstitutor(interfaceMethod, resolveResult));
if (incompatibleElt != null) {
final String incompatibleTypesMessage = "Incompatible parameter types in lambda expression";
HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(incompatibleElt)
.descriptionAndTooltip(incompatibleTypesMessage).create();
myHolder.add(result);
} else {
final PsiClass samClass = resolveResult.getElement();
if (!PsiUtil.isAccessible(myFile.getProject(), samClass, expression, null)) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(HighlightUtil.buildProblemWithAccessDescription(expression, resolveResult)).create());
}
}
}
}
}
}
} else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Cannot infer functional interface type").create());
}
}
else {
HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip("Lambda expression not expected here").create();
myHolder.add(result);
}
if (!myHolder.hasErrorResults()) {
final PsiElement body = expression.getBody();
if (body instanceof PsiCodeBlock) {
myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock)body));
}
}
}
}
@Override
public void visitBreakStatement(PsiBreakStatement statement) {
super.visitBreakStatement(statement);
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findExitedStatement()));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkBreakOutsideLoop(statement));
}
@Override
public void visitClass(PsiClass aClass) {
super.visitClass(aClass);
if (aClass instanceof PsiSyntheticClass) return;
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkInterfaceMultipleInheritance(aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkDuplicateTopLevelClass(aClass));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkEnumMustNotBeLocal(aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkImplicitThisReferenceBeforeSuper(aClass, myJavaSdkVersion));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassAndPackageConflict(aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkPublicClassInRightFile(aClass));
}
@Override
public void visitClassInitializer(PsiClassInitializer initializer) {
super.visitClassInitializer(initializer);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkInitializerCompleteNormally(initializer));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(initializer.getBody()));
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(initializer, initializer.getContainingClass()));
}
}
@Override
public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
super.visitClassObjectAccessExpression(expression);
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkClassObjectAccessExpression(expression));
}
@Override
public void visitComment(PsiComment comment) {
super.visitComment(comment);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnclosedComment(comment));
if (myRefCountHolder != null && !myHolder.hasErrorResults()) registerReferencesFromInjectedFragments(comment);
}
@Override
public void visitContinueStatement(PsiContinueStatement statement) {
super.visitContinueStatement(statement);
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkLabelDefined(statement.getLabelIdentifier(), statement.findContinuedStatement()));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkContinueOutsideLoop(statement));
}
@Override
public void visitJavaToken(PsiJavaToken token) {
super.visitJavaToken(token);
if (!myHolder.hasErrorResults()
&& token.getTokenType() == JavaTokenType.RBRACE
&& token.getParent() instanceof PsiCodeBlock) {
final PsiElement gParent = token.getParent().getParent();
final PsiCodeBlock codeBlock;
final PsiType returnType;
if (gParent instanceof PsiMethod) {
PsiMethod method = (PsiMethod)gParent;
codeBlock = method.getBody();
returnType = method.getReturnType();
}
else if (gParent instanceof PsiLambdaExpression) {
final PsiElement body = ((PsiLambdaExpression)gParent).getBody();
if (!(body instanceof PsiCodeBlock)) return;
codeBlock = (PsiCodeBlock)body;
returnType = LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)gParent);
}
else {
return;
}
myHolder.add(HighlightControlFlowUtil.checkMissingReturnStatement(codeBlock, returnType));
}
}
@Override
public void visitDocComment(PsiDocComment comment) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnclosedComment(comment));
}
@Override
public void visitDocTagValue(PsiDocTagValue value) {
PsiReference reference = value.getReference();
if (reference != null) {
PsiElement element = reference.resolve();
final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
if (element instanceof PsiMethod) {
myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)element, ((PsiDocMethodOrFieldRef)value).getNameElement(), false,
colorsScheme));
}
else if (element instanceof PsiParameter) {
myHolder.add(HighlightNamesUtil.highlightVariableName((PsiVariable)element, value.getNavigationElement(), colorsScheme));
}
}
}
@Override
public void visitEnumConstant(PsiEnumConstant enumConstant) {
super.visitEnumConstant(enumConstant);
if (!myHolder.hasErrorResults()) GenericsHighlightUtil.checkEnumConstantForConstructorProblems(enumConstant, myHolder, myJavaSdkVersion);
if (!myHolder.hasErrorResults()) registerConstructorCall(enumConstant);
}
@Override
public void visitEnumConstantInitializer(PsiEnumConstantInitializer enumConstantInitializer) {
super.visitEnumConstantInitializer(enumConstantInitializer);
if (!myHolder.hasErrorResults()) {
TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(enumConstantInitializer);
myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(enumConstantInitializer, textRange));
}
}
@Override
public void visitExpression(PsiExpression expression) {
ProgressManager.checkCanceled(); // visitLiteralExpression is invoked very often in array initializers
super.visitExpression(expression);
PsiType type = expression.getType();
if (myHolder.add(HighlightUtil.checkMustBeBoolean(expression, type))) return;
if (expression instanceof PsiArrayAccessExpression) {
myHolder.add(HighlightUtil.checkValidArrayAccessExpression((PsiArrayAccessExpression)expression));
}
if (expression.getParent() instanceof PsiNewExpression
&& ((PsiNewExpression)expression.getParent()).getQualifier() != expression
&& ((PsiNewExpression)expression.getParent()).getArrayInitializer() != expression) {
// like in 'new String["s"]'
myHolder.add(HighlightUtil.checkAssignability(PsiType.INT, expression.getType(), expression, expression));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression,myFile));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkVariableExpected(expression));
if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkArrayInitializer(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression, type,myFile));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression, type));
if (!myHolder.hasErrorResults()
&& expression.getParent() instanceof PsiThrowStatement
&& ((PsiThrowStatement)expression.getParent()).getException() == expression) {
myHolder.add(HighlightUtil.checkMustBeThrowable(type, expression, true));
}
if (!myHolder.hasErrorResults()) {
myHolder.add(AnnotationsHighlightUtil.checkConstantExpression(expression));
}
}
@Override
public void visitExpressionList(PsiExpressionList list) {
super.visitExpressionList(list);
PsiElement parent = list.getParent();
if (parent instanceof PsiMethodCallExpression) {
PsiMethodCallExpression expression = (PsiMethodCallExpression)parent;
if (expression.getArgumentList() == list) {
PsiReferenceExpression referenceExpression = expression.getMethodExpression();
JavaResolveResult result;
JavaResolveResult[] results;
try {
results = resolveOptimised(referenceExpression);
result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
catch (IndexNotReadyException e) {
return;
}
PsiElement resolved = result.getElement();
if ((!result.isAccessible() || !result.isStaticsScopeCorrect()) &&
!HighlightMethodUtil.isDummyConstructorCall(expression, myResolveHelper, list, referenceExpression) &&
// this check is for fake expression from JspMethodCallImpl
referenceExpression.getParent() == expression) {
try {
myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallArguments(referenceExpression, results, list, resolved, result, expression, myResolveHelper));
}
catch (IndexNotReadyException ignored) {
}
}
}
}
}
@Override
public void visitField(PsiField field) {
super.visitField(field);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkFinalFieldInitialized(field));
}
@Override
public void visitForStatement(PsiForStatement statement) {
myHolder.add(HighlightUtil.checkForStatement(statement));
}
@Override
public void visitForeachStatement(PsiForeachStatement statement) {
myHolder.add(checkFeature(statement, Feature.FOR_EACH));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkForeachLoopParameterType(statement));
}
@Override
public void visitImportStaticStatement(PsiImportStaticStatement statement) {
myHolder.add(checkFeature(statement, Feature.STATIC_IMPORTS));
}
@Override
public void visitIdentifier(final PsiIdentifier identifier) {
TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
PsiElement parent = identifier.getParent();
if (parent instanceof PsiVariable) {
PsiVariable variable = (PsiVariable)parent;
myHolder.add(HighlightUtil.checkVariableAlreadyDefined(variable));
if (variable.getInitializer() == null) {
final PsiElement child = variable.getLastChild();
if (child instanceof PsiErrorElement && child.getPrevSibling() == identifier) return;
}
boolean isMethodParameter = variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiMethod;
if (isMethodParameter) {
myReassignedParameters.put((PsiParameter)variable, 1); // mark param as present in current file
}
else {
// method params are highlighted in visitMethod since we should make sure the method body was visited before
if (HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems)) {
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, identifier));
}
else {
myHolder.add(HighlightNamesUtil.highlightVariableName(variable, identifier, colorsScheme));
}
}
myHolder.add(HighlightUtil.checkUnderscore(identifier, variable, myLanguageLevel));
}
else if (parent instanceof PsiClass) {
PsiClass aClass = (PsiClass)parent;
if (aClass.isAnnotationType()) {
myHolder.add(checkFeature(identifier, Feature.ANNOTATIONS));
}
myHolder.add(HighlightClassUtil.checkClassAlreadyImported(aClass, identifier));
if (!(parent instanceof PsiAnonymousClass) && aClass.getNameIdentifier() == identifier) {
myHolder.add(HighlightNamesUtil.highlightClassName(aClass, identifier, colorsScheme));
}
if (!myHolder.hasErrorResults() && myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
myHolder.add(GenericsHighlightUtil.checkUnrelatedDefaultMethods(aClass, aClass.getVisibleSignatures(), identifier));
}
}
else if (parent instanceof PsiMethod) {
PsiMethod method = (PsiMethod)parent;
if (method.isConstructor()) {
myHolder.add(HighlightMethodUtil.checkConstructorName(method));
}
myHolder.add(HighlightNamesUtil.highlightMethodName(method, identifier, true, colorsScheme));
myHolder.add(GenericsHighlightUtil.checkDefaultMethodOverrideEquivalentToObjectNonPrivate(myLanguageLevel,
method.getContainingClass(), method,
identifier));
}
super.visitIdentifier(identifier);
}
@Override
public void visitImportStatement(final PsiImportStatement statement) {
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses,myFile));
}
}
@Override
public void visitImportStaticReferenceElement(final PsiImportStaticReferenceElement ref) {
final String refName = ref.getReferenceName();
final JavaResolveResult[] results = ref.multiResolve(false);
if (results.length == 0) {
final String description = JavaErrorMessages.message("cannot.resolve.symbol", refName);
final PsiElement nameElement = ref.getReferenceNameElement();
assert nameElement != null : ref;
final HighlightInfo info =
HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(nameElement).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QuickFixFactory.getInstance().createSetupJDKFix());
myHolder.add(info);
}
else {
final PsiManager manager = ref.getManager();
for (JavaResolveResult result : results) {
final PsiElement element = result.getElement();
String description = null;
if (element instanceof PsiClass) {
final Pair<PsiImportStaticReferenceElement, PsiClass> imported = mySingleImportedClasses.get(refName);
final PsiClass aClass = imported == null ? null : imported.getSecond();
if (aClass != null && !manager.areElementsEquivalent(aClass, element)) {
description = imported.first == null
? JavaErrorMessages.message("single.import.class.conflict", refName)
: imported.first.equals(ref)
? JavaErrorMessages.message("class.is.ambiguous.in.single.static.import", refName)
: JavaErrorMessages.message("class.is.already.defined.in.single.static.import", refName);
}
mySingleImportedClasses.put(refName, Pair.create(ref, (PsiClass)element));
}
else if (element instanceof PsiField) {
final Pair<PsiImportStaticReferenceElement, PsiField> imported = mySingleImportedFields.get(refName);
final PsiField field = imported == null ? null : imported.getSecond();
if (field != null && !manager.areElementsEquivalent(field, element)) {
description = imported.first.equals(ref)
? JavaErrorMessages.message("field.is.ambiguous.in.single.static.import", refName)
: JavaErrorMessages.message("field.is.already.defined.in.single.static.import", refName);
}
mySingleImportedFields.put(refName, Pair.create(ref, (PsiField)element));
}
if (description != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref).descriptionAndTooltip(description).create());
}
}
}
}
@Override
public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
super.visitInstanceOfExpression(expression);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkInstanceOfApplicable(expression));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkInstanceOfGenericType(expression));
}
@Override
public void visitKeyword(PsiKeyword keyword) {
super.visitKeyword(keyword);
PsiElement parent = keyword.getParent();
String text = keyword.getText();
if (parent instanceof PsiModifierList) {
PsiModifierList psiModifierList = (PsiModifierList)parent;
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkNotAllowedModifier(keyword, psiModifierList));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalModifierCombination(keyword, psiModifierList));
if (PsiModifier.ABSTRACT.equals(text) && psiModifierList.getParent() instanceof PsiMethod) {
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightMethodUtil.checkAbstractMethodInConcreteClass((PsiMethod)psiModifierList.getParent(), keyword));
}
}
}
else if (PsiKeyword.INTERFACE.equals(text) && parent instanceof PsiClass) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkInterfaceCannotBeLocal((PsiClass)parent));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkStaticDeclarationInInnerClass(keyword));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalVoidType(keyword));
if (PsiTreeUtil.getParentOfType(keyword, PsiDocTagValue.class) != null) {
HighlightInfo result = HighlightInfo.newHighlightInfo(JavaHighlightInfoTypes.JAVA_KEYWORD).range(keyword).create();
myHolder.add(result);
}
}
@Override
public void visitLabeledStatement(PsiLabeledStatement statement) {
super.visitLabeledStatement(statement);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkLabelWithoutStatement(statement));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkLabelAlreadyInUse(statement));
}
@Override
public void visitLiteralExpression(PsiLiteralExpression expression) {
super.visitLiteralExpression(expression);
if (myHolder.hasErrorResults()) return;
myHolder.add(HighlightUtil.checkLiteralExpressionParsingError(expression, myLanguageLevel,myFile));
if (myRefCountHolder != null && !myHolder.hasErrorResults()) registerReferencesFromInjectedFragments(expression);
}
@Override
public void visitMethod(PsiMethod method) {
super.visitMethod(method);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement(method.getBody()));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorHandleSuperClassExceptions(method));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkRecursiveConstructorInvocation(method));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkOverrideAnnotation(method, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkSafeVarargsAnnotation(method));
PsiClass aClass = method.getContainingClass();
if (!myHolder.hasErrorResults() && method.isConstructor()) {
myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(method, aClass));
}
if (!myHolder.hasErrorResults() && method.hasModifierProperty(PsiModifier.DEFAULT)) {
myHolder.add(checkFeature(method, Feature.EXTENSION_METHODS));
}
if (!myHolder.hasErrorResults() && aClass != null && aClass.isInterface() && method.hasModifierProperty(PsiModifier.STATIC)) {
myHolder.add(checkFeature(method, Feature.EXTENSION_METHODS));
}
if (!myHolder.hasErrorResults() && aClass != null) {
myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass)));
}
// method params are highlighted in visitMethod since we should make sure the method body was visited before
PsiParameter[] parameters = method.getParameterList().getParameters();
final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
for (PsiParameter parameter : parameters) {
int info = myReassignedParameters.get(parameter);
if (info == 0) continue; // out of this file
if (info == 2) {// reassigned
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(parameter, parameter.getNameIdentifier()));
}
else {
myHolder.add(HighlightNamesUtil.highlightVariableName(parameter, parameter.getNameIdentifier(), colorsScheme));
}
}
}
private void highlightReferencedMethodOrClassName(PsiJavaCodeReferenceElement element, PsiElement resolved) {
PsiElement parent = element.getParent();
if (parent instanceof PsiReferenceExpression || parent instanceof PsiJavaCodeReferenceElement) {
return;
}
final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
if (parent instanceof PsiMethodCallExpression) {
PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod();
PsiElement methodNameElement = element.getReferenceNameElement();
if (method != null && methodNameElement != null&& !(methodNameElement instanceof PsiKeyword)) {
myHolder.add(HighlightNamesUtil.highlightMethodName(method, methodNameElement, false, colorsScheme));
myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(element, colorsScheme));
}
}
else if (parent instanceof PsiConstructorCall) {
try {
PsiMethod method = ((PsiConstructorCall)parent).resolveConstructor();
if (method == null) {
if (resolved instanceof PsiClass) {
myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass)resolved, element, colorsScheme));
}
}
else {
final PsiElement referenceNameElement = element.getReferenceNameElement();
if(referenceNameElement != null) {
// exclude type parameters from the highlighted text range
TextRange range = new TextRange(element.getTextRange().getStartOffset(), referenceNameElement.getTextRange().getEndOffset());
myHolder.add(HighlightNamesUtil.highlightMethodName(method, referenceNameElement, range, colorsScheme, false));
}
}
}
catch (IndexNotReadyException ignored) {
}
}
else if (parent instanceof PsiImportStatement && ((PsiImportStatement)parent).isOnDemand()) {
// highlight on demand import as class
myHolder.add(HighlightNamesUtil.highlightClassName(null, element, colorsScheme));
}
else if (resolved instanceof PsiClass) {
myHolder.add(HighlightNamesUtil.highlightClassName((PsiClass)resolved, element, colorsScheme));
}
}
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkEnumSuperConstructorCall(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkSuperQualifierType(myFile.getProject(), expression));
// in case of JSP synthetic method call, do not check
if (myFile.isPhysical() && !myHolder.hasErrorResults()) {
try {
myHolder.add(HighlightMethodUtil.checkMethodCall(expression, myResolveHelper, myLanguageLevel,myJavaSdkVersion));
}
catch (IndexNotReadyException ignored) {
}
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallMustBeFirstStatement(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkSuperAbstractMethodDirectCall(expression));
if (!myHolder.hasErrorResults()) visitExpression(expression);
}
@Override
public void visitModifierList(PsiModifierList list) {
super.visitModifierList(list);
PsiElement parent = list.getParent();
if (parent instanceof PsiMethod) {
PsiMethod method = (PsiMethod)parent;
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodCanHaveBody(method, myLanguageLevel));
MethodSignatureBackedByPsiMethod methodSignature = MethodSignatureBackedByPsiMethod.create(method, PsiSubstitutor.EMPTY);
if (!method.isConstructor()) {
try {
List<HierarchicalMethodSignature> superMethodSignatures = method.getHierarchicalMethodSignature().getSuperSignatures();
if (!superMethodSignatures.isEmpty()) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodIncompatibleReturnType(methodSignature, superMethodSignatures, true));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodIncompatibleThrows(methodSignature, superMethodSignatures, true, method.getContainingClass()));
if (!method.hasModifierProperty(PsiModifier.STATIC)) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodWeakerPrivileges(methodSignature, superMethodSignatures, true, myFile));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodOverridesFinal(methodSignature, superMethodSignatures));
}
}
}
catch (IndexNotReadyException ignored) {
}
}
PsiClass aClass = method.getContainingClass();
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method,myFile));
}
else if (parent instanceof PsiClass) {
PsiClass aClass = (PsiClass)parent;
try {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkDuplicateNestedClass(aClass));
if (!myHolder.hasErrorResults()) {
TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
myHolder.add(HighlightClassUtil.checkClassMustBeAbstract(aClass, textRange));
}
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightClassUtil.checkClassDoesNotCallSuperConstructorOrHandleExceptions(aClass, myRefCountHolder, myResolveHelper));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkOverrideEquivalentInheritedMethods(aClass, myFile));
if (!myHolder.hasErrorResults()) myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(myLanguageLevel, aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkCyclicInheritance(aClass));
}
catch (IndexNotReadyException ignored) {
}
}
else if (parent instanceof PsiEnumConstant) {
if (!myHolder.hasErrorResults()) myHolder.addAll(GenericsHighlightUtil.checkEnumConstantModifierList(list));
}
}
@Override
public void visitNameValuePair(PsiNameValuePair pair) {
myHolder.add(AnnotationsHighlightUtil.checkNameValuePair(pair));
if (!myHolder.hasErrorResults()) {
PsiIdentifier nameId = pair.getNameIdentifier();
if (nameId != null) {
HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ANNOTATION_ATTRIBUTE_NAME).range(nameId).create();
myHolder.add(result);
}
}
}
@Override
public void visitNewExpression(PsiNewExpression expression) {
final PsiType type = expression.getType();
final PsiClass aClass = PsiUtil.resolveClassInType(type);
myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, null));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkAnonymousInheritFinal(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkQualifiedNew(expression, type, aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(expression, type, aClass));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkTypeParameterInstantiation(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass(aClass, expression));
try {
if (!myHolder.hasErrorResults()) HighlightMethodUtil.checkNewExpression(expression, type, myHolder, myJavaSdkVersion);
}
catch (IndexNotReadyException ignored) {
}
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression, aClass));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, type));
if (!myHolder.hasErrorResults()) registerConstructorCall(expression);
if (!myHolder.hasErrorResults()) visitExpression(expression);
}
@Override
public void visitPackageStatement(PsiPackageStatement statement) {
super.visitPackageStatement(statement);
myHolder.add(AnnotationsHighlightUtil.checkPackageAnnotationContainingFile(statement));
}
@Override
public void visitParameter(PsiParameter parameter) {
super.visitParameter(parameter);
final PsiElement parent = parameter.getParent();
if (parent instanceof PsiParameterList && parameter.isVarArgs()) {
if (!myHolder.hasErrorResults()) myHolder.add(checkFeature(parameter, Feature.VARARGS));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkVarArgParameterIsLast(parameter));
}
else if (parent instanceof PsiCatchSection) {
if (!myHolder.hasErrorResults() && parameter.getType() instanceof PsiDisjunctionType) {
myHolder.add(checkFeature(parameter, Feature.MULTI_CATCH));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkCatchParameterIsThrowable(parameter));
if (!myHolder.hasErrorResults()) myHolder.addAll(GenericsHighlightUtil.checkCatchParameterIsClass(parameter));
if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkCatchTypeIsDisjoint(parameter));
}
}
@Override
public void visitParameterList(PsiParameterList list) {
super.visitParameterList(list);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAnnotationMethodParameters(list));
}
@Override
public void visitPostfixExpression(PsiPostfixExpression expression) {
super.visitPostfixExpression(expression);
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand()));
}
}
@Override
public void visitPrefixExpression(PsiPrefixExpression expression) {
super.visitPrefixExpression(expression);
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkUnaryOperatorApplicable(expression.getOperationSign(), expression.getOperand()));
}
}
private void registerConstructorCall(@NotNull PsiConstructorCall constructorCall) {
if (myRefCountHolder != null) {
JavaResolveResult resolveResult = constructorCall.resolveMethodGenerics();
final PsiElement resolved = resolveResult.getElement();
if (resolved instanceof PsiNamedElement) {
myRefCountHolder.registerLocallyReferenced((PsiNamedElement)resolved);
}
}
}
@Override
public void visitReferenceElement(PsiJavaCodeReferenceElement ref) {
JavaResolveResult resolveResult = doVisitReferenceElement(ref);
if (resolveResult != null && !myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(ref, resolveResult.getElement()));
}
private JavaResolveResult doVisitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) {
JavaResolveResult result;
try {
result = resolveOptimised(ref);
}
catch (IndexNotReadyException e) {
return null;
}
PsiElement resolved = result.getElement();
PsiElement parent = ref.getParent();
if (myRefCountHolder != null) {
myRefCountHolder.registerReference(ref, result);
}
myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel));
if (parent instanceof PsiJavaCodeReferenceElement || ref.isQualified()) {
if (!myHolder.hasErrorResults() && resolved instanceof PsiTypeParameter) {
boolean cannotSelectFromTypeParameter = !myJavaSdkVersion.isAtLeast(JavaSdkVersion.JDK_1_7);
if (!cannotSelectFromTypeParameter) {
final PsiClass containingClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class);
if (containingClass != null) {
if (PsiTreeUtil.isAncestor(containingClass.getExtendsList(), ref, false) ||
PsiTreeUtil.isAncestor(containingClass.getImplementsList(), ref, false)) {
cannotSelectFromTypeParameter = true;
}
}
}
if (cannotSelectFromTypeParameter) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Cannot select from a type parameter").range(ref).create());
}
}
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkAbstractInstantiation(ref, resolved));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved,myFile));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassExtendsForeignInnerClass(ref, resolved));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkSelectStaticClassFromParameterizedType(resolved, ref));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParameterizedReferenceTypeArguments(resolved, ref,
result.getSubstitutor(),
myJavaSdkVersion));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref));
if (resolved != null && parent instanceof PsiReferenceList) {
if (!myHolder.hasErrorResults()) {
PsiReferenceList referenceList = (PsiReferenceList)parent;
myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result, myLanguageLevel));
}
}
if (parent instanceof PsiAnonymousClass && ref.equals(((PsiAnonymousClass)parent).getBaseClassReference())) {
PsiClass aClass = (PsiClass)parent;
myHolder.addAll(GenericsHighlightUtil.checkOverrideEquivalentMethods(myLanguageLevel, aClass));
}
if (resolved instanceof PsiVariable) {
PsiVariable variable = (PsiVariable)resolved;
final PsiClass containingClass = PsiTreeUtil.getParentOfType(ref, PsiClass.class);
if (containingClass instanceof PsiAnonymousClass &&
!PsiTreeUtil.isAncestor(containingClass, variable, false) &&
!(variable instanceof PsiField)) {
if (!PsiTreeUtil.isAncestor(((PsiAnonymousClass) containingClass).getArgumentList(), ref, false)) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.IMPLICIT_ANONYMOUS_CLASS_PARAMETER).range(ref).create());
}
}
if (variable instanceof PsiParameter && ref instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression)ref)) {
myReassignedParameters.put((PsiParameter)variable, 2);
}
final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
if (!variable.hasModifierProperty(PsiModifier.FINAL) && isReassigned(variable)) {
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, ref));
}
else {
myHolder.add(HighlightNamesUtil.highlightVariableName(variable, ref.getReferenceNameElement(), colorsScheme));
}
myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(ref, colorsScheme));
}
else {
highlightReferencedMethodOrClassName(ref, resolved);
}
if (parent instanceof PsiNewExpression && !(resolved instanceof PsiClass) && resolved instanceof PsiNamedElement && ((PsiNewExpression)parent).getClassOrAnonymousClassReference() == ref) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(ref)
.descriptionAndTooltip("Cannot find symbol " + ((PsiNamedElement)resolved).getName()).create());
}
if (!myHolder.hasErrorResults() && resolved instanceof PsiClass) {
final PsiClass aClass = ((PsiClass)resolved).getContainingClass();
if (aClass != null) {
final PsiElement qualifier = ref.getQualifier();
final PsiElement place;
if (qualifier instanceof PsiJavaCodeReferenceElement) {
place = ((PsiJavaCodeReferenceElement)qualifier).resolve();
}
else {
if (parent instanceof PsiNewExpression) {
final PsiExpression newQualifier = ((PsiNewExpression)parent).getQualifier();
place = newQualifier == null ? ref : PsiUtil.resolveClassInType(newQualifier.getType());
}
else {
place = ref;
}
}
if (place != null && PsiTreeUtil.isAncestor(aClass, place, false) && aClass.hasTypeParameters()) {
myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(ref, place, (PsiClass)resolved));
}
}
else if (resolved instanceof PsiTypeParameter) {
final PsiTypeParameterListOwner owner = ((PsiTypeParameter)resolved).getOwner();
if (owner instanceof PsiClass) {
final PsiClass outerClass = (PsiClass)owner;
if (!InheritanceUtil.hasEnclosingInstanceInScope(outerClass, ref, false, false)) {
myHolder.add(HighlightClassUtil.reportIllegalEnclosingUsage(ref, aClass, (PsiClass)owner, ref));
}
}
}
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkPackageAndClassConflict(ref, myFile));
return result;
}
@NotNull
private JavaResolveResult resolveOptimised(@NotNull PsiJavaCodeReferenceElement ref) {
JavaResolveResult result;
if (ref instanceof PsiReferenceExpressionImpl) {
PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)ref;
JavaResolveResult[] results = JavaResolveUtil.resolveWithContainingFile(referenceExpression,
PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE,
true, true,
myFile);
result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
else {
result = ref.advancedResolve(true);
}
return result;
}
@NotNull
private JavaResolveResult[] resolveOptimised(@NotNull PsiReferenceExpression expression) {
JavaResolveResult[] results;
if (expression instanceof PsiReferenceExpressionImpl) {
PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)expression;
results = JavaResolveUtil.resolveWithContainingFile(referenceExpression,
PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, true, true,
myFile);
}
else {
results = expression.multiResolve(true);
}
return results;
}
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
JavaResolveResult resultForIncompleteCode = doVisitReferenceElement(expression);
if (!myHolder.hasErrorResults()) {
visitExpression(expression);
if (myHolder.hasErrorResults()) return;
}
JavaResolveResult result;
JavaResolveResult[] results;
try {
results = resolveOptimised(expression);
result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
catch (IndexNotReadyException e) {
return;
}
PsiElement resolved = result.getElement();
if (resolved instanceof PsiVariable && resolved.getContainingFile() == expression.getContainingFile()) {
if (!myHolder.hasErrorResults()) {
try {
myHolder.add(HighlightControlFlowUtil.checkVariableInitializedBeforeUsage(expression, (PsiVariable)resolved, myUninitializedVarProblems,myFile));
}
catch (IndexNotReadyException ignored) {
}
}
PsiVariable variable = (PsiVariable)resolved;
boolean isFinal = variable.hasModifierProperty(PsiModifier.FINAL);
if (isFinal && !variable.hasInitializer()) {
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightControlFlowUtil.checkFinalVariableMightAlreadyHaveBeenAssignedTo(variable, expression, myFinalVarProblems));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkFinalVariableInitializedInLoop(expression, resolved));
}
}
PsiElement parent = expression.getParent();
if (parent instanceof PsiMethodCallExpression && ((PsiMethodCallExpression)parent).getMethodExpression() == expression && (!result.isAccessible() || !result.isStaticsScopeCorrect())) {
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)parent;
PsiExpressionList list = methodCallExpression.getArgumentList();
if (!HighlightMethodUtil.isDummyConstructorCall(methodCallExpression, myResolveHelper, list, expression)) {
try {
myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallIdentifier(expression, results, list, resolved, result,
methodCallExpression, myResolveHelper));
}
catch (IndexNotReadyException ignored) {
}
}
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkExpressionRequired(expression, resultForIncompleteCode));
if (!myHolder.hasErrorResults() && resolved instanceof PsiField) {
try {
myHolder.add(HighlightUtil.checkIllegalForwardReferenceToField(expression, (PsiField)resolved));
}
catch (IndexNotReadyException ignored) {
}
}
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkAccessStaticFieldFromEnumConstructor(expression, result));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved));
myHolder.add(HighlightUtil.checkUnqualifiedSuperInDefaultMethod(myLanguageLevel, expression, expression.getQualifierExpression()));
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
myHolder.add(checkFeature(expression, Feature.METHOD_REFERENCES));
final JavaResolveResult result;
final JavaResolveResult[] results;
try {
results = expression.multiResolve(true);
result = results.length == 1 ? results[0] : JavaResolveResult.EMPTY;
}
catch (IndexNotReadyException e) {
return;
}
if (myRefCountHolder != null) {
myRefCountHolder.registerReference(expression, result);
}
final PsiElement method = result.getElement();
if (method != null && !result.isAccessible()) {
final String accessProblem = HighlightUtil.buildProblemWithAccessDescription(expression, result);
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(accessProblem).create();
myHolder.add(info);
} else {
final TextAttributesScheme colorsScheme = myHolder.getColorsScheme();
if (method instanceof PsiMethod) {
final PsiElement methodNameElement = expression.getReferenceNameElement();
myHolder.add(HighlightNamesUtil.highlightMethodName((PsiMethod)method, methodNameElement, false, colorsScheme));
}
myHolder.add(HighlightNamesUtil.highlightClassNameInQualifier(expression, colorsScheme));
}
if (!myHolder.hasErrorResults()) {
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
final boolean notFunctional = !LambdaUtil.isFunctionalType(functionalInterfaceType);
if (notFunctional) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(functionalInterfaceType.getPresentableText() + " is not a functional interface").create());
}
}
if (!myHolder.hasErrorResults()) {
final PsiElement referenceNameElement = expression.getReferenceNameElement();
if (referenceNameElement instanceof PsiKeyword) {
if (!PsiMethodReferenceUtil.isValidQualifier(expression)) {
final PsiElement qualifier = expression.getQualifier();
String description = "Cannot find class " + qualifier.getText();
HighlightInfo result1 =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(description).create();
myHolder.add(result1);
}
}
}
if (!myHolder.hasErrorResults()) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final PsiClass psiClass = resolveResult.getElement();
if (psiClass != null && !PsiUtil.isAccessible(myFile.getProject(), psiClass, expression, null)) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(HighlightUtil.buildProblemWithAccessDescription(expression, resolveResult)).create());
}
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod != null) {
if (!myHolder.hasErrorResults()) {
final String errorMessage = PsiMethodReferenceUtil.checkMethodReferenceContext(expression);
if (errorMessage != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(errorMessage).create());
}
}
if (!myHolder.hasErrorResults()) {
final String badReturnTypeMessage = PsiMethodReferenceUtil.checkReturnType(expression, result, functionalInterfaceType);
if (badReturnTypeMessage != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(badReturnTypeMessage).create());
}
}
}
}
}
if (!myHolder.hasErrorResults()) {
PsiElement qualifier = expression.getQualifier();
if (qualifier instanceof PsiTypeElement) {
final PsiType psiType = ((PsiTypeElement)qualifier).getType();
final HighlightInfo genericArrayCreationInfo = GenericsHighlightUtil.checkGenericArrayCreation(qualifier, psiType);
if (genericArrayCreationInfo != null) {
myHolder.add(genericArrayCreationInfo);
} else {
final String wildcardMessage = PsiMethodReferenceUtil.checkTypeArguments((PsiTypeElement)qualifier, psiType);
if (wildcardMessage != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(qualifier).descriptionAndTooltip(wildcardMessage).create());
}
}
}
}
if (!myHolder.hasErrorResults()) {
myHolder.add(PsiMethodReferenceHighlightingUtil.checkRawConstructorReference(expression));
}
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, expression.getTextRange()));
}
if (!myHolder.hasErrorResults() && method instanceof PsiTypeParameterListOwner) {
PsiTypeParameter[] typeParameters = ((PsiTypeParameterListOwner)method).getTypeParameters();
if (method instanceof PsiMethod) {
final PsiClass containingClass = ((PsiMethod)method).getContainingClass();
assert containingClass != null : method;
typeParameters = ArrayUtil.mergeArrays(typeParameters, containingClass.getTypeParameters());
}
myHolder.add(GenericsHighlightUtil.checkInferredTypeArguments(typeParameters, expression, result.getSubstitutor()));
}
if (!myHolder.hasErrorResults()) {
if (results.length == 0) {
String description = null;
if (expression.isConstructor()) {
final PsiClass containingClass = PsiMethodReferenceUtil.getQualifierResolveResult(expression).getContainingClass();
if (containingClass != null) {
if (!myHolder.add(HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, expression)) &&
!myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression, containingClass)) &&
containingClass.isPhysical()) {
description = JavaErrorMessages.message("cannot.resolve.constructor", containingClass.getName());
}
}
}
else {
description = JavaErrorMessages.message("cannot.resolve.method", expression.getReferenceName());
}
if (description != null) {
final PsiElement referenceNameElement = expression.getReferenceNameElement();
final HighlightInfo highlightInfo =
HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).descriptionAndTooltip(description).range(referenceNameElement).create();
myHolder.add(highlightInfo);
final TextRange fixRange = HighlightMethodUtil.getFixRange(referenceNameElement);
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().createCreateMethodFromUsageFix(expression));
}
}
}
}
@Override
public void visitReferenceList(PsiReferenceList list) {
if (list.getFirstChild() == null) return;
PsiElement parent = list.getParent();
if (!(parent instanceof PsiTypeParameter)) {
myHolder.add(AnnotationsHighlightUtil.checkAnnotationDeclaration(parent, list));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkExtendsAllowed(list));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkImplementsAllowed(list));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassExtendsOnlyOneClass(list));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkGenericCannotExtendException(list));
}
}
@Override
public void visitReferenceParameterList(PsiReferenceParameterList list) {
if (list.getTextLength() == 0) return;
myHolder.add(checkFeature(list, Feature.GENERICS));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list));
if (!myHolder.hasErrorResults()) {
for (PsiTypeElement typeElement : list.getTypeParameterElements()) {
if (typeElement.getType() instanceof PsiDiamondType) {
myHolder.add(checkFeature(list, Feature.DIAMOND_TYPES));
}
}
}
}
@Override
public void visitReturnStatement(PsiReturnStatement statement) {
try {
myHolder.add(HighlightUtil.checkReturnStatementType(statement));
}
catch (IndexNotReadyException ignore) {
}
}
@Override
public void visitStatement(PsiStatement statement) {
super.visitStatement(statement);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkNotAStatement(statement));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkStatementPrependedWithCaseInsideSwitch(statement));
}
@Override
public void visitSuperExpression(PsiSuperExpression expr) {
myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel));
if (!myHolder.hasErrorResults()) visitExpression(expr);
}
@Override
public void visitSwitchLabelStatement(PsiSwitchLabelStatement statement) {
super.visitSwitchLabelStatement(statement);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkCaseStatement(statement));
}
@Override
public void visitSwitchStatement(PsiSwitchStatement statement) {
super.visitSwitchStatement(statement);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSwitchSelectorType(statement, myLanguageLevel));
}
@Override
public void visitThisExpression(PsiThisExpression expr) {
myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier(), myLanguageLevel));
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr, null, myFile));
}
if (!myHolder.hasErrorResults()) {
visitExpression(expr);
}
}
@Override
public void visitThrowStatement(PsiThrowStatement statement) {
myHolder.add(HighlightUtil.checkUnhandledExceptions(statement, null));
if (!myHolder.hasErrorResults()) visitStatement(statement);
}
@Override
public void visitTryStatement(PsiTryStatement statement) {
super.visitTryStatement(statement);
if (!myHolder.hasErrorResults()) {
final Set<PsiClassType> thrownTypes = HighlightUtil.collectUnhandledExceptions(statement);
for (PsiParameter parameter : statement.getCatchBlockParameters()) {
boolean added = myHolder.addAll(HighlightUtil.checkExceptionAlreadyCaught(parameter));
if (!added) {
added = myHolder.addAll(HighlightUtil.checkExceptionThrownInTry(parameter, thrownTypes));
}
if (!added) {
myHolder.addAll(HighlightUtil.checkWithImprovedCatchAnalysis(parameter, thrownTypes, myFile));
}
}
}
}
@Override
public void visitResourceVariable(final PsiResourceVariable resourceVariable) {
visitVariable(resourceVariable);
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resourceVariable));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resourceVariable));
}
@Override
public void visitResourceList(PsiResourceList resourceList) {
super.visitResourceList(resourceList);
if (!myHolder.hasErrorResults()) myHolder.add(checkFeature(resourceList, Feature.TRY_WITH_RESOURCES));
}
@Override
public void visitTypeElement(final PsiTypeElement type) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalType(type));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkWildcardUsage(type));
}
@Override
public void visitTypeCastExpression(PsiTypeCastExpression typeCast) {
super.visitTypeCastExpression(typeCast);
try {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIntersectionInTypeCast(typeCast, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkInconvertibleTypeCast(typeCast));
}
catch (IndexNotReadyException ignore) {
}
}
@Override
public void visitTypeParameterList(PsiTypeParameterList list) {
PsiTypeParameter[] typeParameters = list.getTypeParameters();
if (typeParameters.length > 0) {
myHolder.add(checkFeature(list, Feature.GENERICS));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkTypeParametersList(list, typeParameters, myLanguageLevel));
}
}
@Override
public void visitVariable(PsiVariable variable) {
super.visitVariable(variable);
try {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkVariableInitializerType(variable));
}
catch (IndexNotReadyException ignored) {
}
}
private boolean isReassigned(@NotNull PsiVariable variable) {
try {
boolean reassigned;
if (variable instanceof PsiParameter) {
reassigned = myReassignedParameters.get((PsiParameter)variable) == 2;
}
else {
reassigned = HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems);
}
return reassigned;
}
catch (IndexNotReadyException e) {
return false;
}
}
@Override
public void visitConditionalExpression(PsiConditionalExpression expression) {
super.visitConditionalExpression(expression);
if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && PsiPolyExpressionUtil.isPolyExpression(expression)) {
final PsiExpression thenExpression = expression.getThenExpression();
final PsiExpression elseExpression = expression.getElseExpression();
if (thenExpression != null && elseExpression != null) {
final PsiType conditionalType = expression.getType();
if (conditionalType != null) {
final PsiExpression[] sides = new PsiExpression[] {thenExpression, elseExpression};
for (PsiExpression side : sides) {
final PsiType sideType = side.getType();
if (sideType != null && !TypeConversionUtil.isAssignable(conditionalType, sideType)) {
myHolder.add(HighlightUtil.checkAssignability(conditionalType, sideType, side, side));
}
}
}
}
}
}
@Nullable
private HighlightInfo checkFeature(@NotNull PsiElement element, @NotNull Feature feature) {
return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile);
}
}