/*
  To declare or not a variable to which method call result will be assigned.
   */
  private static List<VariableInfo> mustAddVariableDeclaration(
      @NotNull GrStatement[] statements, @NotNull VariableInfo[] vars) {
    Map<String, VariableInfo> names = new HashMap<String, VariableInfo>();
    for (VariableInfo var : vars) {
      names.put(var.getName(), var);
    }
    List<VariableInfo> result = new ArrayList<VariableInfo>();

    for (GrStatement statement : statements) {
      if (statement instanceof GrVariableDeclaration) {
        GrVariableDeclaration declaration = (GrVariableDeclaration) statement;
        for (GrVariable variable : declaration.getVariables()) {
          final VariableInfo removed = names.remove(variable.getName());
          if (removed != null) {
            result.add(removed);
          }
        }
      }
    }
    for (String varName : names.keySet()) {
      if (ResolveUtil.resolveProperty(statements[0], varName) == null) {
        result.add(names.get(varName));
      }
    }

    return result;
  }
  public GrInplaceConstantIntroducer(
      GrIntroduceContext context, OccurrencesChooser.ReplaceChoice choice) {
    super(IntroduceConstantHandler.REFACTORING_NAME, choice, context);

    myContext = context;

    myPanel = new GrInplaceIntroduceConstantPanel();

    GrVariable localVar = GrIntroduceHandlerBase.resolveLocalVar(context);
    if (localVar != null) {
      ArrayList<String> result = ContainerUtil.newArrayList(localVar.getName());

      GrExpression initializer = localVar.getInitializerGroovy();
      if (initializer != null) {
        ContainerUtil.addAll(
            result,
            GroovyNameSuggestionUtil.suggestVariableNames(
                initializer, new GroovyInplaceFieldValidator(context), true));
      }
      mySuggestedNames = ArrayUtil.toStringArray(result);
    } else {
      GrExpression expression = context.getExpression();
      assert expression != null;
      mySuggestedNames =
          GroovyNameSuggestionUtil.suggestVariableNames(
              expression, new GroovyInplaceFieldValidator(context), true);
    }
  }
 @Override
 protected void checkVariable(@NotNull GrVariable variable) throws GrRefactoringError {
   final GrExpression initializer = variable.getInitializerGroovy();
   if (initializer == null) {
     throw new GrRefactoringError(
         RefactoringBundle.message("variable.does.not.have.an.initializer", variable.getName()));
   }
   checkExpression(initializer);
 }
 private void flushForeachLoopVariable(@Nullable GrForClause clause) {
   if (clause instanceof GrForInClause) {
     GrVariable variable = clause.getDeclaredVariable();
     if (variable != null && myPolicy.isVariableInitialized(variable)) {
       addNodeAndCheckPending(
           new ReadWriteVariableInstruction(variable.getName(), variable, WRITE));
     }
   }
 }
  public void visitVariable(GrVariable variable) {
    super.visitVariable(variable);

    if (myPolicy.isVariableInitialized(variable)) {
      ReadWriteVariableInstruction writeInst =
          new ReadWriteVariableInstruction(variable.getName(), variable, WRITE);
      addNodeAndCheckPending(writeInst);
    }
  }
  private NameSuggestionsField createNameField(GrVariable var) {
    List<String> names = new ArrayList<String>();
    if (var != null) {
      names.add(var.getName());
    }
    ContainerUtil.addAll(names, suggestNames());

    return new NameSuggestionsField(
        ArrayUtil.toStringArray(names), myProject, GroovyFileType.GROOVY_FILE_TYPE);
  }
 private static boolean variablesAreEquivalent(
     @NotNull GrVariable var1, @NotNull GrVariable var2) {
   final GrExpression initializer1 = (GrExpression) var1.getInitializer();
   final GrExpression initializer2 = (GrExpression) var2.getInitializer();
   if (!expressionsAreEquivalent(initializer1, initializer2)) {
     return false;
   }
   final PsiType type1 = var1.getType();
   final PsiType type2 = var2.getType();
   if (!typesAreEquivalent(type1, type2)) {
     return false;
   }
   final String name1 = var1.getName();
   final String name2 = var2.getName();
   if (name1 == null) {
     return name2 == null;
   }
   return name1.equals(name2);
 }
  public static void generateBody(
      ExtractInfoHelper helper, boolean isVoid, StringBuilder buffer, boolean forceReturn) {
    VariableInfo[] outputInfos = helper.getOutputVariableInfos();

    ParameterInfo[] infos = helper.getParameterInfos();

    Set<String> declaredVars = new HashSet<String>();
    for (ParameterInfo info : infos) {
      declaredVars.add(info.getName());
    }

    for (VariableInfo info : mustAddVariableDeclaration(helper.getStatements(), outputInfos)) {
      declaredVars.add(info.getName());
    }

    List<VariableInfo> genDecl = new ArrayList<VariableInfo>();
    final Collection<GrVariable> outside =
        collectUsedLocalVarsOrParamsDeclaredOutside(helper.getStatements());

    for (final GrVariable variable : outside) {
      if (!declaredVars.contains(variable.getName())) {
        genDecl.add(
            new VariableInfo() {
              @NotNull
              @Override
              public String getName() {
                return variable.getName();
              }

              @Override
              public PsiType getType() {
                return variable.getDeclaredType();
              }
            });
      }
    }
    final List<GrStatement> statements =
        generateVarDeclarations(genDecl, helper.getProject(), null);
    for (GrStatement statement : statements) {
      buffer.append(statement.getText()).append('\n');
    }

    if (!isSingleExpression(helper.getStatements()) || statements.size() > 0) {
      for (PsiElement element : helper.getInnerElements()) {
        buffer.append(element.getText());
      }
      // append return statement
      if (!isVoid && outputInfos.length > 0) {
        buffer.append('\n');
        if (forceReturn) {
          buffer.append("return ");
        }
        if (outputInfos.length > 1) buffer.append('[');
        for (VariableInfo info : outputInfos) {
          buffer.append(info.getName()).append(", ");
        }
        buffer.delete(buffer.length() - 2, buffer.length());
        if (outputInfos.length > 1) buffer.append(']');
      }
    } else {
      GrExpression expr = (GrExpression) PsiUtil.skipParentheses(helper.getStatements()[0], false);
      boolean addReturn = !isVoid && forceReturn;
      if (addReturn) {
        buffer.append("return ");
        expr = ApplicationStatementUtil.convertToMethodCallExpression(expr);
        buffer.append(expr.getText());
      } else {
        buffer.append(expr != null ? expr.getText() : "");
      }
    }
  }
  private void writeTupleDeclaration(
      GrVariableDeclaration variableDeclaration,
      StringBuilder builder,
      ExpressionContext expressionContext) {
    GrVariable[] variables = variableDeclaration.getVariables();
    final GrExpression tupleInitializer = variableDeclaration.getTupleInitializer();
    if (tupleInitializer instanceof GrListOrMap) {
      for (GrVariable variable : variables) {
        writeVariableSeparately(variable, builder, expressionContext);
        builder.append(";\n");
      }
    } else if (tupleInitializer != null) {

      GroovyResolveResult iteratorMethodResult =
          resolveMethod(
              tupleInitializer,
              "iterator",
              GrExpression.EMPTY_ARRAY,
              GrNamedArgument.EMPTY_ARRAY,
              GrClosableBlock.EMPTY_ARRAY,
              variableDeclaration);

      final PsiType iteratorType = inferIteratorType(iteratorMethodResult, tupleInitializer);

      final String iteratorName =
          genIteratorVar(
              variableDeclaration,
              builder,
              expressionContext,
              tupleInitializer,
              iteratorType,
              iteratorMethodResult);

      final GrModifierList modifierList = variableDeclaration.getModifierList();

      PsiType iterableTypeParameter = PsiUtil.extractIterableTypeParameter(iteratorType, false);

      for (final GrVariable v : variables) {
        ModifierListGenerator.writeModifiers(builder, modifierList);
        final PsiType type = context.typeProvider.getVarType(v);
        writeType(builder, type, variableDeclaration);
        builder.append(' ').append(v.getName());

        builder.append(" = ");
        wrapInCastIfNeeded(
            builder,
            type,
            iterableTypeParameter,
            tupleInitializer,
            expressionContext,
            new StatementWriter() {
              @Override
              public void writeStatement(StringBuilder builder, ExpressionContext context) {
                builder
                    .append(iteratorName)
                    .append(".hasNext() ? ")
                    .append(iteratorName)
                    .append(".next() : null");
              }
            });
        builder.append(";\n");
      }
    } else {
      writeSimpleVarDeclaration(variableDeclaration, builder, expressionContext);
    }
  }
 private static void writeVariableWithoutSemicolonAndInitializer(
     StringBuilder builder, GrVariable var, ExpressionContext context) {
   ModifierListGenerator.writeModifiers(builder, var.getModifierList());
   writeType(builder, context.typeProvider.getVarType(var), var);
   builder.append(' ').append(var.getName());
 }