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