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));
  }
  @Nullable
  private static PsiType getTypeByRef(@NotNull GrReferenceExpression invoked) {

    final GroovyResolveResult[] results =
        ControlFlowBuilderUtil.resolveNonQualifiedRefWithoutFlow(invoked);
    if (results.length == 1) {
      final PsiElement element = results[0].getElement();
      if (element instanceof PsiVariable) {
        return ((PsiVariable) element).getType();
      }
    }
    return null;
  }
  @Override
  public void visitBinaryExpression(GrBinaryExpression expression) {
    final GrExpression left = expression.getLeftOperand();
    final GrExpression right = expression.getRightOperand();
    final IElementType opType = expression.getOperationTokenType();

    if (ControlFlowBuilderUtil.isInstanceOfBinary(expression)) {
      expression.getLeftOperand().accept(this);
      processInstanceOf(expression);
      return;
    }

    if (opType != mLOR && opType != mLAND && opType != kIN) {
      left.accept(this);
      if (right != null) {
        right.accept(this);
      }
      visitCall(expression);
      return;
    }

    ConditionInstruction condition = new ConditionInstruction(expression);
    addNodeAndCheckPending(condition);
    registerCondition(condition);

    left.accept(this);

    if (right == null) return;

    final List<GotoInstruction> negations = collectAndRemoveAllPendingNegations(expression);

    visitCall(expression);

    if (opType == mLAND) {
      InstructionImpl head = myHead;
      if (negations.isEmpty()) {
        addNode(new NegatingGotoInstruction(expression, condition));
        handlePossibleReturn(expression);
        addPendingEdge(expression, myHead);
      } else {
        for (GotoInstruction negation : negations) {
          myHead = negation;
          handlePossibleReturn(expression);
          addPendingEdge(expression, myHead);
        }
      }
      myHead = head;
    } else /*if (opType == mLOR)*/ {
      final InstructionImpl instruction =
          addNodeAndCheckPending(
              new InstructionImpl(expression)); // collect all pending edges from left argument
      handlePossibleReturn(expression);
      addPendingEdge(expression, myHead);
      myHead = instruction;

      InstructionImpl head = reduceAllNegationsIntoInstruction(expression, negations);
      if (head != null) myHead = head;
      // addNode(new NegatingGotoInstruction(expression, myInstructionNumber++, condition));
    }
    myConditions.removeFirstOccurrence(condition);

    right.accept(this);
  }
 private void handlePossibleReturn(@NotNull GrStatement possibleReturn) {
   if (possibleReturn instanceof GrExpression
       && ControlFlowBuilderUtil.isCertainlyReturnStatement(possibleReturn)) {
     addNodeAndCheckPending(new MaybeReturnInstruction((GrExpression) possibleReturn));
   }
 }