use of org.codehaus.groovy.ast.InnerClassNode in project gradle by gradle.
the class GradleResolveVisitor method checkThisAndSuperAsPropertyAccess.
private void checkThisAndSuperAsPropertyAccess(PropertyExpression expression) {
if (expression.isImplicitThis()) {
return;
}
String prop = expression.getPropertyAsString();
if (prop == null) {
return;
}
if (!prop.equals("this") && !prop.equals("super")) {
return;
}
ClassNode type = expression.getObjectExpression().getType();
if (expression.getObjectExpression() instanceof ClassExpression) {
if (!(currentClass instanceof InnerClassNode) && !Traits.isTrait(type)) {
addError("The usage of 'Class.this' and 'Class.super' is only allowed in nested/inner classes.", expression);
return;
}
if (currentScope != null && !currentScope.isInStaticContext() && Traits.isTrait(type) && "super".equals(prop) && directlyImplementsTrait(type)) {
return;
}
ClassNode iterType = currentClass;
while (iterType != null) {
if (iterType.equals(type)) {
break;
}
iterType = iterType.getOuterClass();
}
if (iterType == null) {
addError("The class '" + type.getName() + "' needs to be an outer class of '" + currentClass.getName() + "' when using '.this' or '.super'.", expression);
}
if ((currentClass.getModifiers() & Opcodes.ACC_STATIC) == 0) {
return;
}
if (currentScope != null && !currentScope.isInStaticContext()) {
return;
}
addError("The usage of 'Class.this' and 'Class.super' within static nested class '" + currentClass.getName() + "' is not allowed in a static context.", expression);
}
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
the class InnerClassVisitor method visitConstructorCallExpression.
@Override
public void visitConstructorCallExpression(ConstructorCallExpression call) {
super.visitConstructorCallExpression(call);
if (!call.isUsingAnonymousInnerClass()) {
passThisReference(call);
return;
}
InnerClassNode innerClass = (InnerClassNode) call.getType();
ClassNode outerClass = innerClass.getOuterClass();
ClassNode superClass = innerClass.getSuperClass();
if (superClass instanceof InnerClassNode && !superClass.isInterface() && !(superClass.isStaticClass() || ((superClass.getModifiers() & ACC_STATIC) == ACC_STATIC))) {
insertThis0ToSuperCall(call, innerClass);
}
if (!innerClass.getDeclaredConstructors().isEmpty())
return;
if ((innerClass.getModifiers() & ACC_STATIC) != 0)
return;
VariableScope scope = innerClass.getVariableScope();
if (scope == null)
return;
// expressions = constructor call arguments
List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions();
// block = init code for the constructor we produce
BlockStatement block = new BlockStatement();
// parameters = parameters of the constructor
final int additionalParamCount = 1 + scope.getReferencedLocalVariablesCount();
List<Parameter> parameters = new ArrayList<Parameter>(expressions.size() + additionalParamCount);
// superCallArguments = arguments for the super call == the constructor call arguments
List<Expression> superCallArguments = new ArrayList<Expression>(expressions.size());
// first we add a super() call for all expressions given in the
// constructor call expression
int pCount = additionalParamCount;
for (Expression expr : expressions) {
pCount++;
// add one parameter for each expression in the
// constructor call
Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + pCount);
parameters.add(param);
// add to super call
superCallArguments.add(new VariableExpression(param));
}
// add the super call
ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression(superCallArguments));
block.addStatement(new ExpressionStatement(cce));
// we need to add "this" to access unknown methods/properties
// this is saved in a field named this$0
pCount = 0;
expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
boolean isStatic = isStaticThis(innerClass, scope);
ClassNode outerClassType = getClassNode(outerClass, isStatic);
if (!isStatic && inClosure)
outerClassType = ClassHelper.CLOSURE_TYPE;
outerClassType = outerClassType.getPlainNodeReference();
Parameter thisParameter = new Parameter(outerClassType, "p" + pCount);
parameters.add(pCount, thisParameter);
thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, outerClassType, null);
addFieldInit(thisParameter, thisField, block);
// for each shared variable we add a reference and save it as field
for (Iterator it = scope.getReferencedLocalVariablesIterator(); it.hasNext(); ) {
pCount++;
org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) it.next();
VariableExpression ve = new VariableExpression(var);
ve.setClosureSharedVariable(true);
ve.setUseReferenceDirectly(true);
expressions.add(pCount, ve);
ClassNode rawReferenceType = ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
Parameter p = new Parameter(rawReferenceType, "p" + pCount);
parameters.add(pCount, p);
p.setOriginType(var.getOriginType());
final VariableExpression initial = new VariableExpression(p);
initial.setSynthetic(true);
initial.setUseReferenceDirectly(true);
final FieldNode pField = innerClass.addFieldFirst(ve.getName(), PUBLIC_SYNTHETIC, rawReferenceType, initial);
pField.setHolder(true);
pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
}
innerClass.addConstructor(ACC_SYNTHETIC, parameters.toArray(new Parameter[parameters.size()]), ClassNode.EMPTY_ARRAY, block);
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
the class EnumHelper method makeEnumNode.
public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) {
modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
ClassNode enumClass;
if (outerClass == null) {
enumClass = new ClassNode(name, modifiers, null, interfaces, MixinNode.EMPTY_ARRAY);
} else {
name = outerClass.getName() + "$" + name;
enumClass = new InnerClassNode(outerClass, name, modifiers, null, interfaces, MixinNode.EMPTY_ARRAY);
}
// set super class and generics info
// "enum X" -> class X extends Enum<X>
GenericsType gt = new GenericsType(enumClass);
ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum");
superClass.setGenericsTypes(new GenericsType[] { gt });
enumClass.setSuperClass(superClass);
superClass.setRedirect(ClassHelper.Enum_Type);
return enumClass;
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
the class TraitASTTransformation method createHelperClass.
private void createHelperClass(final ClassNode cNode) {
ClassNode helper = new InnerClassNode(cNode, Traits.helperClassName(cNode), ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, ClassNode.EMPTY_ARRAY, null);
cNode.setModifiers(ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT);
checkInnerClasses(cNode);
MethodNode initializer = createInitMethod(false, cNode, helper);
MethodNode staticInitializer = createInitMethod(true, cNode, helper);
// apply the verifier to have the property nodes generated
generatePropertyMethods(cNode);
// prepare fields
List<FieldNode> fields = new ArrayList<FieldNode>();
Set<String> fieldNames = new HashSet<String>();
for (FieldNode field : cNode.getFields()) {
if (!"metaClass".equals(field.getName()) && (!field.isSynthetic() || field.getName().indexOf('$') < 0)) {
fields.add(field);
fieldNames.add(field.getName());
}
}
ClassNode fieldHelper = null;
if (!fields.isEmpty()) {
fieldHelper = new InnerClassNode(cNode, Traits.fieldHelperClassName(cNode), ACC_STATIC | ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, ClassHelper.OBJECT_TYPE);
}
// add methods
List<MethodNode> methods = new ArrayList<MethodNode>(cNode.getMethods());
List<MethodNode> nonPublicAPIMethods = new LinkedList<MethodNode>();
for (final MethodNode methodNode : methods) {
boolean declared = methodNode.getDeclaringClass() == cNode;
if (declared) {
if (!methodNode.isSynthetic() && (methodNode.isProtected() || methodNode.getModifiers() == 0)) {
unit.addError(new SyntaxException("Cannot have protected/package private method in a trait (" + cNode.getName() + "#" + methodNode.getTypeDescriptor() + ")", methodNode.getLineNumber(), methodNode.getColumnNumber()));
return;
}
helper.addMethod(processMethod(cNode, methodNode, fieldHelper, fieldNames));
if (methodNode.isPrivate() || methodNode.isStatic()) {
nonPublicAPIMethods.add(methodNode);
}
}
}
// remove methods which should not appear in the trait interface
for (MethodNode privateMethod : nonPublicAPIMethods) {
cNode.removeMethod(privateMethod);
}
// add fields
for (FieldNode field : fields) {
processField(field, initializer, staticInitializer, fieldHelper, cNode, fieldNames);
}
// clear properties to avoid generation of methods
cNode.getProperties().clear();
// copy annotations
copyClassAnnotations(cNode, helper);
// reuse the full list of fields
fields = new ArrayList<FieldNode>(cNode.getFields());
for (FieldNode field : fields) {
cNode.removeField(field.getName());
}
// visit AST xforms
registerASTTranformations(helper);
unit.getAST().addClass(helper);
if (fieldHelper != null) {
unit.getAST().addClass(fieldHelper);
}
// resolve scope (for closures)
resolveScope(helper);
if (fieldHelper != null) {
resolveScope(fieldHelper);
}
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
the class StaticTypeCheckingVisitor method existsProperty.
/**
* Checks whether a property exists on the receiver, or on any of the possible receiver classes (found in the
* temporary type information table)
*
* @param pexp a property expression
* @param readMode if true, look for property read, else for property set
* @param visitor if not null, when the property node is found, visit it with the provided visitor
* @return true if the property is defined in any of the possible receiver classes
*/
protected boolean existsProperty(final PropertyExpression pexp, final boolean readMode, final ClassCodeVisitorSupport visitor) {
super.visitPropertyExpression(pexp);
String propertyName = pexp.getPropertyAsString();
if (propertyName == null)
return false;
Expression objectExpression = pexp.getObjectExpression();
final ClassNode objectExpressionType = getType(objectExpression);
boolean staticOnlyAccess = isClassClassNodeWrappingConcreteType(objectExpressionType);
if ("this".equals(propertyName) && staticOnlyAccess) {
// Outer.this
ClassNode outerNode = objectExpressionType.getGenericsTypes()[0].getType();
ClassNode current = typeCheckingContext.getEnclosingClassNode();
if (!current.isStaticClass() && current instanceof InnerClassNode) {
InnerClassNode icn = (InnerClassNode) current;
if (outerNode.equals(icn.getOuterClass())) {
storeType(pexp, outerNode);
return true;
}
}
}
if (objectExpressionType.isArray() && "length".equals(pexp.getPropertyAsString())) {
storeType(pexp, int_TYPE);
if (visitor != null) {
PropertyNode node = new PropertyNode("length", Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, int_TYPE, objectExpressionType, null, null, null);
visitor.visitProperty(node);
}
return true;
}
boolean foundGetterOrSetter = false;
List<Receiver<String>> receivers = new LinkedList<Receiver<String>>();
List<Receiver<String>> owners = makeOwnerList(objectExpression);
addReceivers(receivers, owners, pexp.isImplicitThis());
String capName = MetaClassHelper.capitalize(propertyName);
boolean isAttributeExpression = pexp instanceof AttributeExpression;
HashSet<ClassNode> handledNodes = new HashSet<ClassNode>();
for (Receiver<String> receiver : receivers) {
ClassNode testClass = receiver.getType();
LinkedList<ClassNode> queue = new LinkedList<ClassNode>();
queue.add(testClass);
if (isPrimitiveType(testClass)) {
queue.add(getWrapper(testClass));
}
while (!queue.isEmpty()) {
ClassNode current = queue.removeFirst();
if (handledNodes.contains(current))
continue;
handledNodes.add(current);
Set<ClassNode> allInterfaces = current.getAllInterfaces();
for (ClassNode intf : allInterfaces) {
//TODO: apply right generics here!
queue.add(GenericsUtils.parameterizeType(current, intf));
}
// in case of a lookup on Class we look for instance methods on Class
// as well, since in case of a static property access we have the class
// itself in the list of receivers already;
boolean staticOnly;
if (isClassClassNodeWrappingConcreteType(current)) {
staticOnly = false;
} else {
staticOnly = staticOnlyAccess;
}
FieldNode field = current.getDeclaredField(propertyName);
field = allowStaticAccessToMember(field, staticOnly);
if (storeField(field, isAttributeExpression, pexp, current, visitor, receiver.getData()))
return true;
PropertyNode propertyNode = current.getProperty(propertyName);
propertyNode = allowStaticAccessToMember(propertyNode, staticOnly);
if (storeProperty(propertyNode, pexp, current, visitor, receiver.getData()))
return true;
boolean isThisExpression = objectExpression instanceof VariableExpression && ((VariableExpression) objectExpression).isThisExpression();
if (storeField(field, isThisExpression, pexp, receiver.getType(), visitor, receiver.getData()))
return true;
MethodNode getter = current.getGetterMethod("get" + capName);
getter = allowStaticAccessToMember(getter, staticOnly);
if (getter == null)
getter = current.getGetterMethod("is" + capName);
getter = allowStaticAccessToMember(getter, staticOnly);
final String setterName = "set" + capName;
List<MethodNode> setters = findSetters(current, setterName, false);
setters = allowStaticAccessToMember(setters, staticOnly);
// need to visit even if we only look for a setters for compatibility
if (visitor != null && getter != null)
visitor.visitMethod(getter);
if (readMode) {
if (getter != null) {
ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, cn);
pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
String delegationData = receiver.getData();
if (delegationData != null)
pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
return true;
}
} else {
if (!setters.isEmpty()) {
if (visitor != null) {
if (field != null) {
visitor.visitField(field);
} else {
for (MethodNode setter : setters) {
ClassNode setterType = setter.getParameters()[0].getOriginType();
FieldNode virtual = new FieldNode(propertyName, 0, setterType, current, EmptyExpression.INSTANCE);
visitor.visitField(virtual);
}
}
}
//TODO: apply generics on parameter[0]?
// storeType(pexp, setter.getParameters()[0].getType());
SetterInfo info = new SetterInfo(current, setterName, setters);
BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
if (enclosingBinaryExpression != null) {
putSetterInfo(enclosingBinaryExpression.getLeftExpression(), info);
}
String delegationData = receiver.getData();
if (delegationData != null) {
pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
}
return true;
} else if (getter != null) {
pexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY, true);
}
}
foundGetterOrSetter = foundGetterOrSetter || !setters.isEmpty() || getter != null;
if (storeField(field, true, pexp, current, visitor, receiver.getData()))
return true;
// we stop now, otherwise we must check the parent class
if (/*!isAttributeExpression && */
current.getSuperClass() != null) {
queue.add(current.getUnresolvedSuperClass());
}
}
// GROOVY-5568, the property may be defined by DGM
List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), testClass, "get" + capName, ClassNode.EMPTY_ARRAY);
if (!methods.isEmpty()) {
List<MethodNode> methodNodes = chooseBestMethod(testClass, methods, ClassNode.EMPTY_ARRAY);
if (methodNodes.size() == 1) {
MethodNode getter = methodNodes.get(0);
if (visitor != null) {
visitor.visitMethod(getter);
}
ClassNode cn = inferReturnTypeGenerics(testClass, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, cn);
return true;
}
}
}
for (Receiver<String> receiver : receivers) {
ClassNode testClass = receiver.getType();
ClassNode propertyType = getTypeForMapPropertyExpression(testClass, objectExpressionType, pexp);
if (propertyType == null)
propertyType = getTypeForListPropertyExpression(testClass, objectExpressionType, pexp);
if (propertyType == null)
propertyType = getTypeForSpreadExpression(testClass, objectExpressionType, pexp);
if (propertyType == null)
continue;
if (visitor != null) {
// todo : type inference on maps and lists, if possible
PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiver.getType(), null, null, null);
node.setDeclaringClass(receiver.getType());
visitor.visitProperty(node);
}
storeType(pexp, propertyType);
String delegationData = receiver.getData();
if (delegationData != null)
pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
return true;
}
return foundGetterOrSetter;
}
Aggregations