@Override
  public void visitMethodCallExpression(final MethodCallExpression call) {
    super.visitMethodCallExpression(call);

    MethodNode target = (MethodNode) call.getNodeMetaData(DIRECT_METHOD_CALL_TARGET);
    if (target != null) {
      call.setMethodTarget(target);
      memorizeInitialExpressions(target);
    }

    if (call.getMethodTarget() == null && call.getLineNumber() > 0) {
      addError("Target method for method call expression hasn't been set", call);
    }
  }
  @Override
  public void makeGroovyObjectGetPropertySite(
      final Expression receiver,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType = typeChooser.resolveType(receiver, classNode);
    if (receiver instanceof VariableExpression
        && ((VariableExpression) receiver).isThisExpression()
        && !controller.isInClosure()) {
      receiverType = classNode;
    }

    String property = methodName;
    if (implicitThis) {
      if (controller.getInvocationWriter() instanceof StaticInvocationWriter) {
        MethodCallExpression currentCall =
            ((StaticInvocationWriter) controller.getInvocationWriter()).getCurrentCall();
        if (currentCall != null
            && currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) != null) {
          property = (String) currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
          String[] props = property.split("\\.");
          BytecodeExpression thisLoader =
              new BytecodeExpression() {
                @Override
                public void visit(final MethodVisitor mv) {
                  mv.visitVarInsn(ALOAD, 0); // load this
                }
              };
          thisLoader.setType(CLOSURE_TYPE);
          Expression pexp =
              new PropertyExpression(thisLoader, new ConstantExpression(props[0]), safe);
          for (int i = 1, propsLength = props.length; i < propsLength; i++) {
            final String prop = props[i];
            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
            pexp = new PropertyExpression(pexp, prop);
          }
          pexp.visit(controller.getAcg());
          return;
        }
      }
    }

    if (makeGetPropertyWithGetter(receiver, receiverType, property, safe, implicitThis)) return;
    if (makeGetField(
        receiver,
        receiverType,
        property,
        implicitThis,
        samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;

    MethodCallExpression call =
        new MethodCallExpression(
            receiver, "getProperty", new ArgumentListExpression(new ConstantExpression(property)));
    call.setImplicitThis(implicitThis);
    call.setSafe(safe);
    call.setMethodTarget(GROOVYOBJECT_GETPROPERTY_METHOD);
    call.visit(controller.getAcg());
    return;
  }