use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class StaticTypeCheckingVisitor method getType.
protected ClassNode getType(ASTNode exp) {
ClassNode cn = exp.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (cn != null)
return cn;
if (exp instanceof ClassExpression) {
ClassNode node = CLASS_Type.getPlainNodeReference();
node.setGenericsTypes(new GenericsType[] { new GenericsType(((ClassExpression) exp).getType()) });
return node;
} else if (exp instanceof VariableExpression) {
VariableExpression vexp = (VariableExpression) exp;
ClassNode selfTrait = isTraitSelf(vexp);
if (selfTrait != null)
return makeSelf(selfTrait);
if (vexp == VariableExpression.THIS_EXPRESSION)
return makeThis();
if (vexp == VariableExpression.SUPER_EXPRESSION)
return makeSuper();
final Variable variable = vexp.getAccessedVariable();
if (variable instanceof FieldNode) {
checkOrMarkPrivateAccess(vexp, (FieldNode) variable, isLHSOfEnclosingAssignment(vexp));
return getType((FieldNode) variable);
}
if (variable != null && variable != vexp && variable instanceof VariableExpression) {
return getType((Expression) variable);
}
if (variable instanceof Parameter) {
Parameter parameter = (Parameter) variable;
ClassNode type = typeCheckingContext.controlStructureVariables.get(parameter);
TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
ClassNode[] closureParamTypes = (ClassNode[]) (enclosingClosure != null ? enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) : null);
if (type == null && enclosingClosure != null && "it".equals(variable.getName()) && closureParamTypes != null) {
final Parameter[] parameters = enclosingClosure.getClosureExpression().getParameters();
if (parameters.length == 0 && getTemporaryTypesForExpression(vexp) == null) {
type = closureParamTypes[0];
}
}
if (type != null) {
storeType((VariableExpression) exp, type);
return type;
}
}
}
if (exp instanceof ListExpression) {
return inferListExpressionType((ListExpression) exp);
} else if (exp instanceof MapExpression) {
return inferMapExpressionType((MapExpression) exp);
}
if (exp instanceof ConstructorCallExpression) {
return ((ConstructorCallExpression) exp).getType();
}
if (exp instanceof MethodNode) {
if ((exp == GET_DELEGATE || exp == GET_OWNER || exp == GET_THISOBJECT) && typeCheckingContext.getEnclosingClosure() != null) {
return typeCheckingContext.getEnclosingClassNode();
}
ClassNode ret = getInferredReturnType(exp);
return ret != null ? ret : ((MethodNode) exp).getReturnType();
}
if (exp instanceof ClosureExpression) {
ClassNode irt = getInferredReturnType(exp);
if (irt != null) {
irt = wrapTypeIfNecessary(irt);
ClassNode result = CLOSURE_TYPE.getPlainNodeReference();
result.setGenericsTypes(new GenericsType[] { new GenericsType(irt) });
return result;
}
}
if (exp instanceof RangeExpression) {
ClassNode plain = ClassHelper.RANGE_TYPE.getPlainNodeReference();
RangeExpression re = (RangeExpression) exp;
ClassNode fromType = getType(re.getFrom());
ClassNode toType = getType(re.getTo());
if (fromType.equals(toType)) {
plain.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(fromType)) });
} else {
plain.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(lowestUpperBound(fromType, toType))) });
}
return plain;
}
if (exp instanceof UnaryPlusExpression) {
return getType(((UnaryPlusExpression) exp).getExpression());
}
if (exp instanceof UnaryMinusExpression) {
return getType(((UnaryMinusExpression) exp).getExpression());
}
if (exp instanceof BitwiseNegationExpression) {
return getType(((BitwiseNegationExpression) exp).getExpression());
}
if (exp instanceof MethodCall) {
MethodNode target = (MethodNode) exp.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
if (target != null) {
return getType(target);
}
}
if (exp instanceof Parameter) {
return ((Parameter) exp).getOriginType();
}
if (exp instanceof FieldNode) {
FieldNode fn = (FieldNode) exp;
return getGenericsResolvedTypeOfFieldOrProperty(fn, fn.getOriginType());
}
if (exp instanceof PropertyNode) {
PropertyNode pn = (PropertyNode) exp;
return getGenericsResolvedTypeOfFieldOrProperty(pn, pn.getOriginType());
}
return exp instanceof VariableExpression ? ((VariableExpression) exp).getOriginType() : ((Expression) exp).getType();
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class StaticTypeCheckingVisitor method checkReturnType.
protected ClassNode checkReturnType(final ReturnStatement statement) {
Expression expression = statement.getExpression();
ClassNode type = getType(expression);
if (typeCheckingContext.getEnclosingClosure() != null) {
return type;
}
MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod();
if (enclosingMethod != null && typeCheckingContext.getEnclosingClosure() == null) {
if (!enclosingMethod.isVoidMethod() && !type.equals(void_WRAPPER_TYPE) && !type.equals(VOID_TYPE) && !checkCompatibleAssignmentTypes(enclosingMethod.getReturnType(), type, null, false) && !(isNullConstant(expression))) {
if (!extension.handleIncompatibleReturnType(statement, type)) {
addStaticTypeError("Cannot return value of type " + type.toString(false) + " on method returning type " + enclosingMethod.getReturnType().toString(false), expression);
}
} else if (!enclosingMethod.isVoidMethod()) {
ClassNode previousType = getInferredReturnType(enclosingMethod);
ClassNode inferred = previousType == null ? type : lowestUpperBound(type, previousType);
if (implementsInterfaceOrIsSubclassOf(inferred, enclosingMethod.getReturnType())) {
if (missesGenericsTypes(inferred)) {
DeclarationExpression virtualDecl = new DeclarationExpression(varX("{target}", enclosingMethod.getReturnType()), Token.newSymbol(EQUAL, -1, -1), varX("{source}", type));
virtualDecl.setSourcePosition(statement);
virtualDecl.visit(this);
ClassNode newlyInferred = (ClassNode) virtualDecl.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (!missesGenericsTypes(newlyInferred))
type = newlyInferred;
} else {
checkTypeGenerics(enclosingMethod.getReturnType(), inferred, expression);
}
return type;
} else {
return enclosingMethod.getReturnType();
}
}
}
return type;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class StaticTypeCheckingSupport method removeCovariantsAndInterfaceEquivalents.
private static Collection<MethodNode> removeCovariantsAndInterfaceEquivalents(Collection<MethodNode> collection) {
if (collection.size() <= 1)
return collection;
List<MethodNode> toBeRemoved = new LinkedList<MethodNode>();
List<MethodNode> list = new LinkedList<MethodNode>(new HashSet<MethodNode>(collection));
for (int i = 0; i < list.size() - 1; i++) {
MethodNode one = list.get(i);
if (toBeRemoved.contains(one))
continue;
for (int j = i + 1; j < list.size(); j++) {
MethodNode two = list.get(j);
if (toBeRemoved.contains(two))
continue;
if (one.getParameters().length == two.getParameters().length) {
if (areOverloadMethodsInSameClass(one, two)) {
if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) {
removeMethodWithSuperReturnType(toBeRemoved, one, two);
} else {
// this is an imperfect solution to determining if two methods are
// equivalent, for example String#compareTo(Object) and String#compareTo(String)
// in that case, Java marks the Object version as synthetic
removeSyntheticMethodIfOne(toBeRemoved, one, two);
}
} else if (areEquivalentInterfaceMethods(one, two)) {
// GROOVY-6970 choose between equivalent interface methods
removeMethodInSuperInterface(toBeRemoved, one, two);
}
}
}
}
if (toBeRemoved.isEmpty())
return list;
List<MethodNode> result = new LinkedList<MethodNode>(list);
result.removeAll(toBeRemoved);
return result;
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class InnerClassCompletionVisitor method addDispatcherMethods.
private static void addDispatcherMethods(ClassNode classNode) {
final int objectDistance = getObjectDistance(classNode);
// since we added an anonymous inner class we should also
// add the dispatcher methods
// add method dispatcher
Parameter[] parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "args") };
MethodNode method = classNode.addSyntheticMethod("this$dist$invoke$" + objectDistance, ACC_PUBLIC + ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
BlockStatement block = new BlockStatement();
setMethodDispatcherCode(block, VariableExpression.THIS_EXPRESSION, parameters);
method.setCode(block);
// add property setter
parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "value") };
method = classNode.addSyntheticMethod("this$dist$set$" + objectDistance, ACC_PUBLIC + ACC_SYNTHETIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
setPropertySetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
method.setCode(block);
// add property getter
parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name") };
method = classNode.addSyntheticMethod("this$dist$get$" + objectDistance, ACC_PUBLIC + ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
setPropertyGetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
method.setCode(block);
}
use of org.codehaus.groovy.ast.MethodNode in project groovy by apache.
the class InnerClassCompletionVisitor method addDefaultMethods.
private void addDefaultMethods(InnerClassNode node) {
final boolean isStatic = isStatic(node);
ClassNode outerClass = node.getOuterClass();
final String classInternalName = org.codehaus.groovy.classgen.asm.BytecodeHelper.getClassInternalName(node);
final String outerClassInternalName = getInternalName(outerClass, isStatic);
final String outerClassDescriptor = getTypeDescriptor(outerClass, isStatic);
final int objectDistance = getObjectDistance(outerClass);
// add missing method dispatcher
Parameter[] parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "args") };
String methodName = "methodMissing";
if (isStatic)
addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
MethodNode method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
BlockStatement block = new BlockStatement();
if (isStatic) {
setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
} else {
block.addStatement(new BytecodeSequence(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
getThis(mv, classInternalName, outerClassDescriptor, outerClassInternalName);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$invoke$" + objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(ARETURN);
}
}));
}
method.setCode(block);
// add static missing method dispatcher
methodName = "$static_methodMissing";
if (isStatic)
addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
method.setCode(block);
// add property setter dispatcher
parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name"), new Parameter(ClassHelper.OBJECT_TYPE, "val") };
methodName = "propertyMissing";
if (isStatic)
addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
if (isStatic) {
setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
} else {
block.addStatement(new BytecodeSequence(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
getThis(mv, classInternalName, outerClassDescriptor, outerClassInternalName);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$set$" + objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
mv.visitInsn(RETURN);
}
}));
}
method.setCode(block);
// add static property missing setter dispatcher
methodName = "$static_propertyMissing";
if (isStatic)
addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
method.setCode(block);
// add property getter dispatcher
parameters = new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "name") };
methodName = "propertyMissing";
if (isStatic)
addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
if (isStatic) {
setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
} else {
block.addStatement(new BytecodeSequence(new BytecodeInstruction() {
public void visit(MethodVisitor mv) {
getThis(mv, classInternalName, outerClassDescriptor, outerClassInternalName);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$get$" + objectDistance, "(Ljava/lang/String;)Ljava/lang/Object;", false);
mv.visitInsn(ARETURN);
}
}));
}
method.setCode(block);
// add static property missing getter dispatcher
methodName = "$static_propertyMissing";
if (isStatic)
addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
method = node.addSyntheticMethod(methodName, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, null);
block = new BlockStatement();
setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
method.setCode(block);
}
Aggregations