@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 void visitClosure(GrClosableBlock closure) {
    // do not go inside closures except gstring injections
    if (closure.getParent() instanceof GrStringInjection) {
      for (GrParameter parameter : closure.getAllParameters()) {
        if (myPolicy.isVariableInitialized(parameter)) {
          addNode(new ReadWriteVariableInstruction(parameter.getName(), parameter, WRITE));
        }
      }
      addNode(new ReadWriteVariableInstruction("owner", closure.getLBrace(), WRITE));

      super.visitClosure(closure);
      return;
    }

    ReadWriteVariableInstruction[] reads =
        ControlFlowBuilderUtil.getReadsWithoutPriorWrites(closure.getControlFlow(), false);
    for (ReadWriteVariableInstruction read : reads) {
      PsiElement element = read.getElement();
      if (!(element instanceof GrReferenceExpression)
          || myPolicy.isReferenceAccepted((GrReferenceExpression) element)) {
        addNodeAndCheckPending(
            new ReadWriteVariableInstruction(read.getVariableName(), closure, READ));
      }
    }

    addNodeAndCheckPending(new InstructionImpl(closure));
  }
 public ClosureSyntheticParameter(GrClosableBlock closure) {
   super(
       GrClosableBlock.IT_PARAMETER_NAME,
       PsiType.getJavaLangObject(closure.getManager(), closure.getResolveScope()),
       closure);
   myClosure = closure;
   setOptional(true);
 }
  @Override
  protected void processIntention(@NotNull PsiElement element, Project project, Editor editor)
      throws IncorrectOperationException {
    final GrMethodCallExpression expression = (GrMethodCallExpression) element;
    final GrClosableBlock block = expression.getClosureArguments()[0];
    final GrParameterList parameterList = block.getParameterList();
    final GrParameter[] parameters = parameterList.getParameters();

    String var;
    if (parameters.length == 1) {
      var = parameters[0].getText();
      var = StringUtil.replace(var, GrModifier.DEF, "");
    } else {
      var = "it";
    }

    final GrExpression invokedExpression = expression.getInvokedExpression();
    GrExpression qualifier = ((GrReferenceExpression) invokedExpression).getQualifierExpression();
    final GroovyPsiElementFactory elementFactory =
        GroovyPsiElementFactory.getInstance(element.getProject());
    if (qualifier == null) {
      qualifier = elementFactory.createExpressionFromText("this");
    }

    StringBuilder builder = new StringBuilder();
    builder.append("for (").append(var).append(" in ").append(qualifier.getText()).append(") {\n");
    String text = block.getText();
    final PsiElement blockArrow = block.getArrow();
    int index;
    if (blockArrow != null) {
      index = blockArrow.getStartOffsetInParent() + blockArrow.getTextLength();
    } else {
      index = 1;
    }
    while (index < text.length() && Character.isWhitespace(text.charAt(index))) index++;
    text = text.substring(index, text.length() - 1);
    builder.append(text);
    builder.append("}");

    final GrStatement statement = elementFactory.createStatementFromText(builder.toString());
    GrForStatement forStatement = (GrForStatement) expression.replaceWithStatement(statement);
    final GrForClause clause = forStatement.getClause();
    GrVariable variable = clause.getDeclaredVariable();

    forStatement = updateReturnStatements(forStatement);

    if (variable == null) return;

    if (ApplicationManager.getApplication().isUnitTestMode()) return;

    final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
    final Document doc = documentManager.getDocument(element.getContainingFile());
    if (doc == null) return;

    documentManager.doPostponedOperationsAndUnblockDocument(doc);
    editor.getCaretModel().moveToOffset(variable.getTextOffset());
    new VariableInplaceRenamer(variable, editor).performInplaceRename();
  }
 private static boolean closableBlockExpressionsAreEquivalent(
     GrClosableBlock closableBlock1, GrClosableBlock closableBlock2) {
   final GrStatement[] statements1 = closableBlock1.getStatements();
   final GrStatement[] statements2 = closableBlock2.getStatements();
   if (statements1.length != statements2.length) {
     return false;
   }
   for (int i = 0; i < statements1.length; i++) {
     if (!statementsAreEquivalent(statements1[i], statements2[i])) {
       return false;
     }
   }
   return true;
 }
  @Nullable
  public static PsiType getExpectedClosureReturnType(GrClosableBlock closure) {
    final Set<PsiType> expectedTypes = getDefaultExpectedTypes(closure);

    List<PsiType> expectedReturnTypes = new ArrayList<PsiType>();
    for (PsiType expectedType : expectedTypes) {
      if (!(expectedType instanceof PsiClassType)) return null;

      final PsiClassType.ClassResolveResult resolveResult =
          ((PsiClassType) expectedType).resolveGenerics();
      final PsiClass resolved = resolveResult.getElement();
      if (resolved == null
          || !(GroovyCommonClassNames.GROOVY_LANG_CLOSURE.equals(resolved.getQualifiedName())))
        return null;

      final PsiTypeParameter[] typeParameters = resolved.getTypeParameters();
      if (typeParameters.length != 1) return null;

      final PsiTypeParameter expected = typeParameters[0];
      final PsiType expectedReturnType = resolveResult.getSubstitutor().substitute(expected);
      if (expectedReturnType == PsiType.VOID || expectedReturnType == null) return null;

      expectedReturnTypes.add(expectedReturnType);
    }

    return TypesUtil.getLeastUpperBoundNullable(expectedReturnTypes, closure.getManager());
  }
 @Override
 public void visitClosure(GrClosableBlock closure) {
   if (closure == expr) {
     super.visitClosure(closure);
   } else {
     closure.accept(new ConstantChecker(closure, scope));
   }
 }
 public PsiElement setName(@NotNull String newName) throws IncorrectOperationException {
   if (!newName.equals(getName())) {
     GrParameter parameter =
         GroovyPsiElementFactory.getInstance(getProject())
             .createParameter(newName, (String) null, null);
     myClosure.addParameter(parameter);
   }
   return this;
 }
  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]);
    }
  }
  private static void execute(final GrField field, final Collection<PsiElement> fieldUsages) {
    final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(field.getProject());

    final StringBuilder builder = new StringBuilder(field.getTextLength());
    final GrClosableBlock block = (GrClosableBlock) field.getInitializerGroovy();

    final GrModifierList modifierList = field.getModifierList();
    if (modifierList.getModifiers().length > 0 || modifierList.getAnnotations().length > 0) {
      builder.append(modifierList.getText());
    } else {
      builder.append(GrModifier.DEF);
    }
    builder.append(' ').append(field.getName());

    builder.append('(');
    if (block.hasParametersSection()) {
      builder.append(block.getParameterList().getText());
    } else {
      builder.append("def it = null");
    }
    builder.append(") {");

    ApplicationManager.getApplication()
        .runWriteAction(
            new Runnable() {
              public void run() {
                block.getParameterList().delete();
                block.getLBrace().delete();
                final PsiElement psiElement =
                    PsiUtil.skipWhitespacesAndComments(block.getFirstChild(), true);
                if (psiElement != null && "->".equals(psiElement.getText())) {
                  psiElement.delete();
                }
                builder.append(block.getText());
                final GrMethod method =
                    GroovyPsiElementFactory.getInstance(field.getProject())
                        .createMethodFromText(builder.toString());
                field.getParent().replace(method);
                for (PsiElement usage : fieldUsages) {
                  if (usage instanceof GrReferenceExpression) {
                    final PsiElement parent = usage.getParent();
                    StringBuilder newRefText = new StringBuilder();
                    if (parent instanceof GrReferenceExpression
                        && usage == ((GrReferenceExpression) parent).getQualifier()
                        && "call".equals(((GrReferenceExpression) parent).getReferenceName())) {
                      newRefText.append(usage.getText());
                      usage = parent;
                    } else {
                      PsiElement qualifier = ((GrReferenceExpression) usage).getQualifier();
                      if (qualifier == null) {
                        if (parent instanceof GrReferenceExpression
                            && ((GrReferenceExpression) parent).getQualifier() != null
                            && usage != ((GrReferenceExpression) parent).getQualifier()) {
                          qualifier = ((GrReferenceExpression) parent).getQualifier();
                          usage = parent;
                        }
                      }

                      if (qualifier != null) {
                        newRefText.append(qualifier.getText()).append('.');
                        ((GrReferenceExpression) usage).setQualifier(null);
                      } else {
                        newRefText.append("this.");
                      }
                      newRefText.append('&').append(usage.getText());
                    }
                    usage.replace(factory.createReferenceExpressionFromText(newRefText.toString()));
                  }
                }
              }
            });
  }