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 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 EnumVisitor method addInit.
private void addInit(ClassNode enumClass, FieldNode minValue, FieldNode maxValue, FieldNode values, boolean isAic) {
// constructor helper
// This method is used instead of calling the constructor as
// calling the constructor may require a table with MetaClass
// selecting the constructor for each enum value. So instead we
// use this method to have a central point for constructor selection
// and only one table. The whole construction is needed because
// Reflection forbids access to the enum constructor.
// code:
// def $INIT(Object[] para) {
// return this(*para)
// }
ClassNode enumRef = enumClass.getPlainNodeReference();
Parameter[] parameter = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "para") };
MethodNode initMethod = new MethodNode("$INIT", PUBLIC_FS | Opcodes.ACC_SYNTHETIC, enumRef, parameter, ClassNode.EMPTY_ARRAY, null);
initMethod.setSynthetic(true);
ConstructorCallExpression cce = new ConstructorCallExpression(ClassNode.THIS, new ArgumentListExpression(new SpreadExpression(new VariableExpression("para"))));
BlockStatement code = new BlockStatement();
code.addStatement(new ReturnStatement(cce));
initMethod.setCode(code);
enumClass.addMethod(initMethod);
// static init
List<FieldNode> fields = enumClass.getFields();
List<Expression> arrayInit = new ArrayList<Expression>();
int value = -1;
Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
List<Statement> block = new ArrayList<Statement>();
FieldNode tempMin = null;
FieldNode tempMax = null;
for (FieldNode field : fields) {
if ((field.getModifiers() & Opcodes.ACC_ENUM) == 0)
continue;
value++;
if (tempMin == null)
tempMin = field;
tempMax = field;
ClassNode enumBase = enumClass;
ArgumentListExpression args = new ArgumentListExpression();
args.addExpression(new ConstantExpression(field.getName()));
args.addExpression(new ConstantExpression(value));
if (field.getInitialExpression() == null) {
if ((enumClass.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
addError(field, "The enum constant " + field.getName() + " must override abstract methods from " + enumBase.getName() + ".");
continue;
}
} else {
ListExpression oldArgs = (ListExpression) field.getInitialExpression();
List<MapEntryExpression> savedMapEntries = new ArrayList<MapEntryExpression>();
for (Expression exp : oldArgs.getExpressions()) {
if (exp instanceof MapEntryExpression) {
savedMapEntries.add((MapEntryExpression) exp);
continue;
}
InnerClassNode inner = null;
if (exp instanceof ClassExpression) {
ClassExpression clazzExp = (ClassExpression) exp;
ClassNode ref = clazzExp.getType();
if (ref instanceof EnumConstantClassNode) {
inner = (InnerClassNode) ref;
}
}
if (inner != null) {
List<MethodNode> baseMethods = enumBase.getMethods();
for (MethodNode methodNode : baseMethods) {
if (!methodNode.isAbstract())
continue;
MethodNode enumConstMethod = inner.getMethod(methodNode.getName(), methodNode.getParameters());
if (enumConstMethod == null || (enumConstMethod.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
addError(field, "Can't have an abstract method in enum constant " + field.getName() + ". Implement method '" + methodNode.getTypeDescriptor() + "'.");
}
}
if (inner.getVariableScope() == null) {
enumBase = inner;
/*
* GROOVY-3985: Remove the final modifier from $INIT method in this case
* so that subclasses of enum generated for enum constants (aic) can provide
* their own $INIT method
*/
initMethod.setModifiers(initMethod.getModifiers() & ~Opcodes.ACC_FINAL);
continue;
}
}
args.addExpression(exp);
}
if (savedMapEntries.size() > 0) {
args.getExpressions().add(2, new MapExpression(savedMapEntries));
}
}
field.setInitialValueExpression(null);
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(field), assign, new StaticMethodCallExpression(enumBase, "$INIT", args))));
arrayInit.add(new FieldExpression(field));
}
if (!isAic) {
if (tempMin != null) {
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(minValue), assign, new FieldExpression(tempMin))));
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(maxValue), assign, new FieldExpression(tempMax))));
enumClass.addField(minValue);
enumClass.addField(maxValue);
}
block.add(new ExpressionStatement(new BinaryExpression(new FieldExpression(values), assign, new ArrayExpression(enumClass, arrayInit))));
enumClass.addField(values);
}
enumClass.addStaticInitializerStatements(block, true);
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class StaticTypesCallSiteWriter method makeGetPropertyWithGetter.
private boolean makeGetPropertyWithGetter(final Expression receiver, final ClassNode receiverType, final String propertyName, final boolean safe, final boolean implicitThis) {
// check for an accessor method
String getterName = "is" + capitalize(propertyName);
MethodNode getterNode = receiverType.getGetterMethod(getterName);
if (getterNode == null) {
getterName = "get" + capitalize(propertyName);
getterNode = receiverType.getGetterMethod(getterName);
}
if (getterNode != null && receiver instanceof ClassExpression && !isClassType(receiverType) && !getterNode.isStatic()) {
return false;
}
// GROOVY-5561: if two files are compiled in the same source unit and
// one references the other, the getters for properties have not been
// generated by the compiler yet (generated by the Verifier)
PropertyNode propertyNode = receiverType.getProperty(propertyName);
if (getterNode == null && propertyNode != null) {
// it is possible to use an accessor method
String prefix = isPrimitiveBoolean(propertyNode.getOriginType()) ? "is" : "get";
getterName = prefix + capitalize(propertyName);
getterNode = new MethodNode(getterName, ACC_PUBLIC | (propertyNode.isStatic() ? ACC_STATIC : 0), propertyNode.getOriginType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
getterNode.setDeclaringClass(receiverType);
}
if (getterNode != null) {
if (!AsmClassGenerator.isMemberDirectlyAccessible(getterNode.getModifiers(), getterNode.getDeclaringClass(), controller.getClassNode())) {
// GROOVY-6277
return false;
}
MethodCallExpression call = callX(receiver, getterName);
call.setImplicitThis(implicitThis);
call.setMethodTarget(getterNode);
call.setSafe(safe);
call.setSourcePosition(receiver);
call.visit(controller.getAcg());
return true;
}
if (receiverType instanceof InnerClassNode && !receiverType.isStaticClass()) {
if (makeGetPropertyWithGetter(receiver, receiverType.getOuterClass(), propertyName, safe, implicitThis)) {
return true;
}
}
// GROOVY-7149: check direct interfaces
for (ClassNode node : receiverType.getInterfaces()) {
if (makeGetPropertyWithGetter(receiver, node, propertyName, safe, implicitThis)) {
return true;
}
}
// go upper level
ClassNode superClass = receiverType.getSuperClass();
if (superClass != null) {
return makeGetPropertyWithGetter(receiver, superClass, propertyName, safe, implicitThis);
}
return false;
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class StaticTypeCheckingVisitor method findMethod.
protected List<MethodNode> findMethod(ClassNode receiver, final String name, final ClassNode... args) {
if (isPrimitiveType(receiver))
receiver = getWrapper(receiver);
List<MethodNode> methods;
if ("<init>".equals(name) && !receiver.isInterface()) {
methods = addGeneratedMethods(receiver, new ArrayList<>(receiver.getDeclaredConstructors()));
if (methods.isEmpty()) {
MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
node.setDeclaringClass(receiver);
methods.add(node);
if (receiver.isArray()) {
// arbitrary number of parameters.
return methods;
}
}
} else {
methods = findMethodsWithGenerated(receiver, name);
if ("call".equals(name) && receiver.isInterface()) {
MethodNode sam = findSAM(receiver);
if (sam != null) {
MethodNode callMethod = new MethodNode("call", sam.getModifiers(), sam.getReturnType(), sam.getParameters(), sam.getExceptions(), sam.getCode());
callMethod.setDeclaringClass(sam.getDeclaringClass());
callMethod.setSourcePosition(sam);
methods.add(callMethod);
}
}
if (!receiver.isStaticClass() && receiver.getOuterClass() != null && typeCheckingContext.getEnclosingClassNodes().contains(receiver)) {
ClassNode outer = receiver.getOuterClass();
do {
methods.addAll(findMethodsWithGenerated(outer, name));
} while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
}
if (methods.isEmpty()) {
addArrayMethods(methods, receiver, name, args);
}
if (methods.isEmpty() && (args == null || args.length == 0)) {
// check if it's a property
String pname = extractPropertyNameFromMethodName("get", name);
if (pname == null) {
pname = extractPropertyNameFromMethodName("is", name);
}
PropertyNode property = null;
if (pname != null) {
property = findProperty(receiver, pname);
} else {
out: for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
for (PropertyNode pn : cn.getProperties()) {
if (name.equals(pn.getGetterName())) {
property = pn;
break out;
}
}
}
}
if (property != null) {
int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
MethodNode node = new MethodNode(name, mods, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
node.setDeclaringClass(property.getDeclaringClass());
return Collections.singletonList(node);
}
} else if (methods.isEmpty() && args != null && args.length == 1) {
// maybe we are looking for a setter ?
String pname = extractPropertyNameFromMethodName("set", name);
if (pname != null) {
PropertyNode property = findProperty(receiver, pname);
if (property != null && !Modifier.isFinal(property.getModifiers())) {
ClassNode type = property.getOriginType();
if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) {
int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0);
MethodNode node = new MethodNode(name, mods, VOID_TYPE, new Parameter[] { new Parameter(type, name) }, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
node.setDeclaringClass(property.getDeclaringClass());
return Collections.singletonList(node);
}
}
}
}
}
if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
// lookup in DGM methods too
findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), receiver, name, args, methods);
}
methods = filterMethodsByVisibility(methods, typeCheckingContext.getEnclosingClassNode());
List<MethodNode> chosen = chooseBestMethod(receiver, methods, args);
if (!chosen.isEmpty())
return chosen;
// GROOVY-5566
if (receiver instanceof InnerClassNode && ((InnerClassNode) receiver).isAnonymous() && methods.size() == 1 && args != null && "<init>".equals(name)) {
MethodNode constructor = methods.get(0);
if (constructor.getParameters().length == args.length) {
return methods;
}
}
if (isClassClassNodeWrappingConcreteType(receiver)) {
// GROOVY-6802, GROOVY-6803
List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args);
if (!result.isEmpty())
return result;
}
if (isGStringType(receiver)) {
return findMethod(STRING_TYPE, name, args);
}
if (isBeingCompiled(receiver)) {
return findMethod(GROOVY_OBJECT_TYPE, name, args);
}
return EMPTY_METHODNODE_LIST;
}
Aggregations