private static void registerReferenceFixes(
      GrReferenceExpression refExpr,
      HighlightInfo info,
      boolean compileStatic,
      final HighlightDisplayKey key) {
    PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr, compileStatic);
    if (targetClass == null) return;

    if (!compileStatic) {
      addDynamicAnnotation(info, refExpr, key);
    }
    if (targetClass.isWritable()) {
      QuickFixAction.registerQuickFixAction(
          info, new CreateFieldFromUsageFix(refExpr, targetClass), key);

      if (refExpr.getParent() instanceof GrCall && refExpr.getParent() instanceof GrExpression) {
        QuickFixAction.registerQuickFixAction(
            info, new CreateMethodFromUsageFix(refExpr, targetClass), key);
      }
    }

    if (!refExpr.isQualified()) {
      GrVariableDeclarationOwner owner =
          PsiTreeUtil.getParentOfType(refExpr, GrVariableDeclarationOwner.class);
      if (!(owner instanceof GroovyFileBase) || ((GroovyFileBase) owner).isScript()) {
        QuickFixAction.registerQuickFixAction(
            info, new CreateLocalVariableFromUsageFix(refExpr, owner), key);
      }
      if (PsiTreeUtil.getParentOfType(refExpr, GrMethod.class) != null) {
        QuickFixAction.registerQuickFixAction(info, new CreateParameterFromUsageFix(refExpr), key);
      }
    }
  }
 private static boolean isPropertyAccessInStaticMethod(GrReferenceExpression referenceExpression) {
   if (referenceExpression.getParent() instanceof GrMethodCall
       || referenceExpression.getQualifier() != null) return false;
   GrMember context =
       PsiTreeUtil.getParentOfType(
           referenceExpression, GrMember.class, true, GrClosableBlock.class);
   return (context instanceof GrMethod || context instanceof GrClassInitializer)
       && context.hasModifierProperty(STATIC);
 }
  @Nullable
  private static HighlightInfo checkRefInner(GrReferenceExpression ref) {
    PsiElement refNameElement = ref.getReferenceNameElement();
    if (refNameElement == null) return null;

    boolean cannotBeDynamic = PsiUtil.isCompileStatic(ref) || isPropertyAccessInStaticMethod(ref);
    GroovyResolveResult resolveResult = getBestResolveResult(ref);

    if (resolveResult.getElement() != null) {
      if (!isInspectionEnabled(ref.getContainingFile(), ref.getProject())) return null;

      if (isStaticOk(resolveResult)) return null;
      String message = GroovyBundle.message("cannot.reference.non.static", ref.getReferenceName());
      return createAnnotationForRef(ref, cannotBeDynamic, message);
    }

    if (ResolveUtil.isKeyOfMap(ref) || isClassReference(ref)) {
      return null;
    }

    if (!cannotBeDynamic) {
      if (!isInspectionEnabled(ref.getContainingFile(), ref.getProject())) return null;
      GrUnresolvedAccessInspection inspection =
          getInstance(ref.getContainingFile(), ref.getProject());

      if (!inspection.myHighlightIfGroovyObjectOverridden && areGroovyObjectMethodsOverridden(ref))
        return null;
      if (!inspection.myHighlightIfMissingMethodsDeclared && areMissingMethodsDeclared(ref))
        return null;

      if (GroovySuppressableInspectionTool.isElementToolSuppressedIn(ref, SHORT_NAME)) return null;
    }

    if (cannotBeDynamic || shouldHighlightAsUnresolved(ref)) {
      HighlightInfo info =
          createAnnotationForRef(
              ref, cannotBeDynamic, GroovyBundle.message("cannot.resolve", ref.getReferenceName()));
      LOG.assertTrue(info != null);

      HighlightDisplayKey displayKey = HighlightDisplayKey.find(SHORT_NAME);
      if (ref.getParent() instanceof GrMethodCall) {
        registerStaticImportFix(ref, info, displayKey);
      } else {
        registerCreateClassByTypeFix(ref, info, displayKey);
        registerAddImportFixes(ref, info, displayKey);
      }

      registerReferenceFixes(ref, info, cannotBeDynamic, displayKey);
      UnresolvedReferenceQuickFixProvider.registerReferenceFixes(
          ref, new QuickFixActionRegistrarAdapter(info, displayKey));
      OrderEntryFix.registerFixes(new QuickFixActionRegistrarAdapter(info, displayKey), ref);
      return info;
    }

    return null;
  }
  private static void registerStaticImportFix(
      @NotNull GrReferenceExpression referenceExpression,
      @Nullable HighlightInfo info,
      @Nullable final HighlightDisplayKey key) {
    final String referenceName = referenceExpression.getReferenceName();
    if (StringUtil.isEmpty(referenceName)) return;
    if (referenceExpression.getQualifier() != null) return;

    QuickFixAction.registerQuickFixAction(
        info, new GroovyStaticImportMethodFix((GrMethodCall) referenceExpression.getParent()), key);
  }
  private static boolean areMissingMethodsDeclared(GrReferenceExpression ref) {
    PsiType qualifierType = GrReferenceResolveUtil.getQualifierType(ref);
    if (!(qualifierType instanceof PsiClassType)) return false;

    PsiClass resolved = ((PsiClassType) qualifierType).resolve();
    if (resolved == null) return false;

    if (ref.getParent() instanceof GrCall) {
      PsiMethod[] found = resolved.findMethodsByName("methodMissing", true);
      for (PsiMethod method : found) {
        if (MissingMethodAndPropertyUtil.isMethodMissing(method)) return true;
      }
    } else {
      PsiMethod[] found = resolved.findMethodsByName("propertyMissing", true);
      for (PsiMethod method : found) {
        if (MissingMethodAndPropertyUtil.isPropertyMissing(method)) return true;
      }
    }

    return false;
  }
  private static boolean areGroovyObjectMethodsOverridden(GrReferenceExpression ref) {
    PsiType qualifierType = GrReferenceResolveUtil.getQualifierType(ref);
    if (!(qualifierType instanceof PsiClassType)) return false;

    PsiClass resolved = ((PsiClassType) qualifierType).resolve();
    if (resolved == null) return false;

    PsiClass groovyObject =
        JavaPsiFacade.getInstance(ref.getProject())
            .findClass(GroovyCommonClassNames.GROOVY_OBJECT, ref.getResolveScope());
    if (groovyObject == null) return false;

    String methodName;
    if (ref.getParent() instanceof GrCall) {
      methodName = "invokeMethod";
    } else if (PsiUtil.isLValue(ref)) {
      methodName = "setProperty";
    } else {
      methodName = "getProperty";
    }

    PsiMethod[] patternMethods = groovyObject.findMethodsByName(methodName, false);
    if (patternMethods.length != 1) return false;

    PsiMethod patternMethod = patternMethods[0];
    PsiMethod found = resolved.findMethodBySignature(patternMethod, true);
    if (found == null) return false;

    PsiClass aClass = found.getContainingClass();
    if (aClass == null) return false;
    String qname = aClass.getQualifiedName();
    if (GroovyCommonClassNames.GROOVY_OBJECT.equals(qname)) return false;
    if (GroovyCommonClassNames.GROOVY_OBJECT_SUPPORT.equals(qname)) return false;

    return true;
  }