/*
  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 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();
  }
 private static boolean varStatementsAreEquivalent(
     @NotNull GrVariableDeclaration statement1, @NotNull GrVariableDeclaration statement2) {
   final GrVariable[] variables1 = statement1.getVariables();
   final GrVariable[] variables2 = statement2.getVariables();
   if (variables1.length != variables2.length) {
     return false;
   }
   for (int i = 0; i < variables2.length; i++) {
     if (!variablesAreEquivalent(variables1[i], variables2[i])) {
       return false;
     }
   }
   return true;
 }
  private static PsiClassType doGetSuperClassType(GroovyScriptClass scriptClass) {
    GrVariableDeclaration declaration = findDeclaration(scriptClass.getContainingFile());
    if (declaration != null) {

      GrModifierList modifierList = declaration.getModifierList();
      if (modifierList.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_BASE_SCRIPT)
          != null) {
        GrTypeElement typeElement = declaration.getTypeElementGroovy();
        if (typeElement != null) {
          PsiType type = typeElement.getType();
          if (type instanceof PsiClassType) {
            return (PsiClassType) type;
          }
        }
      }
    }
    return null;
  }
  private void alignVariableDeclarations(List<GrStatement> group, boolean classLevel) {
    AlignmentProvider.Aligner typeElement = myAlignmentProvider.createAligner(true);
    AlignmentProvider.Aligner varName = myAlignmentProvider.createAligner(true);
    AlignmentProvider.Aligner eq = myAlignmentProvider.createAligner(true);
    for (GrStatement statement : group) {
      GrVariableDeclaration varDeclaration = (GrVariableDeclaration) statement;
      GrVariable[] variables = varDeclaration.getVariables();
      for (GrVariable variable : variables) {
        varName.append(variable.getNameIdentifierGroovy());
      }

      if (classLevel && mySettings.ALIGN_GROUP_FIELD_DECLARATIONS) {
        typeElement.append(varDeclaration.getTypeElementGroovy());

        ASTNode current_eq =
            variables[variables.length - 1].getNode().findChildByType(GroovyTokenTypes.mASSIGN);
        if (current_eq != null) {
          eq.append(current_eq.getPsi());
        }
      }
    }
  }
  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);
    }
  }