Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-9077

STC: inferred type not always stored for property getters that resolve to a method

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Minor
    • Resolution: Fixed
    • 2.5.6
    • 3.0.0-beta-1, 2.5.7
    • None
    • None

    Description

      Consider the following:

      @groovy.transform.CompileStatic
      void meth(List list) {
        if (list instanceof LinkedList && list.first) {
        }
        if (list instanceof LinkedList && list.peek()) {
        }
      }
      

      storeTargetMethod is called for the method call expression list.peek(). However, when org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.existsProperty resolves list.first to a method, storeTargetMethod is not called. This means the AST node does not record the direct method call target. Also, a type-checking extension does not have a chance to handle the method selection event.

      This addition addresses the issue for class getters:

                      if (readMode && checkGetterOrSetter) {
                          if (getter != null) {
                              ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
                              storeInferredTypeForPropertyExpression(pexp, cn);
                              // GRECLIPSE add
                              storeTargetMethod(pexp, getter);
                              // GRECLIPSE end
                              pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
                              String delegationData = receiver.getData();
                              if (delegationData != null)
                                  pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
                              return true;
                          }
      

      and this change addresses the issue for extension method getters:

                  // GROOVY-5568, the property may be defined by DGM
                  List<ClassNode> dgmReceivers = new ArrayList<ClassNode>(2);
                  dgmReceivers.add(testClass);
                  if (isPrimitiveType(testClass)) dgmReceivers.add(getWrapper(testClass));
                  for (ClassNode dgmReceiver : dgmReceivers) {
                      List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), dgmReceiver, "get" + capName, ClassNode.EMPTY_ARRAY);
                      for (MethodNode m : findDGMMethodsByNameAndArguments(getTransformLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
                          if (Boolean_TYPE.equals(getWrapper(m.getReturnType()))) methods.add(m);
                      }
                      if (!methods.isEmpty()) {
                          List<MethodNode> methodNodes = chooseBestMethod(dgmReceiver, methods, ClassNode.EMPTY_ARRAY);
                          if (methodNodes.size() == 1) {
                              MethodNode getter = methodNodes.get(0);
                              if (visitor != null) {
                                  visitor.visitMethod(getter);
                              }
                              ClassNode cn = inferReturnTypeGenerics(dgmReceiver, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
                              storeInferredTypeForPropertyExpression(pexp, cn);
                              // GRECLIPSE add
                              storeTargetMethod(pexp, getter);
                              // GRECLIPSE end
                              return true;
                          }
                      }
                  }
      

      The selection of a setter method is not as simple, since there may be many candidates.

      Attachments

        Activity

          People

            paulk Paul King
            emilles Eric Milles
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: