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;
  }