use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class StaticTypeCheckingVisitor method visitClosureExpression.
@Override
public void visitClosureExpression(final ClosureExpression expression) {
boolean oldStaticContext = typeCheckingContext.isInStaticContext;
typeCheckingContext.isInStaticContext = false;
// collect every variable expression used in the loop body
final Map<VariableExpression, ClassNode> varOrigType = new HashMap<VariableExpression, ClassNode>();
Statement code = expression.getCode();
code.visit(new VariableExpressionTypeMemoizer(varOrigType));
Map<VariableExpression, List<ClassNode>> oldTracker = pushAssignmentTracking();
// first, collect closure shared variables and reinitialize types
SharedVariableCollector collector = new SharedVariableCollector(getSourceUnit());
collector.visitClosureExpression(expression);
Set<VariableExpression> closureSharedExpressions = collector.getClosureSharedExpressions();
Map<VariableExpression, ListHashMap> typesBeforeVisit = null;
if (!closureSharedExpressions.isEmpty()) {
typesBeforeVisit = new HashMap<VariableExpression, ListHashMap>();
saveVariableExpressionMetadata(closureSharedExpressions, typesBeforeVisit);
}
// perform visit
typeCheckingContext.pushEnclosingClosureExpression(expression);
DelegationMetadata dmd = getDelegationMetadata(expression);
if (dmd == null) {
typeCheckingContext.delegationMetadata = new DelegationMetadata(typeCheckingContext.getEnclosingClassNode(), Closure.OWNER_FIRST, typeCheckingContext.delegationMetadata);
} else {
typeCheckingContext.delegationMetadata = new DelegationMetadata(dmd.getType(), dmd.getStrategy(), typeCheckingContext.delegationMetadata);
}
super.visitClosureExpression(expression);
typeCheckingContext.delegationMetadata = typeCheckingContext.delegationMetadata.getParent();
MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
returnAdder.visitMethod(node);
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
if (!enclosingClosure.getReturnTypes().isEmpty()) {
ClassNode returnType = lowestUpperBound(enclosingClosure.getReturnTypes());
storeInferredReturnType(expression, returnType);
ClassNode inferredType = wrapClosureType(returnType);
storeType(enclosingClosure.getClosureExpression(), inferredType);
}
typeCheckingContext.popEnclosingClosure();
boolean typeChanged = isSecondPassNeededForControlStructure(varOrigType, oldTracker);
if (typeChanged)
visitClosureExpression(expression);
// restore original metadata
restoreVariableExpressionMetadata(typesBeforeVisit);
typeCheckingContext.isInStaticContext = oldStaticContext;
Parameter[] parameters = expression.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
typeCheckingContext.controlStructureVariables.remove(parameter);
}
}
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class StaticTypeCheckingVisitor method ensureValidSetter.
/**
* Given a binary expression corresponding to an assignment, will check that the type of the RHS matches one
* of the possible setters and if not, throw a type checking error.
* @param expression the assignment expression
* @param leftExpression left expression of the assignment
* @param rightExpression right expression of the assignment
* @param setterInfo possible setters
* @return true if type checking passed
*/
private boolean ensureValidSetter(final Expression expression, final Expression leftExpression, final Expression rightExpression, final SetterInfo setterInfo) {
// for expressions like foo = { ... }
// we know that the RHS type is a closure
// but we must check if the binary expression is an assignment
// because we need to check if a setter uses @DelegatesTo
VariableExpression ve = varX("%", setterInfo.receiverType);
// for compound assignment "x op= y" find type as if it was "x = (x op y)"
final Expression newRightExpression = isCompoundAssignment(expression) ? binX(leftExpression, getOpWithoutEqual(expression), rightExpression) : rightExpression;
MethodCallExpression call = callX(ve, setterInfo.name, newRightExpression);
call.setImplicitThis(false);
visitMethodCallExpression(call);
MethodNode directSetterCandidate = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
if (directSetterCandidate == null) {
// notation AND that the RHS is not a boolean/String/Class
for (MethodNode setter : setterInfo.setters) {
ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
call = callX(ve, setterInfo.name, castX(type, newRightExpression));
call.setImplicitThis(false);
visitMethodCallExpression(call);
directSetterCandidate = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
if (directSetterCandidate != null) {
break;
}
}
}
}
if (directSetterCandidate != null) {
for (MethodNode setter : setterInfo.setters) {
if (setter == directSetterCandidate) {
leftExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
storeType(leftExpression, getType(newRightExpression));
break;
}
}
} else {
ClassNode firstSetterType = setterInfo.setters.iterator().next().getParameters()[0].getOriginType();
addAssignmentError(firstSetterType, getType(newRightExpression), expression);
return true;
}
return false;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class TraitTypeCheckingExtension method handleMissingMethod.
@Override
public List<MethodNode> handleMissingMethod(final ClassNode receiver, final String name, final ArgumentListExpression argumentList, final ClassNode[] argumentTypes, final MethodCall call) {
String[] decomposed = Traits.decomposeSuperCallName(name);
if (decomposed != null) {
return convertToDynamicCall(call, receiver, decomposed, argumentTypes);
}
if (call instanceof MethodCallExpression) {
MethodCallExpression mce = (MethodCallExpression) call;
if (mce.getReceiver() instanceof VariableExpression) {
VariableExpression var = (VariableExpression) mce.getReceiver();
// GROOVY-7322
// static method call in trait?
ClassNode type = null;
if (isStaticTraitReceiver(receiver, var)) {
type = receiver.getGenericsTypes()[0].getType();
} else if (isThisTraitReceiver(var)) {
type = receiver;
}
if (type != null && Traits.isTrait(type)) {
ClassNode helper = Traits.findHelper(type);
Parameter[] params = new Parameter[argumentTypes.length + 1];
params[0] = new Parameter(ClassHelper.CLASS_Type.getPlainNodeReference(), "staticSelf");
for (int i = 1; i < params.length; i++) {
params[i] = new Parameter(argumentTypes[i - 1], "p" + i);
}
MethodNode method = helper.getDeclaredMethod(name, params);
if (method != null) {
return Collections.singletonList(makeDynamic(call, method.getReturnType()));
}
}
}
ClassNode dynamic = mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
if (dynamic != null) {
return Collections.singletonList(makeDynamic(call, dynamic));
}
}
return NOTFOUND;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class SuperCallTraitTransformer method transformBinaryExpression.
private Expression transformBinaryExpression(final BinaryExpression exp) {
Expression trn = super.transform(exp);
if (trn instanceof BinaryExpression) {
BinaryExpression bin = (BinaryExpression) trn;
Expression leftExpression = bin.getLeftExpression();
if (bin.getOperation().getType() == Types.EQUAL && leftExpression instanceof PropertyExpression) {
ClassNode traitReceiver = null;
PropertyExpression leftPropertyExpression = (PropertyExpression) leftExpression;
if (isTraitSuperPropertyExpression(leftPropertyExpression.getObjectExpression())) {
PropertyExpression pexp = (PropertyExpression) leftPropertyExpression.getObjectExpression();
traitReceiver = pexp.getObjectExpression().getType();
}
if (traitReceiver != null) {
// A.super.foo = ...
TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
ClassNode helper = helpers.getHelper();
String setterName = MetaProperty.getSetterName(leftPropertyExpression.getPropertyAsString());
List<MethodNode> methods = helper.getMethods(setterName);
for (MethodNode method : methods) {
Parameter[] parameters = method.getParameters();
if (parameters.length == 2 && parameters[0].getType().equals(traitReceiver)) {
ArgumentListExpression args = new ArgumentListExpression(new VariableExpression("this"), transform(exp.getRightExpression()));
MethodCallExpression setterCall = new MethodCallExpression(new ClassExpression(helper), setterName, args);
setterCall.setMethodTarget(method);
setterCall.setImplicitThis(false);
return setterCall;
}
}
return bin;
}
}
}
return trn;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class StaticTypeCheckingVisitor method visitStaticMethodCallExpression.
@Override
public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) {
final String name = call.getMethod();
if (name == null) {
addStaticTypeError("cannot resolve dynamic method name at compile time.", call);
return;
}
if (extension.beforeMethodCall(call)) {
extension.afterMethodCall(call);
return;
}
Expression callArguments = call.getArguments();
ArgumentListExpression argumentList = InvocationWriter.makeArgumentList(callArguments);
checkForbiddenSpreadArgument(argumentList);
final ClassNode receiver = call.getOwnerType();
visitMethodCallArguments(receiver, argumentList, false, null);
ClassNode[] args = getArgumentTypes(argumentList);
try {
// method call receivers are :
// - possible "with" receivers
// - the actual receiver as found in the method call expression
// - any of the potential receivers found in the instanceof temporary table
// in that order
List<Receiver<String>> receivers = new LinkedList<Receiver<String>>();
addReceivers(receivers, makeOwnerList(new ClassExpression(receiver)), false);
List<MethodNode> mn = null;
Receiver<String> chosenReceiver = null;
for (Receiver<String> currentReceiver : receivers) {
mn = findMethod(currentReceiver.getType(), name, args);
if (!mn.isEmpty()) {
if (mn.size() == 1)
typeCheckMethodsWithGenericsOrFail(currentReceiver.getType(), args, mn.get(0), call);
chosenReceiver = currentReceiver;
break;
}
}
if (mn.isEmpty()) {
mn = extension.handleMissingMethod(receiver, name, argumentList, args, call);
}
boolean callArgsVisited = false;
if (mn.isEmpty()) {
addNoMatchingMethodError(receiver, name, args, call);
} else {
mn = disambiguateMethods(mn, receiver, args, call);
if (mn.size() == 1) {
MethodNode directMethodCallCandidate = mn.get(0);
ClassNode returnType = getType(directMethodCallCandidate);
if (returnType.isUsingGenerics() && !returnType.isEnum()) {
visitMethodCallArguments(receiver, argumentList, true, directMethodCallCandidate);
ClassNode irtg = inferReturnTypeGenerics(chosenReceiver.getType(), directMethodCallCandidate, callArguments);
returnType = irtg != null && implementsInterfaceOrIsSubclassOf(irtg, returnType) ? irtg : returnType;
callArgsVisited = true;
}
storeType(call, returnType);
storeTargetMethod(call, directMethodCallCandidate);
} else {
addAmbiguousErrorMessage(mn, name, args, call);
}
if (!callArgsVisited) {
visitMethodCallArguments(receiver, argumentList, true, (MethodNode) call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
}
}
} finally {
extension.afterMethodCall(call);
}
}
Aggregations