@Nullable
  public static GrExpression getRuntimeQualifier(GrReferenceExpression refExpr) {
    GrExpression qualifier = refExpr.getQualifierExpression();
    if (qualifier != null) return qualifier;

    for (GrClosableBlock closure = PsiTreeUtil.getParentOfType(refExpr, GrClosableBlock.class);
        closure != null;
        closure = PsiTreeUtil.getParentOfType(closure, GrClosableBlock.class)) {

      PsiElement parent = closure.getParent();
      if (parent instanceof GrArgumentList) parent = parent.getParent();
      if (!(parent instanceof GrMethodCall)) continue;

      GrExpression funExpr = ((GrMethodCall) parent).getInvokedExpression();
      if (!(funExpr instanceof GrReferenceExpression)) return funExpr;

      final PsiElement resolved = ((GrReferenceExpression) funExpr).resolve();
      if (!(resolved instanceof PsiMethod)) return funExpr;

      if (resolved instanceof GrGdkMethod
          && isFromDGM((GrGdkMethod) resolved)
          && !GdkMethodUtil.isWithName(((GrGdkMethod) resolved).getStaticMethod().getName())) {
        continue;
      }

      qualifier = ((GrReferenceExpression) funExpr).getQualifierExpression();
      if (qualifier != null) return qualifier;
    }

    return null;
  }
 public static boolean hasNamedArguments(@Nullable GrNamedArgumentsOwner list) {
   if (list == null) return false;
   for (PsiElement child = list.getFirstChild(); child != null; child = child.getNextSibling()) {
     if (child instanceof GrNamedArgument) return true;
   }
   return false;
 }
 public static void deleteStatementTail(PsiElement container, @NotNull PsiElement statement) {
   PsiElement next = statement.getNextSibling();
   while (next != null) {
     final ASTNode node = next.getNode();
     final IElementType type = node.getElementType();
     if (type == mSEMI) {
       final PsiElement nnext = next.getNextSibling();
       container.deleteChildRange(next, next);
       next = nnext;
     } else if (type == mNLS || type == TokenType.WHITE_SPACE && next.getText().contains("\n")) {
       final String text = next.getText();
       final int first = text.indexOf("\n");
       final int second = text.indexOf("\n", first + 1);
       if (second < 0) {
         container.deleteChildRange(next, next);
         return;
       }
       final String substring = text.substring(second);
       container
           .getNode()
           .replaceChild(
               node,
               createSingleLeafElement(
                   type, substring, 0, substring.length(), null, container.getManager()));
       return;
     } else {
       break;
     }
   }
 }
  public static boolean hasExpressionArguments(@Nullable GrArgumentList list) {
    if (list == null) return false;

    for (PsiElement child = list.getFirstChild(); child != null; child = child.getNextSibling()) {
      if (child instanceof GrExpression) return true;
    }
    return false;
  }
  public static boolean hasClosureArguments(@Nullable GrCall call) {
    if (call == null) return false;

    for (PsiElement child = call.getFirstChild(); child != null; child = child.getNextSibling()) {
      if (child instanceof GrClosableBlock) return true;
    }
    return false;
  }
  public static PsiElement findTailingSemicolon(@NotNull GrStatement statement) {
    final PsiElement nextNonSpace = PsiUtil.skipWhitespaces(statement.getNextSibling(), true);
    if (nextNonSpace != null && nextNonSpace.getNode().getElementType() == mSEMI) {
      return nextNonSpace;
    }

    return null;
  }
  public void replaceDotToken(PsiElement newDot) {
    if (newDot == null) return;
    if (!TokenSets.DOTS.contains(newDot.getNode().getElementType())) return;
    final PsiElement oldDot = getDotToken();
    if (oldDot == null) return;

    getNode().replaceChild(oldDot.getNode(), newDot.getNode());
  }
 @Override
 public void visitParenthesizedExpression(GrParenthesizedExpression expression) {
   final PsiElement parent = expression.getParent();
   if (parent instanceof GroovyPsiElement) {
     ((GroovyPsiElement) parent).accept(this);
   } else {
     parent.accept(new GroovyPsiElementVisitor(this));
   }
 }
  private static boolean isStaticOk(GroovyResolveResult resolveResult) {
    if (resolveResult.isStaticsOK()) return true;

    PsiElement resolved = resolveResult.getElement();
    LOG.assertTrue(resolved != null);
    LOG.assertTrue(resolved instanceof PsiModifierListOwner, resolved + " : " + resolved.getText());

    return ((PsiModifierListOwner) resolved).hasModifierProperty(STATIC);
  }
 public static GrStatement[] getStatements(final GrStatementOwner statementOwner) {
   List<GrStatement> result = new ArrayList<GrStatement>();
   for (PsiElement cur = statementOwner.getFirstChild(); cur != null; cur = cur.getNextSibling()) {
     if (cur instanceof GrStatement) {
       result.add((GrStatement) cur);
     }
   }
   return result.toArray(new GrStatement[result.size()]);
 }
 /** @return leading regex or null if it does not exist */
 @Nullable
 private static GrLiteral getRegexAtTheBeginning(PsiElement expr) {
   PsiElement fchild = expr;
   while (fchild != null) {
     if (fchild instanceof GrLiteral && GrStringUtil.isRegex((GrLiteral) fchild))
       return (GrLiteral) fchild;
     fchild = fchild.getFirstChild();
   }
   return null;
 }
    @Override
    public void visitCaseLabel(GrCaseLabel caseLabel) {
      final PsiElement parent = caseLabel.getParent().getParent();
      assert parent instanceof GrSwitchStatement : parent + " of class " + parent.getClass();
      final GrExpression condition = ((GrSwitchStatement) parent).getCondition();
      if (condition == null) return;

      final PsiType type = condition.getType();
      if (type == null) return;

      myResult = new TypeConstraint[] {SubtypeConstraint.create(type)};
    }
  public String getReferenceName() {
    PsiElement nameElement = getReferenceNameElement();
    if (nameElement != null) {
      IElementType nodeType = nameElement.getNode().getElementType();
      if (TokenSets.STRING_LITERAL_SET.contains(nodeType)) {
        final Object value = GrLiteralImpl.getLiteralValue(nameElement);
        if (value instanceof String) {
          return (String) value;
        }
      }

      return nameElement.getText();
    }
    return null;
  }
  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);
  }
    @Override
    public void visitAnnotationArrayInitializer(GrAnnotationArrayInitializer arrayInitializer) {
      final GrAnnotationNameValuePair nameValuePair =
          PsiTreeUtil.getParentOfType(
              arrayInitializer,
              GrAnnotationNameValuePair.class,
              true,
              GrDefaultAnnotationValue.class);
      if (nameValuePair != null) {

        final PsiClass annot = ResolveUtil.resolveAnnotation(arrayInitializer);
        if (annot == null) return;

        final String name = nameValuePair.getName();
        if (name == null) return;

        final PsiMethod[] attrs = annot.findMethodsByName(name, false);
        if (attrs.length > 0) {
          PsiType type = attrs[0].getReturnType();
          while (type instanceof PsiArrayType) type = ((PsiArrayType) type).getComponentType();
          if (type != null && isAcceptableAnnotationValueType(type)) {
            myResult = createSimpleSubTypeResult(type);
          }
        }
      } else {
        final GrAnnotationMethod method =
            PsiTreeUtil.getParentOfType(arrayInitializer, GrAnnotationMethod.class);
        assert method != null;

        PsiType type = method.getReturnType();

        int count = 1;
        PsiElement parent = arrayInitializer.getParent();
        while (parent instanceof GrAnnotationArrayInitializer) {
          count++;
          parent = parent.getParent();
        }

        while (type instanceof PsiArrayType && count > 0) {
          type = ((PsiArrayType) type).getComponentType();
          count--;
        }
        if (type != null && isAcceptableAnnotationValueType(type)) {
          myResult = createSimpleSubTypeResult(type);
        }
      }
    }
  public static void removeVariable(GrVariable variable) {
    final GrVariableDeclaration varDecl = (GrVariableDeclaration) variable.getParent();
    final List<GrVariable> variables = Arrays.asList(varDecl.getVariables());
    if (!variables.contains(variable)) {
      throw new IllegalArgumentException();
    }

    final PsiElement parent = varDecl.getParent();
    final ASTNode owner = parent.getNode();
    if (variables.size() == 1 && owner != null) {
      PsiElement next = varDecl.getNextSibling();

      // remove redundant semicolons
      //noinspection ConstantConditions
      while (next != null && next.getNode() != null && next.getNode().getElementType() == mSEMI) {
        PsiElement tmpNext = next.getNextSibling();
        //noinspection ConstantConditions
        next.delete();
        next = tmpNext;
      }

      removeNewLineAfter(varDecl);
      varDecl.delete();
      return;
    }
    variable.delete();
  }
 @Nullable
 private InstructionImpl findInstruction(PsiElement element) {
   final Iterator<InstructionImpl> iterator = myProcessingStack.descendingIterator();
   while (iterator.hasNext()) {
     final InstructionImpl instruction = iterator.next();
     if (element.equals(instruction.getElement())) return instruction;
   }
   return null;
 }
 @Nullable
 public static PsiElement realPrevious(PsiElement previousLeaf) {
   while (previousLeaf != null
       && (previousLeaf instanceof PsiWhiteSpace
           || previousLeaf instanceof PsiComment
           || previousLeaf instanceof PsiErrorElement)) {
     previousLeaf = previousLeaf.getPrevSibling();
   }
   return previousLeaf;
 }
 public static <T extends PsiElement> void setQualifier(
     @NotNull GrQualifiedReference<T> ref, @Nullable T newQualifier) {
   final T oldQualifier = ref.getQualifier();
   final ASTNode node = ref.getNode();
   final PsiElement refNameElement = ref.getReferenceNameElement();
   if (newQualifier == null) {
     if (oldQualifier != null && refNameElement != null) {
       ref.deleteChildRange(ref.getFirstChild(), refNameElement.getPrevSibling());
     }
   } else {
     if (oldQualifier == null) {
       if (refNameElement != null) {
         node.addLeaf(mDOT, ".", refNameElement.getNode());
         ref.addBefore(newQualifier, refNameElement.getPrevSibling());
       }
     } else {
       oldQualifier.replace(newQualifier);
     }
   }
 }
  private void processMethods(final MethodResolverProcessor methodResolver) {
    GrReferenceResolveUtil.resolveImpl(methodResolver, this);
    if (methodResolver.hasApplicableCandidates()) {
      return;
    }

    // Search in ClosureMissingMethodContributor
    if (!isQualified() && getContext() instanceof GrMethodCall) {
      for (PsiElement e = this.getContext(); e != null; e = e.getContext()) {
        if (e instanceof GrClosableBlock) {
          ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, e);
          for (ClosureMissingMethodContributor contributor :
              ClosureMissingMethodContributor.EP_NAME.getExtensions()) {
            if (!contributor.processMembers((GrClosableBlock) e, methodResolver, this, state)) {
              return;
            }
          }
        }
      }
    }
  }
  private void buildFlowForClosure(final GrClosableBlock closure) {
    for (GrParameter parameter : closure.getAllParameters()) {
      if (myPolicy.isVariableInitialized(parameter)) {
        addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, WRITE));
      }
    }

    addNode(new ReadWriteVariableInstruction("owner", closure.getLBrace(), WRITE));

    PsiElement child = closure.getFirstChild();
    while (child != null) {
      if (child instanceof GroovyPsiElement) {
        ((GroovyPsiElement) child).accept(this);
      }
      child = child.getNextSibling();
    }

    final GrStatement[] statements = closure.getStatements();
    if (statements.length > 0) {
      handlePossibleReturn(statements[statements.length - 1]);
    }
  }
  @NotNull
  public static String getName(@NotNull GrNamedElement namedElement) {
    PsiElement nameElement = namedElement.getNameIdentifierGroovy();
    ASTNode node = nameElement.getNode();
    LOG.assertTrue(node != null);

    if (node.getElementType() == mIDENT) {
      return nameElement.getText();
    }

    if (node.getElementType() == mSTRING_LITERAL || node.getElementType() == mGSTRING_LITERAL) {
      final Object value = GrLiteralImpl.getLiteralValue(nameElement);
      if (value instanceof String) {
        return (String) value;
      } else {
        return GrStringUtil.removeQuotes(nameElement.getText());
      }
    }

    throw new IncorrectOperationException(
        "incorrect name element: " + node.getElementType() + ", named element: " + namedElement);
  }
  @Nullable
  public static PsiType inferExpectedTypeForDiamond(GrExpression diamondNew) {
    PsiElement skipped = PsiUtil.skipParentheses(diamondNew, true);
    assert skipped != null;
    PsiElement pparent = skipped.getParent();
    if (pparent instanceof GrAssignmentExpression
        && PsiTreeUtil.isAncestor(
            ((GrAssignmentExpression) pparent).getRValue(), diamondNew, false)) {
      GrExpression lValue = ((GrAssignmentExpression) pparent).getLValue();
      if (PsiUtil.mightBeLValue(lValue)) {
        return lValue.getNominalType();
      }
    } else if (pparent instanceof GrVariable
        && ((GrVariable) pparent).getInitializerGroovy() == diamondNew) {
      return ((GrVariable) pparent).getDeclaredType();
    } else if (pparent instanceof GrListOrMap) {
      PsiElement ppparent = PsiUtil.skipParentheses(pparent.getParent(), true);

      if (ppparent instanceof GrAssignmentExpression
          && PsiTreeUtil.isAncestor(
              ((GrAssignmentExpression) ppparent).getRValue(), pparent, false)) {

        PsiElement lValue =
            PsiUtil.skipParentheses(((GrAssignmentExpression) ppparent).getLValue(), false);
        if (lValue instanceof GrTupleExpression) {
          GrExpression[] initializers = ((GrListOrMap) pparent).getInitializers();
          int index = ArrayUtil.find(initializers, diamondNew);
          GrExpression[] expressions = ((GrTupleExpression) lValue).getExpressions();
          if (index < expressions.length) {
            return expressions[index].getNominalType();
          }
        }
      }
    }

    return null;
  }
    @Nullable
    public PsiType fun(GrReferenceExpressionImpl refExpr) {
      PsiType result = GrReassignedLocalVarsChecker.checkReassignedVar(refExpr, true);
      if (result != null) return result;

      if (GrUnresolvedAccessInspection.isClassReference(refExpr)) {
        GrExpression qualifier = refExpr.getQualifier();
        LOG.assertTrue(qualifier != null);
        return TypesUtil.createJavaLangClassType(
            qualifier.getType(), refExpr.getProject(), refExpr.getResolveScope());
      }

      final PsiElement resolved = refExpr.resolve();
      final PsiType inferred = getInferredTypes(refExpr, resolved);
      final PsiType nominal = refExpr.getNominalType();
      if (inferred == null || PsiType.NULL.equals(inferred)) {
        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;
    }
 public static boolean hasElementType(
     @Nullable PsiElement next, @NotNull final IElementType type) {
   if (next == null) return false;
   final ASTNode astNode = next.getNode();
   return astNode != null && astNode.getElementType() == type;
 }
  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) {
      ArrayList<GroovyResolveResult> results = new ArrayList<GroovyResolveResult>();
      if (GrReferenceResolveUtil.resolveThisExpression(this, results)) {
        return results.toArray(new GroovyResolveResult[results.size()]);
      }
    } else if (nameType == GroovyTokenTypes.kSUPER) {
      ArrayList<GroovyResolveResult> results = new ArrayList<GroovyResolveResult>();
      if (GrReferenceResolveUtil.resolveSuperExpression(this, results)) {
        return results.toArray(new GroovyResolveResult[results.size()]);
      }
    }

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

    GroovyResolveResult[] classCandidates = null;

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

    if (hasAt()) {
      return fieldCandidates;
    }

    boolean canBeClassOrPackage = ResolveUtil.canBeClassOrPackage(this);

    if (canBeClassOrPackage && findClassOrPackageAtFirst()) {
      boolean preferVar = containsLocalVar(fieldCandidates);
      if (!preferVar) {
        ResolverProcessor classProcessor = new ClassResolverProcessor(name, this, kinds);
        GrReferenceResolveUtil.resolveImpl(classProcessor, this);
        classCandidates = classProcessor.getCandidates();
        if (classCandidates.length > 0) 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 && PsiTreeUtil.isContextAncestor(containingClass, this, true))
          return fieldCandidates;
      } else {
        return fieldCandidates;
      }
    }

    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,
              GrReferenceResolveUtil.getQualifierType(this),
              getTypeArguments());
      GrReferenceResolveUtil.resolveImpl(accessorResolver, this);
      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);
      }
    }
    if (fieldCandidates.length > 0) return fieldCandidates;
    if (classCandidates == null && canBeClassOrPackage) {
      ResolverProcessor classProcessor = new ClassResolverProcessor(name, this, kinds);
      GrReferenceResolveUtil.resolveImpl(classProcessor, this);
      classCandidates = classProcessor.getCandidates();
    }
    if (classCandidates != null && classCandidates.length > 0) return classCandidates;
    if (accessorResults.size() > 0) return new GroovyResolveResult[] {accessorResults.get(0)};
    return GroovyResolveResult.EMPTY_ARRAY;
  }
  @Nullable
  private PsiType getNominalTypeInner(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);
        }
      }
      if (getParent() instanceof GrReferenceExpression || PsiUtil.isSuperReference(this)) {
        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(
            GrReferenceResolveUtil.getQualifierType(this), getProject(), getResolveScope());
      }

      return PsiUtil.getSmartReturnType(method);
    }

    if (resolved instanceof GrReferenceExpression) {
      PsiElement parent = resolved.getParent();
      if (parent instanceof GrAssignmentExpression) {
        GrAssignmentExpression assignment = (GrAssignmentExpression) parent;
        if (resolved.equals(assignment.getLValue())) {
          GrExpression rValue = assignment.getRValue();
          if (rValue != null) {
            PsiType rType = rValue.getType();
            if (rType != null) {
              return rType;
            }
          }
        }
      }
    }

    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;
  }
 private static void assertAllAreValid(GroovyResolveResult[] candidates) {
   for (GroovyResolveResult candidate : candidates) {
     final PsiElement element = candidate.getElement();
     LOG.assertTrue(element == null || element.isValid());
   }
 }
 @Nullable
 public IElementType getDotTokenType() {
   PsiElement dot = getDotToken();
   return dot == null ? null : dot.getNode().getElementType();
 }
 public static boolean hasElementType(@Nullable PsiElement next, final TokenSet set) {
   if (next == null) return false;
   final ASTNode astNode = next.getNode();
   return astNode != null && set.contains(astNode.getElementType());
 }