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);
}
}
}