@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);
  }
Пример #2
0
  private List getPrimaryClassNodes(boolean sort) {
    if (sort == true) {
      List<ModuleNode> sortedModules = this.ast.getSortedModules();
      if (sortedModules != null) {
        return sortedModules;
      }
    }
    // FIXASC (groovychange) rewritten
    /*old{
    List unsorted = new ArrayList();
    Iterator modules = this.ast.getModules().iterator();
    while (modules.hasNext()) {
        ModuleNode module = (ModuleNode) modules.next();

        Iterator classNodes = module.getClasses().iterator();
        while (classNodes.hasNext()) {
            ClassNode classNode = (ClassNode) classNodes.next();
            unsorted.add(classNode);
        }
    }
    */
    // new
    List<ClassNode> unsorted = new ArrayList<ClassNode>();
    for (ModuleNode module : this.ast.getModules()) {
      unsorted.addAll(module.getClasses());
    }
    // FIXASC (groovychange) end

    if (!sort) return unsorted;

    // GRECLIPSE: start: rewritten sort algorithm
    /*old{
            int[] indexClass = new int[unsorted.size()];
            int[] indexInterface = new int[unsorted.size()];
            {
                int i = 0;
                for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) {
                    ClassNode element = iter.next();
                    if (element.isInterface()) {
                        indexInterface[i] = getSuperInterfaceCount(element);
                        indexClass[i] = -1;
                    } else {
                        indexClass[i] = getSuperClassCount(element);
                        indexInterface[i] = -1;
                    }
                }
            }

            List<ClassNode> sorted = getSorted(indexInterface, unsorted);
            sorted.addAll(getSorted(indexClass, unsorted));
    */
    // newcode:
    // Sort them by how many types are in their hierarchy, but all interfaces first.
    // Algorithm:
    // Create a list of integers.  Each integer captures the index into the unsorted
    // list (bottom 16bits) and the count of how many types are in that types
    // hierarchy (top 16bits).  For classes the count is augmented by 2000 so that
    // when sorting the classes will come out after the interfaces.
    // This list of integers is sorted.  We then just go through it and for the
    // lower 16bits of each entry (0xffff) that is the index of the next value to
    // pull from the unsorted list and put into the sorted list.
    // Will break down if more than 2000 interfaces in the type hierarchy for an
    // individual type, or a project contains > 65535 files... but if you've got
    // that kind of setup, you have other problems...
    List<Integer> countIndexPairs = new ArrayList<Integer>();
    {
      int i = 0;
      for (Iterator iter = unsorted.iterator(); iter.hasNext(); i++) {
        ClassNode node = (ClassNode) iter.next();
        if (node.isInterface()) {
          countIndexPairs.add((getSuperInterfaceCount(node) << 16) + i);
        } else {
          countIndexPairs.add(((getSuperClassCount(node) + 2000) << 16) + i);
        }
      }
    }
    Collections.sort(countIndexPairs);
    List sorted = new ArrayList();
    for (int i : countIndexPairs) {
      sorted.add(unsorted.get(i & 0xffff));
    }
    this.ast.setSortedModules(sorted);
    // end
    return sorted;
  }