@Override
 public void makeSingleArgumentCall(
     final Expression receiver, final String message, final Expression arguments) {
   TypeChooser typeChooser = controller.getTypeChooser();
   ClassNode classNode = controller.getClassNode();
   ClassNode rType = typeChooser.resolveType(receiver, classNode);
   ClassNode aType = typeChooser.resolveType(arguments, classNode);
   if (trySubscript(receiver, message, arguments, rType, aType)) {
     return;
   }
   // new try with flow type instead of declaration type
   rType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
   if (rType != null && trySubscript(receiver, message, arguments, rType, aType)) {
     return;
   }
   // todo: more cases
   throw new GroovyBugError(
       "At line "
           + receiver.getLineNumber()
           + " column "
           + receiver.getColumnNumber()
           + "\n"
           + "On receiver: "
           + receiver.getText()
           + " with message: "
           + message
           + " and arguments: "
           + arguments.getText()
           + "\n"
           + "This method should not have been called. Please try to create a simple example reproducing this error and file"
           + "a bug report at http://jira.codehaus.org/browse/GROOVY");
 }
  private void writeMapDotProperty(
      final Expression receiver,
      final String methodName,
      final MethodVisitor mv,
      final boolean safe) {
    receiver.visit(controller.getAcg()); // load receiver

    Label exit = new Label();
    if (safe) {
      Label doGet = new Label();
      mv.visitJumpInsn(IFNONNULL, doGet);
      controller.getOperandStack().remove(1);
      mv.visitInsn(ACONST_NULL);
      mv.visitJumpInsn(GOTO, exit);
      mv.visitLabel(doGet);
      receiver.visit(controller.getAcg());
    }

    mv.visitLdcInsn(methodName); // load property name
    mv.visitMethodInsn(
        INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
    if (safe) {
      mv.visitLabel(exit);
    }
    controller.getOperandStack().replace(OBJECT_TYPE);
  }
  public void visitConstructorCallExpression(ConstructorCallExpression call) {
    isSpecialConstructorCall = call.isSpecialCall();
    super.visitConstructorCallExpression(call);
    isSpecialConstructorCall = false;
    if (!call.isUsingAnonymousInnerClass()) return;

    pushState();
    InnerClassNode innerClass = (InnerClassNode) call.getType();
    innerClass.setVariableScope(currentScope);
    for (MethodNode method : innerClass.getMethods()) {
      Parameter[] parameters = method.getParameters();
      if (parameters.length == 0) parameters = null; // null means no implicit "it"
      ClosureExpression cl = new ClosureExpression(parameters, method.getCode());
      visitClosureExpression(cl);
    }

    for (FieldNode field : innerClass.getFields()) {
      final Expression expression = field.getInitialExpression();
      if (expression != null) {
        expression.visit(this);
      }
    }

    for (Statement statement : innerClass.getObjectInitializerStatements()) {
      statement.visit(this);
    }
    markClosureSharedVariables();
    popState();
  }
  protected Expression transformPropertyExpression(PropertyExpression pe) {
    boolean oldInPropertyExpression = inPropertyExpression;
    Expression oldFoundArgs = foundArgs;
    Expression oldFoundConstant = foundConstant;
    inPropertyExpression = true;
    foundArgs = null;
    foundConstant = null;
    Expression objectExpression = transform(pe.getObjectExpression());
    boolean candidate = false;
    if (objectExpression instanceof MethodCallExpression) {
      candidate = ((MethodCallExpression) objectExpression).isImplicitThis();
    }

    if (foundArgs != null && foundConstant != null && candidate) {
      Expression result = findStaticMethodImportFromModule(foundConstant, foundArgs);
      if (result != null) {
        objectExpression = result;
        objectExpression.setSourcePosition(pe);
      }
    }
    inPropertyExpression = oldInPropertyExpression;
    foundArgs = oldFoundArgs;
    foundConstant = oldFoundConstant;
    pe.setObjectExpression(objectExpression);
    return pe;
  }
  private Expression transformInlineConstants(Expression exp) {
    if (exp instanceof PropertyExpression) {
      PropertyExpression pe = (PropertyExpression) exp;
      if (pe.getObjectExpression() instanceof ClassExpression) {
        ClassExpression ce = (ClassExpression) pe.getObjectExpression();
        ClassNode type = ce.getType();
        if (type.isEnum()) return exp;
        Expression constant = findConstant(type.getField(pe.getPropertyAsString()));
        // GRECLIPSE edit
        // if (constant != null) return constant;
        if (constant != null) {
          String name = pe.getText().replace('$', '.');
          Object alias = pe.getNodeMetaData("static.import.alias");
          if (alias != null && !alias.equals(pe.getPropertyAsString())) {
            name += " as " + alias;
          }
          // store the qualified name to facilitate organizing static imports
          constant.setNodeMetaData("static.import", name);

          return constant;
        }
        // GRECLIPSE end
      }
    } else if (exp instanceof ListExpression) {
      ListExpression le = (ListExpression) exp;
      ListExpression result = new ListExpression();
      for (Expression e : le.getExpressions()) {
        result.addExpression(transformInlineConstants(e));
      }
      return result;
    }

    return exp;
  }
 public void visitAnnotations(AnnotatedNode node) {
   List<AnnotationNode> annotations = node.getAnnotations();
   if (annotations.isEmpty()) return;
   for (AnnotationNode an : annotations) {
     // skip built-in properties
     if (an.isBuiltIn()) continue;
     for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
       Expression annMemberValue = member.getValue();
       annMemberValue.visit(this);
     }
   }
 }
 private List createPropertiesForHasManyExpression(Expression e, ClassNode classNode) {
   List properties = new ArrayList();
   if (e instanceof MapExpression) {
     MapExpression me = (MapExpression) e;
     List mapEntries = me.getMapEntryExpressions();
     for (Iterator j = mapEntries.iterator(); j.hasNext(); ) {
       MapEntryExpression mee = (MapEntryExpression) j.next();
       Expression keyExpression = mee.getKeyExpression();
       String key = keyExpression.getText();
       addAssociationForKey(key, properties, classNode);
     }
   }
   return properties;
 }
 public Expression transform(Expression exp) {
   if (exp == null) return null;
   if (exp.getClass() == VariableExpression.class) {
     return transformVariableExpression((VariableExpression) exp);
   }
   if (exp.getClass() == BinaryExpression.class) {
     return transformBinaryExpression((BinaryExpression) exp);
   }
   if (exp.getClass() == PropertyExpression.class) {
     return transformPropertyExpression((PropertyExpression) exp);
   }
   if (exp.getClass() == MethodCallExpression.class) {
     return transformMethodCallExpression((MethodCallExpression) exp);
   }
   if (exp.getClass() == ClosureExpression.class) {
     return transformClosureExpression((ClosureExpression) exp);
   }
   if (exp.getClass() == ConstructorCallExpression.class) {
     return transformConstructorCallExpression((ConstructorCallExpression) exp);
   }
   if (exp.getClass() == ArgumentListExpression.class) {
     Expression result = exp.transformExpression(this);
     if (inPropertyExpression) {
       foundArgs = result;
     }
     return result;
   }
   if (exp instanceof ConstantExpression) {
     Expression result = exp.transformExpression(this);
     if (inPropertyExpression) {
       foundConstant = result;
     }
     if (inAnnotation && exp instanceof AnnotationConstantExpression) {
       ConstantExpression ce = (ConstantExpression) result;
       if (ce.getValue() instanceof AnnotationNode) {
         // replicate a little bit of AnnotationVisitor here
         // because we can't wait until later to do this
         AnnotationNode an = (AnnotationNode) ce.getValue();
         Map<String, Expression> attributes = an.getMembers();
         for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
           Expression attrExpr = transform(entry.getValue());
           entry.setValue(attrExpr);
         }
       }
     }
     return result;
   }
   return exp.transformExpression(this);
 }
  @Override
  protected boolean existsProperty(
      final PropertyExpression pexp,
      final boolean checkForReadOnly,
      final ClassCodeVisitorSupport visitor) {
    Expression objectExpression = pexp.getObjectExpression();
    ClassNode objectExpressionType = getType(objectExpression);
    final Reference<ClassNode> rType = new Reference<ClassNode>(objectExpressionType);
    ClassCodeVisitorSupport receiverMemoizer =
        new ClassCodeVisitorSupport() {
          @Override
          protected SourceUnit getSourceUnit() {
            return null;
          }

          public void visitField(final FieldNode node) {
            if (visitor != null) visitor.visitField(node);
            ClassNode declaringClass = node.getDeclaringClass();
            if (declaringClass != null) rType.set(declaringClass);
          }

          public void visitMethod(final MethodNode node) {
            if (visitor != null) visitor.visitMethod(node);
            ClassNode declaringClass = node.getDeclaringClass();
            if (declaringClass != null) rType.set(declaringClass);
          }

          @Override
          public void visitProperty(final PropertyNode node) {
            if (visitor != null) visitor.visitProperty(node);
            ClassNode declaringClass = node.getDeclaringClass();
            if (declaringClass != null) rType.set(declaringClass);
          }
        };
    boolean exists = super.existsProperty(pexp, checkForReadOnly, receiverMemoizer);
    if (exists) {
      if (objectExpression.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER) == null) {
        objectExpression.putNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER, rType.get());
      }
      if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(
          objectExpressionType, ClassHelper.LIST_TYPE)) {
        objectExpression.putNodeMetaData(
            COMPONENT_TYPE, inferComponentType(objectExpressionType, ClassHelper.int_TYPE));
      }
    }
    return exists;
  }
 private void writeArrayGet(
     final Expression receiver,
     final Expression arguments,
     final ClassNode rType,
     final ClassNode aType) {
   OperandStack operandStack = controller.getOperandStack();
   int m1 = operandStack.getStackLength();
   // visit receiver
   receiver.visit(controller.getAcg());
   // visit arguments as array index
   arguments.visit(controller.getAcg());
   operandStack.doGroovyCast(int_TYPE);
   int m2 = operandStack.getStackLength();
   // array access
   controller.getMethodVisitor().visitInsn(AALOAD);
   operandStack.replace(rType.getComponentType(), m2 - m1);
 }
 private Expression transformMapEntryExpression(
     MapEntryExpression me, ClassNode constructorCallType) {
   Expression key = me.getKeyExpression();
   Expression value = me.getValueExpression();
   ModuleNode module = currentClass.getModule();
   if (module != null && key instanceof ConstantExpression) {
     Map<String, ImportNode> importNodes = module.getStaticImports();
     if (importNodes.containsKey(key.getText())) {
       ImportNode importNode = importNodes.get(key.getText());
       if (importNode.getType().equals(constructorCallType)) {
         String newKey = importNode.getFieldName();
         return new MapEntryExpression(
             new ConstantExpression(newKey), value.transformExpression(this));
       }
     }
   }
   return me;
 }
 /**
  * Given a method call, first checks that it's a static method call, and if it is, returns the
  * class node for the receiver. For example, with the following code: <code></code>Person.findAll
  * { ... }</code>, it would return the class node for <i>Person</i>. If it's not a static method
  * call, returns null.
  *
  * @param call a method call
  * @return null if it's not a static method call, or the class node for the receiver instead.
  */
 public ClassNode extractStaticReceiver(MethodCall call) {
   if (call instanceof StaticMethodCallExpression) {
     return ((StaticMethodCallExpression) call).getOwnerType();
   } else if (call instanceof MethodCallExpression) {
     Expression objectExpr = ((MethodCallExpression) call).getObjectExpression();
     if (objectExpr instanceof ClassExpression
         && ClassHelper.CLASS_Type.equals(objectExpr.getType())) {
       GenericsType[] genericsTypes = objectExpr.getType().getGenericsTypes();
       if (genericsTypes != null && genericsTypes.length == 1) {
         return genericsTypes[0].getType();
       }
     }
     if (objectExpr instanceof ClassExpression) {
       return objectExpr.getType();
     }
   }
   return null;
 }
 private Statement createConstructorStatementCollection(FieldNode fNode) {
   final Expression fieldExpr = new VariableExpression(fNode);
   Expression initExpr = fNode.getInitialValueExpression();
   if (initExpr == null) initExpr = new ConstantExpression(null);
   Expression collection = findArg(fNode.getName());
   ClassNode fieldType = fieldExpr.getType();
   return new IfStatement(
       equalsNullExpr(collection),
       new IfStatement(
           equalsNullExpr(initExpr),
           new EmptyStatement(),
           assignStatement(fieldExpr, cloneCollectionExpr(initExpr))),
       new IfStatement(
           isInstanceOf(collection, CLONEABLE_TYPE),
           assignStatement(
               fieldExpr, cloneCollectionExpr(cloneArrayOrCloneableExpr(collection, fieldType))),
           assignStatement(fieldExpr, cloneCollectionExpr(collection))));
 }
 @Override
 protected MethodNode findMethodOrFail(
     final Expression expr, final ClassNode receiver, final String name, final ClassNode... args) {
   MethodNode methodNode = super.findMethodOrFail(expr, receiver, name, args);
   if (expr instanceof BinaryExpression && methodNode != null) {
     expr.putNodeMetaData(BINARY_EXP_TARGET, new Object[] {methodNode, name});
   }
   return methodNode;
 }
  private void validateFields(BlockStatement block) {
    Validation.Option mode =
        getEnumMemberValue(
            getAnnotation(annotatedClass, VALIDATION_ANNOTATION),
            "option",
            Validation.Option.class,
            Validation.Option.IGNORE_UNMARKED);
    for (FieldNode fieldNode : annotatedClass.getFields()) {
      if (shouldFieldBeIgnoredForValidation(fieldNode)) continue;

      ClosureExpression validationClosure =
          createGroovyTruthClosureExpression(block.getVariableScope());
      String message = null;

      AnnotationNode validateAnnotation = getAnnotation(fieldNode, VALIDATE_ANNOTATION);
      if (validateAnnotation != null) {
        message =
            getMemberStringValue(
                validateAnnotation, "message", "'" + fieldNode.getName() + "' must be set!");
        Expression member = validateAnnotation.getMember("value");
        if (member instanceof ClassExpression) {
          ClassNode memberType = member.getType();
          if (memberType.equals(ClassHelper.make(Validate.Ignore.class))) continue;
          else if (!memberType.equals(ClassHelper.make(Validate.GroovyTruth.class))) {
            addError(
                "value of Validate must be either Validate.GroovyTruth, Validate.Ignore or a closure.",
                fieldNode);
          }
        } else if (member instanceof ClosureExpression) {
          validationClosure = (ClosureExpression) member;
        }
      }

      if (validateAnnotation != null || mode == Validation.Option.VALIDATE_UNMARKED) {
        block.addStatement(
            new AssertStatement(
                new BooleanExpression(
                    callX(validationClosure, "call", args(varX(fieldNode.getName())))),
                message == null ? ConstantExpression.NULL : new ConstantExpression(message)));
      }
    }
  }
  private List<String> getKnownImmutableClasses(AnnotationNode node) {
    final ArrayList<String> immutableClasses = new ArrayList<String>();

    final Expression expression = node.getMember(MEMBER_KNOWN_IMMUTABLE_CLASSES);
    if (expression == null) return immutableClasses;

    if (!(expression instanceof ListExpression)) {
      addError(
          "Use the Groovy list notation [el1, el2] to specify known immutable classes via \""
              + MEMBER_KNOWN_IMMUTABLE_CLASSES
              + "\"",
          node);
      return immutableClasses;
    }

    final ListExpression listExpression = (ListExpression) expression;
    for (Expression listItemExpression : listExpression.getExpressions()) {
      if (listItemExpression instanceof ClassExpression) {
        immutableClasses.add(listItemExpression.getType().getName());
      }
    }

    return immutableClasses;
  }
  protected Expression transformPropertyExpression(PropertyExpression pe) {
    if (currentMethod != null
        && currentMethod.isStatic()
        && pe.getObjectExpression() instanceof VariableExpression
        && ((VariableExpression) pe.getObjectExpression()).isSuperExpression()) {
      PropertyExpression pexp =
          new PropertyExpression(
              new ClassExpression(currentClass.getSuperClass()), transform(pe.getProperty()));
      pexp.setSourcePosition(pe);
      return pexp;
    }
    boolean oldInPropertyExpression = inPropertyExpression;
    Expression oldFoundArgs = foundArgs;
    Expression oldFoundConstant = foundConstant;
    inPropertyExpression = true;
    foundArgs = null;
    foundConstant = null;
    Expression objectExpression = transform(pe.getObjectExpression());
    boolean candidate = false;
    if (objectExpression instanceof MethodCallExpression) {
      candidate = ((MethodCallExpression) objectExpression).isImplicitThis();
    }

    if (foundArgs != null && foundConstant != null && candidate) {
      Expression result = findStaticMethodImportFromModule(foundConstant, foundArgs);
      if (result != null) {
        objectExpression = result;
        objectExpression.setSourcePosition(pe);
      }
    }
    inPropertyExpression = oldInPropertyExpression;
    foundArgs = oldFoundArgs;
    foundConstant = oldFoundConstant;
    pe.setObjectExpression(objectExpression);
    return pe;
  }
 boolean makeGetField(
     final Expression receiver,
     final ClassNode receiverType,
     final String fieldName,
     final boolean implicitThis,
     final boolean samePackage) {
   FieldNode field = receiverType.getField(fieldName);
   // direct access is allowed if we are in the same class as the declaring class
   // or we are in an inner class
   if (field != null && isDirectAccessAllowed(field, controller.getClassNode(), samePackage)) {
     CompileStack compileStack = controller.getCompileStack();
     MethodVisitor mv = controller.getMethodVisitor();
     if (field.isStatic()) {
       mv.visitFieldInsn(
           GETSTATIC,
           BytecodeHelper.getClassInternalName(field.getOwner()),
           fieldName,
           BytecodeHelper.getTypeDescription(field.getOriginType()));
       controller.getOperandStack().push(field.getOriginType());
     } else {
       if (implicitThis) {
         compileStack.pushImplicitThis(implicitThis);
       }
       receiver.visit(controller.getAcg());
       if (implicitThis) compileStack.popImplicitThis();
       if (!controller.getOperandStack().getTopOperand().isDerivedFrom(field.getOwner())) {
         mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(field.getOwner()));
       }
       mv.visitFieldInsn(
           GETFIELD,
           BytecodeHelper.getClassInternalName(field.getOwner()),
           fieldName,
           BytecodeHelper.getTypeDescription(field.getOriginType()));
     }
     controller.getOperandStack().replace(field.getOriginType());
     return true;
   }
   ClassNode superClass = receiverType.getSuperClass();
   if (superClass != null) {
     return makeGetField(receiver, superClass, fieldName, implicitThis, false);
   }
   return false;
 }
 public ClosureExpression(Parameter[] parameters, Statement code) {
   this.parameters = parameters;
   this.code = code;
   super.setType(ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
 }
  @Override
  public void makeGetPropertySite(
      Expression receiver,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    Object dynamic =
        receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
    if (dynamic != null) {
      MethodNode target =
          safe ? INVOKERHELPER_GETPROPERTYSAFE_METHOD : INVOKERHELPER_GETPROPERTY_METHOD;
      MethodCallExpression mce =
          new MethodCallExpression(
              new ClassExpression(INVOKERHELPER_TYPE),
              target.getName(),
              new ArgumentListExpression(receiver, new ConstantExpression(methodName)));
      mce.setSafe(false);
      mce.setImplicitThis(false);
      mce.setMethodTarget(target);
      mce.visit(controller.getAcg());
      return;
    }
    TypeChooser typeChooser = controller.getTypeChooser();
    ClassNode classNode = controller.getClassNode();
    ClassNode receiverType =
        (ClassNode) receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
    if (receiverType == null) {
      receiverType = typeChooser.resolveType(receiver, classNode);
    }
    Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
    if (type == null && receiver instanceof VariableExpression) {
      Variable variable = ((VariableExpression) receiver).getAccessedVariable();
      if (variable instanceof Expression) {
        type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
      }
    }
    if (type != null) {
      // in case a "flow type" is found, it is preferred to use it instead of
      // the declaration type
      receiverType = (ClassNode) type;
    }
    boolean isClassReceiver = false;
    if (isClassClassNodeWrappingConcreteType(receiverType)) {
      isClassReceiver = true;
      receiverType = receiverType.getGenericsTypes()[0].getType();
    }
    MethodVisitor mv = controller.getMethodVisitor();

    if (receiverType.isArray() && methodName.equals("length")) {
      receiver.visit(controller.getAcg());
      ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
      controller.getOperandStack().doGroovyCast(arrayGetReturnType);
      mv.visitInsn(ARRAYLENGTH);
      controller.getOperandStack().replace(int_TYPE);
      return;
    } else if ((receiverType.implementsInterface(COLLECTION_TYPE)
            || COLLECTION_TYPE.equals(receiverType))
        && ("size".equals(methodName) || "length".equals(methodName))) {
      MethodCallExpression expr =
          new MethodCallExpression(receiver, "size", ArgumentListExpression.EMPTY_ARGUMENTS);
      expr.setMethodTarget(COLLECTION_SIZE_METHOD);
      expr.setImplicitThis(implicitThis);
      expr.setSafe(safe);
      expr.visit(controller.getAcg());
      return;
    }
    if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis)) return;
    if (makeGetField(
        receiver,
        receiverType,
        methodName,
        implicitThis,
        samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
    if (receiverType.isEnum()) {
      mv.visitFieldInsn(
          GETSTATIC,
          BytecodeHelper.getClassInternalName(receiverType),
          methodName,
          BytecodeHelper.getTypeDescription(receiverType));
      controller.getOperandStack().push(receiverType);
      return;
    }
    if (receiver instanceof ClassExpression) {
      if (makeGetField(
          receiver,
          receiver.getType(),
          methodName,
          implicitThis,
          samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
      if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis))
        return;
      if (makeGetPrivateFieldWithBridgeMethod(
          receiver, receiver.getType(), methodName, safe, implicitThis)) return;
    }
    if (isClassReceiver) {
      // we are probably looking for a property of the class
      if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis)) return;
      if (makeGetField(receiver, CLASS_Type, methodName, false, true)) return;
    }
    if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis))
      return;

    // GROOVY-5580, it is still possible that we're calling a superinterface property
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    if (receiverType.isInterface()) {
      Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
      MethodNode getterMethod = null;
      for (ClassNode anInterface : allInterfaces) {
        getterMethod = anInterface.getGetterMethod(getterName);
        if (getterMethod != null) break;
      }
      // GROOVY-5585
      if (getterMethod == null) {
        getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
      }

      if (getterMethod != null) {
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getterMethod);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    // GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
    List<MethodNode> methods =
        findDGMMethodsByNameAndArguments(
            controller.getSourceUnit().getClassLoader(),
            receiverType,
            getterName,
            ClassNode.EMPTY_ARRAY);
    if (!methods.isEmpty()) {
      List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
      if (methodNodes.size() == 1) {
        MethodNode getter = methodNodes.get(0);
        MethodCallExpression call =
            new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
        call.setMethodTarget(getter);
        call.setImplicitThis(false);
        call.setSourcePosition(receiver);
        call.visit(controller.getAcg());
        return;
      }
    }

    boolean isStaticProperty =
        receiver instanceof ClassExpression
            && (receiverType.isDerivedFrom(receiver.getType())
                || receiverType.implementsInterface(receiver.getType()));

    if (!isStaticProperty) {
      if (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType)) {
        // for maps, replace map.foo with map.get('foo')
        writeMapDotProperty(receiver, methodName, mv, safe);
        return;
      }
      if (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType)) {
        writeListDotProperty(receiver, methodName, mv, safe);
        return;
      }
    }

    controller
        .getSourceUnit()
        .addError(
            new SyntaxException(
                "Access to "
                    + (receiver instanceof ClassExpression ? receiver.getType() : receiverType)
                        .toString(false)
                    + "#"
                    + methodName
                    + " is forbidden",
                receiver.getLineNumber(),
                receiver.getColumnNumber(),
                receiver.getLastLineNumber(),
                receiver.getLastColumnNumber()));
    controller.getMethodVisitor().visitInsn(ACONST_NULL);
    controller.getOperandStack().push(OBJECT_TYPE);
  }
  private Expression findStaticFieldOrPropAccessorImportFromModule(String name) {
    ModuleNode module = currentClass.getModule();
    if (module == null) return null;
    Map<String, ImportNode> importNodes = module.getStaticImports();
    Expression expression = null;
    String accessorName = getAccessorName(name);
    // look for one of these:
    //   import static MyClass.setProp [as setOtherProp]
    //   import static MyClass.getProp [as getOtherProp]
    // when resolving prop reference
    if (importNodes.containsKey(accessorName)) {
      ImportNode importNode = importNodes.get(accessorName);
      expression =
          findStaticPropertyAccessorByFullName(importNode.getType(), importNode.getFieldName());
      if (expression != null) return expression;
      expression =
          findStaticPropertyAccessor(
              importNode.getType(), getPropNameForAccessor(importNode.getFieldName()));
      if (expression != null) return expression;
    }
    if (accessorName.startsWith("get")) {
      accessorName = "is" + accessorName.substring(3);
      if (importNodes.containsKey(accessorName)) {
        ImportNode importNode = importNodes.get(accessorName);
        expression =
            findStaticPropertyAccessorByFullName(importNode.getType(), importNode.getFieldName());
        if (expression != null) return expression;
        expression =
            findStaticPropertyAccessor(
                importNode.getType(), getPropNameForAccessor(importNode.getFieldName()));
        if (expression != null) return expression;
      }
    }

    // look for one of these:
    //   import static MyClass.prop [as otherProp]
    // when resolving prop or field reference
    if (importNodes.containsKey(name)) {
      ImportNode importNode = importNodes.get(name);
      // GRECLIPSE add
      try {
        if (!isReconcile) {
          // GRECLIPSE end
          expression = findStaticPropertyAccessor(importNode.getType(), importNode.getFieldName());
          if (expression != null) return expression;
          // GRECLIPSE add
        }
        // end
        expression = findStaticField(importNode.getType(), importNode.getFieldName());
        if (expression != null) return expression;
        // GRECLIPSE add
      } finally {
        // store the identifier to facilitate organizing static imports
        if (expression != null) expression.setNodeMetaData("static.import.alias", name);
      }
      // GRECLIPSE end
    }
    // look for one of these:
    //   import static MyClass.*
    // when resolving prop or field reference
    for (ImportNode importNode : module.getStaticStarImports().values()) {
      ClassNode node = importNode.getType();
      expression = findStaticPropertyAccessor(node, name);
      if (expression != null) return expression;
      expression = findStaticField(node, name);
      if (expression != null) return expression;
    }
    return null;
  }
  @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;
  }
  private void writeListDotProperty(
      final Expression receiver,
      final String methodName,
      final MethodVisitor mv,
      final boolean safe) {
    ClassNode componentType =
        (ClassNode) receiver.getNodeMetaData(StaticCompilationMetadataKeys.COMPONENT_TYPE);
    if (componentType == null) {
      componentType = OBJECT_TYPE;
    }
    // for lists, replace list.foo with:
    // def result = new ArrayList(list.size())
    // for (e in list) { result.add (e.foo) }
    // result
    CompileStack compileStack = controller.getCompileStack();

    Label exit = new Label();
    if (safe) {
      receiver.visit(controller.getAcg());
      Label doGet = new Label();
      mv.visitJumpInsn(IFNONNULL, doGet);
      controller.getOperandStack().remove(1);
      mv.visitInsn(ACONST_NULL);
      mv.visitJumpInsn(GOTO, exit);
      mv.visitLabel(doGet);
    }

    Variable tmpList = new VariableExpression("tmpList", make(ArrayList.class));
    int var = compileStack.defineTemporaryVariable(tmpList, false);
    Variable iterator = new VariableExpression("iterator", Iterator_TYPE);
    int it = compileStack.defineTemporaryVariable(iterator, false);
    Variable nextVar = new VariableExpression("next", componentType);
    final int next = compileStack.defineTemporaryVariable(nextVar, false);

    mv.visitTypeInsn(NEW, "java/util/ArrayList");
    mv.visitInsn(DUP);
    receiver.visit(controller.getAcg());
    mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "size", "()I", true);
    controller.getOperandStack().remove(1);
    mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "(I)V", false);
    mv.visitVarInsn(ASTORE, var);
    Label l1 = new Label();
    mv.visitLabel(l1);
    receiver.visit(controller.getAcg());
    mv.visitMethodInsn(
        INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;", true);
    controller.getOperandStack().remove(1);
    mv.visitVarInsn(ASTORE, it);
    Label l2 = new Label();
    mv.visitLabel(l2);
    mv.visitVarInsn(ALOAD, it);
    mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true);
    Label l3 = new Label();
    mv.visitJumpInsn(IFEQ, l3);
    mv.visitVarInsn(ALOAD, it);
    mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true);
    mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(componentType));
    mv.visitVarInsn(ASTORE, next);
    Label l4 = new Label();
    mv.visitLabel(l4);
    mv.visitVarInsn(ALOAD, var);
    final ClassNode finalComponentType = componentType;
    PropertyExpression pexp =
        new PropertyExpression(
            new BytecodeExpression() {
              @Override
              public void visit(final MethodVisitor mv) {
                mv.visitVarInsn(ALOAD, next);
              }

              @Override
              public ClassNode getType() {
                return finalComponentType;
              }
            },
            methodName);
    pexp.visit(controller.getAcg());
    controller.getOperandStack().box();
    controller.getOperandStack().remove(1);
    mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true);
    mv.visitInsn(POP);
    Label l5 = new Label();
    mv.visitLabel(l5);
    mv.visitJumpInsn(GOTO, l2);
    mv.visitLabel(l3);
    mv.visitVarInsn(ALOAD, var);
    if (safe) {
      mv.visitLabel(exit);
    }
    controller.getOperandStack().push(make(ArrayList.class));
    controller.getCompileStack().removeVar(next);
    controller.getCompileStack().removeVar(it);
    controller.getCompileStack().removeVar(var);
  }
 /**
  * Set the source position of toSet including its property expression if it has one.
  *
  * @param toSet resulting node
  * @param origNode original node
  */
 private void setSourcePosition(Expression toSet, Expression origNode) {
   toSet.setSourcePosition(origNode);
   if (toSet instanceof PropertyExpression) {
     ((PropertyExpression) toSet).getProperty().setSourcePosition(origNode);
   }
 }
 public MethodNode getTargetMethod(final Expression expression) {
   return (MethodNode) expression.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
 }
  protected Expression transformMethodCallExpression(MethodCallExpression mce) {
    Expression args = transform(mce.getArguments());
    Expression method = transform(mce.getMethod());
    Expression object = transform(mce.getObjectExpression());
    boolean isExplicitThisOrSuper = false;
    if (object instanceof VariableExpression) {
      VariableExpression ve = (VariableExpression) object;
      isExplicitThisOrSuper =
          !mce.isImplicitThis() && (ve.getName().equals("this") || ve.getName().equals("super"));
    }

    if (mce.isImplicitThis() || isExplicitThisOrSuper) {
      if (mce.isImplicitThis()) {
        Expression ret = findStaticMethodImportFromModule(method, args);
        if (ret != null) {
          // GRECLIPSE add
          if (!((StaticMethodCallExpression) ret).getMethod().equals(method.getText())) {
            // store the identifier to facilitate organizing static imports
            ret.setNodeMetaData("static.import.alias", method.getText());
          }
          // GRECLIPSE end
          setSourcePosition(ret, mce);
          return ret;
        }
        if (method instanceof ConstantExpression && !inLeftExpression) {
          // could be a closure field
          String methodName = (String) ((ConstantExpression) method).getValue();
          ret = findStaticFieldOrPropAccessorImportFromModule(methodName);
          if (ret != null) {
            ret = new MethodCallExpression(ret, "call", args);
            setSourcePosition(ret, mce);
            return ret;
          }
        }
      }

      if (method instanceof ConstantExpression) {
        ConstantExpression ce = (ConstantExpression) method;
        Object value = ce.getValue();
        if (value instanceof String) {
          String methodName = (String) value;
          boolean lookForPossibleStaticMethod = !methodName.equals("call");
          if (currentMethod != null && !currentMethod.isStatic()) {
            if (currentClass.hasPossibleMethod(methodName, args)) {
              lookForPossibleStaticMethod = false;
            }
          }
          if (inSpecialConstructorCall
              || (lookForPossibleStaticMethod
                  && currentClass.hasPossibleStaticMethod(methodName, args))) {
            StaticMethodCallExpression smce =
                new StaticMethodCallExpression(currentClass, methodName, args);
            setSourcePosition(smce, mce);
            return smce;
          }
        }
      }
    }

    MethodCallExpression result = new MethodCallExpression(object, method, args);
    result.setSafe(mce.isSafe());
    result.setImplicitThis(mce.isImplicitThis());
    result.setSpreadSafe(mce.isSpreadSafe());
    result.setMethodTarget(mce.getMethodTarget());
    // GROOVY-6757
    result.setGenericsTypes(mce.getGenericsTypes());
    setSourcePosition(result, mce);
    return result;
  }