@Override
    public void visitLabeledStatement(@NotNull GrLabeledStatement labeledStatement) {
      super.visitLabeledStatement(labeledStatement);

      final String name = labeledStatement.getName();
      GrLabeledStatement existing =
          ResolveUtil.resolveLabeledStatement(name, labeledStatement, true);
      if (existing != null && PsiTreeUtil.isAncestor(existing, labeledStatement, true)) {
        registerError(labeledStatement.getLabel(), name);
      }
    }
  // See org.spockframework.compiler.WhereBlockRewriter
  public static Map<String, SpockVariableDescriptor> createVariableMap(GrMethod method) {
    GrOpenBlock block = method.getBlock();
    if (block == null) return Collections.emptyMap();

    PsiElement elementUnderLabel = null;
    PsiElement elementAfterLabel = null;

    main:
    for (PsiElement e = block.getFirstChild(); e != null; e = e.getNextSibling()) {
      if (e instanceof GrLabeledStatement) {
        GrLabeledStatement l = (GrLabeledStatement) e;

        elementAfterLabel = l.getNextSibling();

        while (true) {
          GrStatement statement = l.getStatement();

          if ("where".equals(l.getName())) {
            elementUnderLabel = statement;
            break main;
          }

          if (statement instanceof GrLabeledStatement) {
            l = (GrLabeledStatement) statement;
            continue;
          }

          break;
        }
      }
    }

    if (elementUnderLabel == null) return Collections.emptyMap();

    Map<String, SpockVariableDescriptor> res = new HashMap<>();

    PsiElement e = elementUnderLabel;

    while (e != null) {
      if (e instanceof GrBinaryExpression
          && ((GrBinaryExpression) e).getOperationTokenType()
              == GroovyElementTypes.COMPOSITE_LSHIFT_SIGN) {
        GrBinaryExpression shift = (GrBinaryExpression) e;
        GrExpression leftOperand = shift.getLeftOperand();
        GrExpression rightOperand = shift.getRightOperand();

        if (leftOperand instanceof GrReferenceExpression) {
          String name = getNameByReference(leftOperand);
          if (name != null) {
            SpockVariableDescriptor descriptor = new SpockVariableDescriptor(leftOperand, name);
            descriptor.addExpressionOfCollection(rightOperand);
            res.put(name, descriptor);
          }
        } else if (leftOperand instanceof GrListOrMap) {
          GrExpression[] variableDefinitions = ((GrListOrMap) leftOperand).getInitializers();

          SpockVariableDescriptor[] variables =
              createVariables(res, Arrays.asList(variableDefinitions));

          if (rightOperand instanceof GrListOrMap) {
            for (GrExpression expression : ((GrListOrMap) rightOperand).getInitializers()) {
              if (expression instanceof GrListOrMap) {
                add(variables, Arrays.asList(((GrListOrMap) expression).getInitializers()));
              } else {
                for (SpockVariableDescriptor variable : variables) {
                  if (variable != null) {
                    variable.addExpressionOfCollection(expression);
                  }
                }
              }
            }
          }
        }
      } else if (e instanceof GrAssignmentExpression) {
        GrAssignmentExpression assExpr = (GrAssignmentExpression) e;
        GrExpression lValue = assExpr.getLValue();
        String name = getNameByReference(lValue);
        if (name != null) {
          res.put(
              name, new SpockVariableDescriptor(lValue, name).addExpression(assExpr.getRValue()));
        }
      } else if (isOrStatement(e)) {
        // See org.spockframework.compiler.WhereBlockRewriter#rewriteTableLikeParameterization()
        List<GrExpression> variableDefinitions = new ArrayList<>();
        splitOr(variableDefinitions, (GrExpression) e);

        SpockVariableDescriptor[] variables = createVariables(res, variableDefinitions);

        List<GrExpression> row = new ArrayList<>();

        PsiElement rowElement = getNext(e, elementUnderLabel, elementAfterLabel);
        while (isOrStatement(rowElement)) {
          row.clear();
          splitOr(row, (GrExpression) rowElement);

          add(variables, row);

          rowElement = getNext(rowElement, elementUnderLabel, elementAfterLabel);
        }

        e = rowElement;
        continue;
      }

      e = getNext(e, elementUnderLabel, elementAfterLabel);
    }

    return res;
  }
  private static GrForStatement updateReturnStatements(GrForStatement forStatement) {
    GrStatement body = forStatement.getBody();
    assert body != null;

    final Set<String> usedLabels = ContainerUtil.newHashSet();
    final Ref<Boolean> needLabel = Ref.create(false);

    body.accept(
        new GroovyRecursiveElementVisitor() {
          private int myLoops = 0;

          @Override
          public void visitReturnStatement(GrReturnStatement returnStatement) {
            if (returnStatement.getReturnValue() != null) return;

            if (myLoops > 0) needLabel.set(true);
          }

          @Override
          public void visitLabeledStatement(GrLabeledStatement labeledStatement) {
            super.visitLabeledStatement(labeledStatement);
            usedLabels.add(labeledStatement.getName());
          }

          @Override
          public void visitForStatement(GrForStatement forStatement) {
            myLoops++;
            super.visitForStatement(forStatement);
            myLoops--;
          }

          @Override
          public void visitWhileStatement(GrWhileStatement whileStatement) {
            myLoops++;
            super.visitWhileStatement(whileStatement);
            myLoops--;
          }

          @Override
          public void visitClosure(GrClosableBlock closure) {
            // don't go into closures
          }

          @Override
          public void visitAnonymousClassDefinition(
              GrAnonymousClassDefinition anonymousClassDefinition) {
            // don't go into anonymous
          }
        });

    GroovyPsiElementFactory factory =
        GroovyPsiElementFactory.getInstance(forStatement.getProject());

    final String continueText;
    if (needLabel.get()) {
      int i = 0;
      String label = OUTER;
      while (usedLabels.contains(label)) {
        label = OUTER + i;
        i++;
      }

      continueText = "continue " + label;

      GrLabeledStatement labeled =
          (GrLabeledStatement) factory.createStatementFromText(label + ": while (true){}");

      labeled.getStatement().replaceWithStatement(forStatement);

      labeled = forStatement.replaceWithStatement(labeled);

      forStatement = (GrForStatement) labeled.getStatement();

      body = forStatement.getBody();
      assert body != null;
    } else {
      continueText = "continue";
    }

    final GrStatement continueStatement = factory.createStatementFromText(continueText);

    body.accept(
        new GroovyRecursiveElementVisitor() {
          @Override
          public void visitReturnStatement(GrReturnStatement returnStatement) {
            if (returnStatement.getReturnValue() == null) {
              returnStatement.replaceWithStatement(continueStatement);
            }
          }

          @Override
          public void visitClosure(GrClosableBlock closure) {
            // don't go into closures
          }

          @Override
          public void visitAnonymousClassDefinition(
              GrAnonymousClassDefinition anonymousClassDefinition) {
            // don't go into anonymous
          }
        });

    return forStatement;
  }