@NotNull
  private GroovyResolveResult[] doPolyResolve(boolean incompleteCode, boolean genericsMatter) {
    String name = getReferenceName();
    if (name == null) return GroovyResolveResult.EMPTY_ARRAY;

    if (incompleteCode) {
      ResolverProcessor processor = CompletionProcessor.createRefSameNameProcessor(this, name);
      new GrReferenceResolveRunner(this).resolveImpl(processor);
      GroovyResolveResult[] propertyCandidates = processor.getCandidates();
      if (propertyCandidates.length > 0 && !PsiUtil.isSingleBindingVariant(propertyCandidates))
        return propertyCandidates;
    }

    try {
      ResolveProfiler.start();
      switch (getKind()) {
        case METHOD_OR_PROPERTY:
          return resolveMethodOrProperty(false, null, genericsMatter);
        case TYPE_OR_PROPERTY:
          return resolveTypeOrProperty();
        case METHOD_OR_PROPERTY_OR_TYPE:
          GroovyResolveResult[] results = resolveMethodOrProperty(false, null, genericsMatter);
          if (results.length == 0) results = resolveTypeOrProperty();
          return results;
        default:
          return GroovyResolveResult.EMPTY_ARRAY;
      }
    } finally {
      final long time = ResolveProfiler.finish();
      ResolveProfiler.write("ref", this, time);
    }
  }
    private static PsiType doFun(GrReferenceExpression refExpr) {
      if (ResolveUtil.isClassReference(refExpr)) {
        GrExpression qualifier = refExpr.getQualifier();
        LOG.assertTrue(qualifier != null);
        return TypesUtil.createJavaLangClassType(
            qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope());
      }

      if (PsiUtil.isCompileStatic(refExpr)) {
        final GroovyResolveResult resolveResult = refExpr.advancedResolve();
        final PsiElement resolvedF = resolveResult.getElement();
        final PsiType type;
        if (resolvedF instanceof GrField) {
          type = ((GrField) resolvedF).getType();
        } else if (resolvedF instanceof GrAccessorMethod) {
          type = ((GrAccessorMethod) resolvedF).getProperty().getType();
        } else {
          type = null;
        }
        if (type != null) {
          return resolveResult.getSubstitutor().substitute(type);
        }
      }

      final PsiElement resolved = refExpr.resolve();
      final PsiType nominal = refExpr.getNominalType();

      Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr);
      if (reassigned != null && reassigned.booleanValue()) {
        return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true);
      }

      final PsiType inferred = getInferredTypes(refExpr, resolved);
      if (inferred == null) {
        if (nominal == null) {
          // inside nested closure we could still try to infer from variable initializer. Not sound,
          // but makes sense
          if (resolved instanceof GrVariable) {
            LOG.assertTrue(resolved.isValid());
            return ((GrVariable) resolved).getTypeGroovy();
          }
        }

        return nominal;
      }

      if (nominal == null) return inferred;
      if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) {
        if (resolved instanceof GrVariable
            && ((GrVariable) resolved).getTypeElementGroovy() != null) {
          return nominal;
        }
      }
      return inferred;
    }
  @Override
  public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
    final GroovyResolveResult result = advancedResolve();
    if (result.isInvokedOnProperty()) {
      final String name = GroovyPropertyUtils.getPropertyNameByAccessorName(newElementName);
      if (name != null) {
        newElementName = name;
      }
    }
    if (PsiUtil.isThisOrSuperRef(this)) return this;

    return handleElementRenameSimple(newElementName);
  }
  @Override
  public PsiElement handleElementRenameSimple(String newElementName)
      throws IncorrectOperationException {
    if (!PsiUtil.isValidReferenceName(newElementName)) {
      final PsiElement old = getReferenceNameElement();
      if (old == null) throw new IncorrectOperationException("ref has no name element");

      PsiElement element =
          GroovyPsiElementFactory.getInstance(getProject())
              .createStringLiteralForReference(newElementName);
      old.replace(element);
      return this;
    }

    return super.handleElementRenameSimple(newElementName);
  }
 @NotNull
 private MethodResolverProcessor createMethodProcessor(
     boolean allVariants,
     @Nullable String name,
     final boolean byShape,
     @Nullable GrExpression upToArgument) {
   final PsiType[] argTypes = PsiUtil.getArgumentTypes(this, false, upToArgument, byShape);
   if (byShape && argTypes != null) {
     for (int i = 0; i < argTypes.length; i++) {
       argTypes[i] = TypeConversionUtil.erasure(argTypes[i]);
     }
   }
   PsiType qualifierType = PsiImplUtil.getQualifierType(this);
   return new MethodResolverProcessor(
       name, this, false, qualifierType, argTypes, getTypeArguments(), allVariants, byShape);
 }
  @Nullable
  private PsiType getNominalTypeInner(@Nullable PsiElement resolved) {
    if (resolved == null && !"class".equals(getReferenceName())) {
      resolved = resolve();
    }

    if (resolved instanceof PsiClass) {
      final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
      if (PsiUtil.isInstanceThisRef(this)) {
        final PsiClassType categoryType = GdkMethodUtil.getCategoryType((PsiClass) resolved);
        if (categoryType != null) {
          return categoryType;
        } else {
          return factory.createType((PsiClass) resolved);
        }
      } else if (PsiUtil.isSuperReference(this)) {
        PsiClass contextClass = PsiUtil.getContextClass(this);
        if (GrTraitUtil.isTrait(contextClass)) {
          PsiClassType[] extendsTypes = contextClass.getExtendsListTypes();
          PsiClassType[] implementsTypes = contextClass.getImplementsListTypes();

          PsiClassType[] superTypes =
              ArrayUtil.mergeArrays(implementsTypes, extendsTypes, PsiClassType.ARRAY_FACTORY);

          return PsiIntersectionType.createIntersection(ArrayUtil.reverseArray(superTypes));
        }
        return factory.createType((PsiClass) resolved);
      }
      if (getParent() instanceof GrReferenceExpression) {
        return factory.createType((PsiClass) resolved);
      } else {
        return TypesUtil.createJavaLangClassType(
            factory.createType((PsiClass) resolved), getProject(), getResolveScope());
      }
    }

    if (resolved instanceof GrVariable) {
      return ((GrVariable) resolved).getDeclaredType();
    }

    if (resolved instanceof PsiVariable) {
      return ((PsiVariable) resolved).getType();
    }

    if (resolved instanceof PsiMethod) {
      PsiMethod method = (PsiMethod) resolved;
      if (PropertyUtil.isSimplePropertySetter(method)
          && !method.getName().equals(getReferenceName())) {
        return method.getParameterList().getParameters()[0].getType();
      }

      // 'class' property with explicit generic
      PsiClass containingClass = method.getContainingClass();
      if (containingClass != null
          && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName())
          && "getClass".equals(method.getName())) {
        return TypesUtil.createJavaLangClassType(
            PsiImplUtil.getQualifierType(this), getProject(), getResolveScope());
      }

      return PsiUtil.getSmartReturnType(method);
    }

    if (resolved == null) {
      final PsiType fromClassRef = getTypeFromClassRef(this);
      if (fromClassRef != null) {
        return fromClassRef;
      }

      final PsiType fromMapAccess = getTypeFromMapAccess(this);
      if (fromMapAccess != null) {
        return fromMapAccess;
      }

      final PsiType fromSpreadOperator = getTypeFromSpreadOperator(this);
      if (fromSpreadOperator != null) {
        return fromSpreadOperator;
      }
    }

    return null;
  }
  @NotNull
  private GroovyResolveResult[] resolveTypeOrPropertyInner() {
    PsiElement nameElement = getReferenceNameElement();
    String name = getReferenceName();

    if (name == null || nameElement == null) return GroovyResolveResult.EMPTY_ARRAY;

    IElementType nameType = nameElement.getNode().getElementType();
    if (nameType == GroovyTokenTypes.kTHIS) {
      GroovyResolveResult[] results = GrThisReferenceResolver.resolveThisExpression(this);
      if (results != null) {
        return results;
      }
    } else if (nameType == GroovyTokenTypes.kSUPER) {
      GroovyResolveResult[] results = GrSuperReferenceResolver.resolveSuperExpression(this);
      if (results != null) {
        return results;
      }
    }

    EnumSet<ClassHint.ResolveKind> kinds =
        getParent() instanceof GrReferenceExpression
            ? ClassHint.RESOLVE_KINDS_CLASS_PACKAGE
            : ClassHint.RESOLVE_KINDS_CLASS;

    GroovyResolveResult[] classCandidates = null;

    GrReferenceResolveRunner resolveRunner = new GrReferenceResolveRunner(this);

    ResolverProcessor processor = new PropertyResolverProcessor(name, this);
    resolveRunner.resolveImpl(processor);
    final GroovyResolveResult[] fieldCandidates = processor.getCandidates();

    if (hasAt()) {
      return fieldCandidates;
    }

    boolean canBeClassOrPackage = ResolveUtil.canBeClassOrPackage(this);

    if (canBeClassOrPackage && findClassOrPackageAtFirst()) {
      ResolverProcessor classProcessor = new ClassResolverProcessor(name, this, kinds);
      resolveRunner.resolveImpl(classProcessor);
      classCandidates = classProcessor.getCandidates();
      if (classCandidates.length > 0 && containsPackage(classCandidates)) {
        final PsiElement firstNonReferenceExprParent =
            PsiTreeUtil.skipParentsOfType(this, GrReferenceExpressionImpl.class);
        final GrReferenceExpressionImpl topRef =
            (GrReferenceExpressionImpl)
                PsiTreeUtil.findFirstParent(
                    this,
                    new Condition<PsiElement>() {
                      @Override
                      public boolean value(PsiElement parent) {
                        return parent.getParent() == firstNonReferenceExprParent
                            && parent instanceof GrReferenceExpressionImpl;
                      }
                    });
        if (topRef != null) {
          final String fqn = topRef.getTextSkipWhiteSpaceAndComments();
          if (JavaPsiFacade.getInstance(getProject()).findClass(fqn, getResolveScope()) != null) {
            return classCandidates;
          }
        }
      }
    }

    // if reference expression is in class we need to return field instead of accessor method
    for (GroovyResolveResult candidate : fieldCandidates) {
      final PsiElement element = candidate.getElement();
      if (element instanceof PsiField) {
        final PsiClass containingClass = ((PsiField) element).getContainingClass();
        if (containingClass != null && PsiUtil.getContextClass(this) == containingClass)
          return fieldCandidates;
      } else if (!(element instanceof GrBindingVariable)) {
        return fieldCandidates;
      }
    }

    if (classCandidates != null && classCandidates.length > 0) return classCandidates;

    final boolean isLValue = PsiUtil.isLValue(this);
    String[] accessorNames =
        isLValue
            ? GroovyPropertyUtils.suggestSettersName(name)
            : GroovyPropertyUtils.suggestGettersName(name);
    List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>();
    for (String accessorName : accessorNames) {
      AccessorResolverProcessor accessorResolver =
          new AccessorResolverProcessor(
              accessorName,
              name,
              this,
              !isLValue,
              false,
              PsiImplUtil.getQualifierType(this),
              getTypeArguments());
      resolveRunner.resolveImpl(accessorResolver);
      final GroovyResolveResult[] candidates = accessorResolver.getCandidates();

      // can be only one correct candidate or some incorrect
      if (candidates.length == 1 && candidates[0].isStaticsOK() && candidates[0].isAccessible()) {
        return candidates;
      } else {
        ContainerUtil.addAll(accessorResults, candidates);
      }
    }

    final ArrayList<GroovyResolveResult> fieldList = ContainerUtil.newArrayList(fieldCandidates);
    filterOutBindings(fieldList);
    if (!fieldList.isEmpty()) {
      return fieldList.toArray(new GroovyResolveResult[fieldList.size()]);
    }

    if (classCandidates == null && canBeClassOrPackage) {
      ResolverProcessor classProcessor = new ClassResolverProcessor(name, this, kinds);
      resolveRunner.resolveImpl(classProcessor);
      classCandidates = classProcessor.getCandidates();
    }

    if (classCandidates != null && classCandidates.length > 0) return classCandidates;
    if (!accessorResults.isEmpty()) return new GroovyResolveResult[] {accessorResults.get(0)};
    return GroovyResolveResult.EMPTY_ARRAY;
  }