private static boolean canWriteToFinal( @NotNull PsiVariable variable, @NotNull PsiExpression expression, @NotNull PsiReferenceExpression reference, @NotNull PsiFile containingFile) { if (variable.hasInitializer()) return false; if (variable instanceof PsiParameter) return false; PsiElement innerClass = getInnerClassVariableReferencedFrom(variable, expression); if (variable instanceof PsiField) { // if inside some field initializer if (HighlightUtil.findEnclosingFieldInitializer(expression) != null) return true; // assignment from within inner class is illegal always PsiField field = (PsiField) variable; if (innerClass != null && !containingFile .getManager() .areElementsEquivalent(innerClass, field.getContainingClass())) return false; final PsiMember enclosingCtrOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expression); return enclosingCtrOrInitializer != null && isSameField(enclosingCtrOrInitializer, field, reference, containingFile); } if (variable instanceof PsiLocalVariable) { boolean isAccessedFromOtherClass = innerClass != null; if (isAccessedFromOtherClass) { return false; } } return true; }
public static HighlightInfo checkClashesWithSuperMethods(@NotNull PsiAnnotationMethod psiMethod) { final PsiIdentifier nameIdentifier = psiMethod.getNameIdentifier(); if (nameIdentifier != null) { final PsiMethod[] methods = psiMethod.findDeepestSuperMethods(); for (PsiMethod method : methods) { final PsiClass containingClass = method.getContainingClass(); if (containingClass != null) { final String qualifiedName = containingClass.getQualifiedName(); if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName) || CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION.equals(qualifiedName)) { return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(nameIdentifier) .descriptionAndTooltip( "@interface member clashes with '" + JavaHighlightUtil.formatMethod(method) + "' in " + HighlightUtil.formatClass(containingClass)) .create(); } } } } return null; }
@Nullable public static HighlightInfo checkApplicability( @NotNull PsiAnnotation annotation, @NotNull LanguageLevel languageLevel, @NotNull PsiFile containingFile) { if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) { return null; } PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement(); if (nameRef == null) return null; PsiAnnotationOwner owner = annotation.getOwner(); PsiAnnotation.TargetType[] targets = PsiImplUtil.getTargetsForLocation(owner); if (owner == null || targets.length == 0) { String message = JavaErrorMessages.message("annotation.not.allowed.here"); return annotationError(annotation, message); } if (!(owner instanceof PsiModifierList)) { HighlightInfo info = HighlightUtil.checkTypeAnnotationFeature(annotation, languageLevel, containingFile); if (info != null) return info; } PsiAnnotation.TargetType applicable = PsiImplUtil.findApplicableTarget(annotation, targets); if (applicable == PsiAnnotation.TargetType.UNKNOWN) return null; if (applicable == null) { String target = JavaErrorMessages.message("annotation.target." + targets[0]); String message = JavaErrorMessages.message("annotation.not.applicable", nameRef.getText(), target); return annotationError(annotation, message); } if (applicable == PsiAnnotation.TargetType.TYPE_USE) { if (owner instanceof PsiClassReferenceType) { PsiJavaCodeReferenceElement ref = ((PsiClassReferenceType) owner).getReference(); HighlightInfo info = checkReferenceTarget(annotation, ref); if (info != null) return info; } else if (owner instanceof PsiModifierList) { PsiElement nextElement = PsiTreeUtil.skipSiblingsForward( (PsiModifierList) owner, PsiComment.class, PsiWhiteSpace.class, PsiTypeParameterList.class); if (nextElement instanceof PsiTypeElement) { PsiTypeElement typeElement = (PsiTypeElement) nextElement; PsiType type = typeElement.getType(); if (PsiType.VOID.equals(type)) { String message = JavaErrorMessages.message("annotation.not.allowed.void"); return annotationError(annotation, message); } if (!(type instanceof PsiPrimitiveType)) { PsiJavaCodeReferenceElement ref = getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement()); HighlightInfo info = checkReferenceTarget(annotation, ref); if (info != null) return info; } } } else if (owner instanceof PsiTypeElement) { PsiElement context = PsiTreeUtil.skipParentsOfType((PsiTypeElement) owner, PsiTypeElement.class); if (context instanceof PsiClassObjectAccessExpression) { String message = JavaErrorMessages.message("annotation.not.allowed.class"); return annotationError(annotation, message); } } } return null; }
@Nullable public static HighlightInfo checkVariableInitializedBeforeUsage( @NotNull PsiReferenceExpression expression, @NotNull PsiVariable variable, @NotNull Map<PsiElement, Collection<PsiReferenceExpression>> uninitializedVarProblems, @NotNull PsiFile containingFile) { if (variable instanceof ImplicitVariable) return null; if (!PsiUtil.isAccessedForReading(expression)) return null; int startOffset = expression.getTextRange().getStartOffset(); final PsiElement topBlock; if (variable.hasInitializer()) { topBlock = PsiUtil.getVariableCodeBlock(variable, variable); if (topBlock == null) return null; } else { PsiElement scope = variable instanceof PsiField ? ((PsiField) variable).getContainingClass() : variable.getParent() != null ? variable.getParent().getParent() : null; if (scope instanceof PsiCodeBlock && scope.getParent() instanceof PsiSwitchStatement) { scope = PsiTreeUtil.getParentOfType(scope, PsiCodeBlock.class); } topBlock = FileTypeUtils.isInServerPageFile(scope) && scope instanceof PsiFile ? scope : PsiUtil.getTopLevelEnclosingCodeBlock(expression, scope); if (variable instanceof PsiField) { // non final field already initialized with default value if (!variable.hasModifierProperty(PsiModifier.FINAL)) return null; // final field may be initialized in ctor or class initializer only // if we're inside non-ctr method, skip it if (PsiUtil.findEnclosingConstructorOrInitializer(expression) == null && HighlightUtil.findEnclosingFieldInitializer(expression) == null) { return null; } if (topBlock == null) return null; final PsiElement parent = topBlock.getParent(); // access to final fields from inner classes always allowed if (inInnerClass(expression, ((PsiField) variable).getContainingClass(), containingFile)) return null; final PsiCodeBlock block; final PsiClass aClass; if (parent instanceof PsiMethod) { PsiMethod constructor = (PsiMethod) parent; if (!containingFile .getManager() .areElementsEquivalent( constructor.getContainingClass(), ((PsiField) variable).getContainingClass())) return null; // static variables already initialized in class initializers if (variable.hasModifierProperty(PsiModifier.STATIC)) return null; // as a last chance, field may be initialized in this() call final List<PsiMethod> redirectedConstructors = JavaHighlightUtil.getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); // variable must be initialized before its usage // ??? // if (startOffset < redirectedConstructor.getTextRange().getStartOffset()) continue; PsiCodeBlock body = redirectedConstructor.getBody(); if (body != null && variableDefinitelyAssignedIn(variable, body)) { return null; } } block = constructor.getBody(); aClass = constructor.getContainingClass(); } else if (parent instanceof PsiClassInitializer) { final PsiClassInitializer classInitializer = (PsiClassInitializer) parent; if (!containingFile .getManager() .areElementsEquivalent( classInitializer.getContainingClass(), ((PsiField) variable).getContainingClass())) return null; block = classInitializer.getBody(); aClass = classInitializer.getContainingClass(); } else { // field reference outside code block // check variable initialized before its usage final PsiField field = (PsiField) variable; aClass = field.getContainingClass(); if (aClass == null || isFieldInitializedInOtherFieldInitializer( aClass, field, field.hasModifierProperty(PsiModifier.STATIC))) { return null; } final PsiField anotherField = PsiTreeUtil.getTopmostParentOfType(expression, PsiField.class); int offset = startOffset; if (anotherField != null && anotherField.getContainingClass() == aClass && !field.hasModifierProperty(PsiModifier.STATIC)) { offset = 0; } block = null; // initializers will be checked later final PsiMethod[] constructors = aClass.getConstructors(); for (PsiMethod constructor : constructors) { // variable must be initialized before its usage if (offset < constructor.getTextRange().getStartOffset()) continue; PsiCodeBlock body = constructor.getBody(); if (body != null && variableDefinitelyAssignedIn(variable, body)) { return null; } // as a last chance, field may be initialized in this() call final List<PsiMethod> redirectedConstructors = JavaHighlightUtil.getChainedConstructors(constructor); for (int j = 0; redirectedConstructors != null && j < redirectedConstructors.size(); j++) { PsiMethod redirectedConstructor = redirectedConstructors.get(j); // variable must be initialized before its usage if (offset < redirectedConstructor.getTextRange().getStartOffset()) continue; PsiCodeBlock redirectedBody = redirectedConstructor.getBody(); if (redirectedBody != null && variableDefinitelyAssignedIn(variable, redirectedBody)) { return null; } } } } if (aClass != null) { // field may be initialized in class initializer final PsiClassInitializer[] initializers = aClass.getInitializers(); for (PsiClassInitializer initializer : initializers) { PsiCodeBlock body = initializer.getBody(); if (body == block) break; // variable referenced in initializer must be initialized in initializer preceding // assignment // variable referenced in field initializer or in class initializer boolean shouldCheckInitializerOrder = block == null || block.getParent() instanceof PsiClassInitializer; if (shouldCheckInitializerOrder && startOffset < initializer.getTextRange().getStartOffset()) continue; if (initializer.hasModifierProperty(PsiModifier.STATIC) == variable.hasModifierProperty(PsiModifier.STATIC)) { if (variableDefinitelyAssignedIn(variable, body)) return null; } } } } } if (topBlock == null) return null; Collection<PsiReferenceExpression> codeBlockProblems = uninitializedVarProblems.get(topBlock); if (codeBlockProblems == null) { try { final ControlFlow controlFlow = getControlFlow(topBlock); codeBlockProblems = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow); } catch (AnalysisCanceledException | IndexNotReadyException e) { codeBlockProblems = Collections.emptyList(); } uninitializedVarProblems.put(topBlock, codeBlockProblems); } if (codeBlockProblems.contains(expression)) { final String name = expression.getElement().getText(); String description = JavaErrorMessages.message("variable.not.initialized", name); HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(expression) .descriptionAndTooltip(description) .create(); QuickFixAction.registerQuickFixAction( highlightInfo, QUICK_FIX_FACTORY.createAddVariableInitializerFix(variable)); if (variable instanceof PsiField) { QuickFixAction.registerQuickFixAction( highlightInfo, QUICK_FIX_FACTORY.createModifierListFix(variable, PsiModifier.FINAL, false, false)); } return highlightInfo; } return null; }