public void visitMethodPointerExpression()

in src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java [2605:2712]


    public void visitMethodPointerExpression(final MethodPointerExpression expression) {
        super.visitMethodPointerExpression(expression);
        Expression nameExpr = expression.getMethodName();
        if (nameExpr instanceof ConstantExpression
                && isStringType(getType(nameExpr))) {
            String nameText = nameExpr.getText();

            if ("new".equals(nameText)) {
                ClassNode type = getType(expression.getExpression());
                if (isClassClassNodeWrappingConcreteType(type)){
                    type = type.getGenericsTypes()[0].getType();
                    storeType(expression,wrapClosureType(type));
                    // GROOVY-11385: check if create possible
                    if (type.isAbstract() && !type.isArray())
                        addStaticTypeError("Cannot instantiate the type " +
                                    prettyPrintTypeName(type), expression);
                    // GROOVY-10930: check constructor reference
                    ClassNode[] signature = expression.getNodeMetaData(CLOSURE_ARGUMENTS);
                    if (signature != null) { Expression[] mocks = Arrays.stream(signature)
                            .map(t -> typedValueExpression(t)).toArray(Expression[]::new);
                        Expression dummy = ctorX(type, args(mocks));
                        dummy.setSourcePosition(expression);
                        dummy.visit(this);
                    }
                }
                return;
            }

            List<Receiver<String>> receivers = new ArrayList<>();
            addReceivers(receivers, makeOwnerList(expression.getExpression()), false);

            ClassNode receiverType = null;
            List<MethodNode> candidates = EMPTY_METHODNODE_LIST;
            for (Receiver<String> currentReceiver : receivers) {
                receiverType = wrapTypeIfNecessary(currentReceiver.getType());

                candidates = findMethodsWithGenerated(receiverType, nameText);
                // GROOVY-10741: check for reference to a property node's method
                MethodNode generated = findPropertyMethod(receiverType, nameText);
                if (generated != null && candidates.stream().noneMatch(m -> m.getName().equals(generated.getName()))) {
                    candidates.add(generated);
                }
                candidates.addAll(findDGMMethodsForClassNode(getSourceUnit().getClassLoader(), receiverType, nameText));

                if (candidates.size() > 1) {
                    candidates = filterMethodCandidates(candidates, expression.getExpression(), expression.getNodeMetaData(CLOSURE_ARGUMENTS));
                }
                if (!candidates.isEmpty()) {
                    break;
                }
            }

            if (candidates.isEmpty()) {
                candidates = extension.handleMissingMethod(
                    getType(expression.getExpression()), nameText, null, null, null);
            } else if (candidates.size() > 1) {
                candidates = extension.handleAmbiguousMethods(candidates, expression);
            }

            if (!candidates.isEmpty()) {
                ClassNode[] arguments = expression.getNodeMetaData(CLOSURE_ARGUMENTS);
                if (asBoolean(arguments) && asBoolean(receiverType.redirect().getGenericsTypes())
                                         && expression.getExpression() instanceof ClassExpression) {
                    receiverType = GenericsUtils.parameterizeType(arguments[0], receiverType); // GROOVY-11241
                }

                ClassNode ownerType = receiverType;
                candidates.stream()
                        .peek(candidate -> checkOrMarkPrivateAccess(expression, candidate)) // GROOVY-11365
                        .map (candidate -> {
                            ClassNode returnType = candidate.getReturnType();
                            if (!candidate.isStatic() && GenericsUtils.hasUnresolvedGenerics(returnType)) {
                                Map<GenericsTypeName, GenericsType> spec = new HashMap<>(); // GROOVY-11364
                                extractGenericsConnections(spec, ownerType, candidate.getDeclaringClass());
                                returnType = applyGenericsContext(spec, returnType);
                            }
                            return returnType;
                        })
                        .reduce(WideningCategories::lowestUpperBound).ifPresent(returnType -> {
                            ClassNode closureType = wrapClosureType(returnType);
                            storeType(expression, closureType);
                            // GROOVY-10858: check method return type
                            ClassNode targetType = expression.getNodeMetaData(PARAMETER_TYPE);
                            if (!returnType.isGenericsPlaceHolder() && isSAMType(targetType)) {
                                targetType = GenericsUtils.parameterizeSAM(targetType).getV2();
                                if (!isPrimitiveVoid(targetType) && !checkCompatibleAssignmentTypes(targetType, returnType, null, false)) // TODO: ext.handleIncompatibleReturnType
                                    addStaticTypeError("Invalid return type: " + prettyPrintType(returnType) + " is not convertible to " + prettyPrintType(targetType), expression);
                            }
                        });
                expression.putNodeMetaData(MethodNode.class, candidates);

                if (asBoolean(arguments)) {
                    ClassNode[] parameters = collateMethodReferenceParameterTypes(expression, candidates.get(0));
                    for (int i = 0; i < arguments.length; i += 1) {
                        ClassNode at = arguments[i];
                        ClassNode pt = parameters[Math.min(i, parameters.length - 1)];
                        if (!pt.equals(at) && (at.isInterface() ? pt.implementsInterface(at) : pt.isDerivedFrom(at)))
                            arguments[i] = pt; // GROOVY-10734, GROOVY-10807, GROPOVY-11026: expected type is refined
                    }
                }
            } else if (!(expression instanceof MethodReferenceExpression)
                    || this.getClass() == StaticTypeCheckingVisitor.class) {
                ClassNode type = wrapTypeIfNecessary(getType(expression.getExpression()));
                if (isClassClassNodeWrappingConcreteType(type)) type = type.getGenericsTypes()[0].getType();
                addStaticTypeError("Cannot find matching method " + prettyPrintTypeName(type) + "#" + nameText + ". Please check if the declared type is correct and if the method exists.", nameExpr);
            }
        }
    }