| /* |
| * Copyright 2000-2013 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.impl.DaemonCodeAnalyzerEx; |
| 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.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.Comparing; |
| 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.FunctionalInterfaceParameterizationUtil; |
| 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.ObjectUtils; |
| import com.intellij.util.containers.MostlySingularMultiMap; |
| import gnu.trove.THashMap; |
| import gnu.trove.TObjectIntHashMap; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| public class HighlightVisitorImpl extends JavaElementVisitor implements HighlightVisitor { |
| 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; |
| |
| public HighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) { |
| myResolveHelper = resolveHelper; |
| } |
| |
| @NotNull |
| private MostlySingularMultiMap<MethodSignature, PsiMethod> getDuplicateMethods(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) { |
| 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 HighlightInfoHolder holder, |
| @NotNull final Runnable action) { |
| myFile = file; |
| myHolder = 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(HighlightUtil.checkAnnotationFeature(annotation, myLanguageLevel, myFile)); |
| 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)); |
| 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())); |
| myHolder.add(AnnotationsHighlightUtil.checkCyclicMemberType(method.getReturnTypeElement(), method.getContainingClass())); |
| myHolder.add(AnnotationsHighlightUtil.checkClashesWithSuperMethods(method)); |
| } |
| |
| @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(HighlightUtil.checkLambdaFeature(expression, myLanguageLevel,myFile)); |
| 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(); |
| final PsiParameter[] lambdaParameters = expression.getParameterList().getParameters(); |
| final String incompatibleTypesMessage = "Incompatible parameter types in lambda expression"; |
| if (lambdaParameters.length != parameters.length) { |
| HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression) |
| .descriptionAndTooltip(incompatibleTypesMessage).create(); |
| myHolder.add(result); |
| } |
| else { |
| final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult); |
| if (expression.hasFormalParameterTypes()) { |
| for (int i = 0; i < lambdaParameters.length; i++) { |
| if (!Comparing.equal(lambdaParameters[i].getType(), substitutor.substitute(parameters[i].getType()))) { |
| HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) |
| .range(lambdaParameters[i]) |
| .descriptionAndTooltip(incompatibleTypesMessage) |
| .create(); |
| myHolder.add(result); |
| break; |
| } |
| } |
| } else { |
| for (int i = 0; i < lambdaParameters.length; i++) { |
| PsiParameter lambdaParameter = lambdaParameters[i]; |
| if (!TypeConversionUtil.isAssignable(lambdaParameter.getType(), |
| GenericsUtil.eliminateWildcards(substitutor.substitute(parameters[i].getType())))) { |
| HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(lambdaParameter) |
| .descriptionAndTooltip(incompatibleTypesMessage).create(); |
| myHolder.add(result); |
| break; |
| } |
| } |
| } |
| } |
| if (!myHolder.hasErrorResults()) { |
| 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 { |
| 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())); |
| } |
| } |
| |
| @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)); |
| } |
| |
| @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())); |
| } |
| } |
| |
| @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 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(final PsiForeachStatement statement) { |
| myHolder.add(HighlightUtil.checkForEachFeature(statement, myLanguageLevel, myFile)); |
| } |
| |
| @Override |
| public void visitImportStaticStatement(final PsiImportStaticStatement statement) { |
| myHolder.add(HighlightUtil.checkStaticImportFeature(statement, myLanguageLevel, myFile)); |
| } |
| |
| @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) { // 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)); |
| } |
| } |
| else { |
| myReassignedParameters.put((PsiParameter)variable, 1); // mark param as present in current file |
| } |
| |
| myHolder.add(HighlightUtil.checkUnderscore(identifier, variable)); |
| } |
| else if (parent instanceof PsiClass) { |
| PsiClass aClass = (PsiClass)parent; |
| if (aClass.isAnnotationType()) { |
| myHolder.add(HighlightUtil.checkAnnotationFeature(identifier, myLanguageLevel, myFile)); |
| } |
| |
| myHolder.add(HighlightClassUtil.checkClassAlreadyImported(aClass, identifier)); |
| if (!(parent instanceof PsiAnonymousClass) && aClass.getNameIdentifier() == identifier) { |
| myHolder.add(HighlightNamesUtil.highlightClassName(aClass, identifier, colorsScheme)); |
| } |
| } |
| 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)); |
| } |
| else { |
| visitParentReference(parent); |
| } |
| |
| super.visitIdentifier(identifier); |
| } |
| |
| private void visitParentReference(PsiElement parent) { |
| if (parent instanceof PsiJavaCodeReferenceElement && !(parent.getParent() instanceof PsiJavaCodeReferenceElement) && |
| !((PsiJavaCodeReferenceElement)parent).isQualified()) { |
| PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement)parent; |
| JavaResolveResult result; |
| try { |
| result = ref.advancedResolve(true); |
| } |
| catch (IndexNotReadyException e) { |
| return; |
| } |
| myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel)); |
| if (myRefCountHolder != null) { |
| myRefCountHolder.registerReference(ref, result); |
| } |
| } |
| } |
| |
| @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 (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkPublicClassInRightFile(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.CONTINUE.equals(text) && parent instanceof PsiContinueStatement) { |
| PsiContinueStatement statement = (PsiContinueStatement)parent; |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkContinueOutsideLoop(statement)); |
| } |
| else if (PsiKeyword.BREAK.equals(text) && parent instanceof PsiBreakStatement) { |
| PsiBreakStatement statement = (PsiBreakStatement)parent; |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkBreakOutsideLoop(statement)); |
| } |
| else if (PsiKeyword.INTERFACE.equals(text) && parent instanceof PsiClass) { |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkInterfaceCannotBeLocal((PsiClass)parent)); |
| } |
| else { |
| visitParentReference(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)); |
| if (!myHolder.hasErrorResults() && method.isConstructor()) { |
| myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(method, method.getContainingClass())); |
| } |
| |
| // 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()) 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,myFile)); |
| 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.checkDuplicateMethod(aClass, method, getDuplicateMethods(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.add(GenericsHighlightUtil.checkOverrideEquivalentMethods(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) { |
| myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, null)); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkAnonymousInheritFinal(expression)); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkQualifiedNew(expression)); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkCreateInnerClassFromStaticContext(expression)); |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkTypeParameterInstantiation(expression)); |
| try { |
| if (!myHolder.hasErrorResults()) HighlightMethodUtil.checkNewExpression(expression, myHolder, myJavaSdkVersion); |
| } |
| catch (IndexNotReadyException ignored) { |
| } |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkEnumInstantiation(expression)); |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkGenericArrayCreation(expression, expression.getType())); |
| 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) { |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkVarArgParameterIsLast(parameter, |
| myLanguageLevel,myFile)); |
| } |
| else if (parent instanceof PsiForeachStatement) { |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkForeachLoopParameterType((PsiForeachStatement)parent)); |
| } |
| else if (parent instanceof PsiCatchSection) { |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkMultiCatchFeature(parameter, myLanguageLevel,myFile)); |
| 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(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) { |
| doVisitReferenceElement(ref); |
| } |
| |
| private JavaResolveResult doVisitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) { |
| JavaResolveResult result; |
| try { |
| 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); |
| } |
| } |
| catch (IndexNotReadyException e) { |
| return null; |
| } |
| PsiElement resolved = result.getElement(); |
| PsiElement parent = ref.getParent(); |
| |
| if (parent instanceof PsiJavaCodeReferenceElement || ref.isQualified()) { |
| if (myRefCountHolder != null) { |
| myRefCountHolder.registerReference(ref, result); |
| } |
| myHolder.add(HighlightUtil.checkReference(ref, result, myFile, myLanguageLevel)); |
| 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())) { |
| myHolder.add(GenericsHighlightUtil.checkOverrideEquivalentMethods((PsiClass)parent)); |
| } |
| |
| 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 (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, true, false)) { |
| myHolder.add(HighlightClassUtil.reportIllegalEnclosingUsage(ref, aClass, (PsiClass)owner, ref)); |
| } |
| } |
| } |
| } |
| |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkPackageAndClassConflict(ref)); |
| |
| return result; |
| } |
| |
| @Override |
| public void visitReferenceExpression(PsiReferenceExpression expression) { |
| JavaResolveResult resultForIncompleteCode = doVisitReferenceElement(expression); |
| if (!myHolder.hasErrorResults()) { |
| visitExpression(expression); |
| if (myHolder.hasErrorResults()) return; |
| } |
| JavaResolveResult result; |
| JavaResolveResult[] results; |
| try { |
| if (expression instanceof PsiReferenceExpressionImpl) { |
| PsiReferenceExpressionImpl referenceExpression = (PsiReferenceExpressionImpl)expression; |
| results = JavaResolveUtil.resolveWithContainingFile(referenceExpression, |
| PsiReferenceExpressionImpl.OurGenericsResolver.INSTANCE, true, true, |
| myFile); |
| } |
| else { |
| results = expression.multiResolve(true); |
| } |
| 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 { |
| HighlightInfo info = HighlightMethodUtil.checkAmbiguousMethodCall(expression, results, list, resolved, result, methodCallExpression, myResolveHelper); |
| myHolder.add(info); |
| } |
| 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(HighlightMethodUtil.checkConstructorCallMustBeFirstStatement(expression)); |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkAccessStaticFieldFromEnumConstructor(expression, result)); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkClassReferenceAfterQualifier(expression, resolved)); |
| } |
| |
| @Override |
| public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) { |
| myHolder.add(HighlightUtil.checkMethodReferencesFeature(expression, myLanguageLevel,myFile)); |
| JavaResolveResult result; |
| try { |
| result = expression.advancedResolve(true); |
| } |
| 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); |
| } |
| if (!myHolder.hasErrorResults()) { |
| final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType(); |
| if (functionalInterfaceType != null && LambdaUtil.dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression)) { |
| HighlightInfo result1 = |
| HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Cyclic inference").create(); |
| myHolder.add(result1); //todo[ann] append not inferred type params info |
| } else { |
| 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()); |
| } |
| } |
| |
| if (functionalInterfaceType != null && LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null && !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()) { |
| myHolder.add(HighlightUtil.checkUnhandledExceptions(expression, expression.getTextRange())); |
| } |
| } |
| |
| @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) { |
| myHolder.add(GenericsHighlightUtil.checkParametersAllowed(list, myLanguageLevel,myFile)); |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkParametersOnRaw(list)); |
| if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(list)); |
| } |
| |
| @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())); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkAbstractMethodDirectCall(expr)); |
| 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)); |
| } |
| |
| @Override |
| public void visitThisExpression(PsiThisExpression expr) { |
| myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier())); |
| 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.checkTryWithResourcesFeature(resourceVariable, myLanguageLevel,myFile)); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTryResourceIsAutoCloseable(resourceVariable)); |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkUnhandledCloserExceptions(resourceVariable)); |
| } |
| |
| @Override |
| public void visitTypeElement(final PsiTypeElement type) { |
| if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkDiamondFeature(type, myLanguageLevel,myFile)); |
| 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.checkInconvertibleTypeCast(typeCast)); |
| } |
| catch (IndexNotReadyException ignore) { |
| } |
| } |
| |
| @Override |
| public void visitTypeParameterList(PsiTypeParameterList list) { |
| myHolder.add(GenericsHighlightUtil.checkTypeParametersList(list, myLanguageLevel,myFile)); |
| } |
| |
| @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; |
| } |
| } |
| } |