use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
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.isEmpty()) {
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 AsmClassGenerator method makeInnerClassEntry.
private void makeInnerClassEntry(ClassNode cn) {
if (!(cn instanceof InnerClassNode))
return;
InnerClassNode innerClass = (InnerClassNode) cn;
String innerClassName = innerClass.getName();
String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
{
int index = innerClassName.lastIndexOf('$');
if (index >= 0)
innerClassName = innerClassName.substring(index + 1);
}
String outerClassName = BytecodeHelper.getClassInternalName(innerClass.getOuterClass().getName());
MethodNode enclosingMethod = innerClass.getEnclosingMethod();
if (enclosingMethod != null) {
// local inner classes do not specify the outer class name
outerClassName = null;
if (innerClass.isAnonymous())
innerClassName = null;
}
int mods = adjustedClassModifiersForInnerClassTable(cn);
if (Modifier.isPrivate(mods)) {
mods = mods ^ Modifier.PRIVATE;
innerClass.setModifiers(mods);
}
cv.visitInnerClass(innerClassInternalName, outerClassName, innerClassName, mods);
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class InnerClassCompletionVisitor method visitClass.
@Override
public void visitClass(ClassNode node) {
this.classNode = node;
thisField = null;
InnerClassNode innerClass = null;
if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
innerClass = (InnerClassNode) node;
thisField = innerClass.getField("this$0");
if (innerClass.getVariableScope() == null && innerClass.getDeclaredConstructors().isEmpty()) {
// add dummy constructor
innerClass.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, null, null);
}
}
if (node.isEnum() || node.isInterface())
return;
// use Iterator.hasNext() to check for available inner classes
if (node.getInnerClasses().hasNext())
addDispatcherMethods(node);
if (innerClass == null)
return;
super.visitClass(node);
addDefaultMethods(innerClass);
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class InnerClassVisitor method visitClass.
@Override
public void visitClass(ClassNode node) {
this.classNode = node;
thisField = null;
InnerClassNode innerClass = null;
if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
innerClass = (InnerClassNode) node;
if (!isStatic(innerClass) && innerClass.getVariableScope() == null) {
thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, node.getOuterClass().getPlainNodeReference(), null);
}
}
super.visitClass(node);
if (node.isEnum() || node.isInterface())
return;
if (innerClass == null)
return;
if (node.getSuperClass().isInterface()) {
node.addInterface(node.getUnresolvedSuperClass());
node.setUnresolvedSuperClass(ClassHelper.OBJECT_TYPE);
}
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class AntlrParserPlugin method innerClassDef.
protected void innerClassDef(AST classDef) {
List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
if (isType(TRAIT_DEF, classDef)) {
annotations.add(new AnnotationNode(ClassHelper.make("groovy.transform.Trait")));
}
AST node = classDef.getFirstChild();
int modifiers = Opcodes.ACC_PUBLIC;
if (isType(MODIFIERS, node)) {
modifiers = modifiers(node, annotations, modifiers);
checkNoInvalidModifier(classDef, "Class", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
node = node.getNextSibling();
}
String name = identifier(node);
node = node.getNextSibling();
GenericsType[] genericsType = null;
if (isType(TYPE_PARAMETERS, node)) {
genericsType = makeGenericsType(node);
node = node.getNextSibling();
}
ClassNode superClass = null;
if (isType(EXTENDS_CLAUSE, node)) {
superClass = makeTypeWithArguments(node);
node = node.getNextSibling();
}
ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
if (isType(IMPLEMENTS_CLAUSE, node)) {
interfaces = interfaces(node);
node = node.getNextSibling();
}
// TODO read mixins
MixinNode[] mixins = {};
ClassNode outerClass = classNode;
boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
modifiers &= ~Opcodes.ACC_SYNTHETIC;
if (classNode != null) {
name = classNode.getNameWithoutPackage() + "$" + name;
String fullName = dot(classNode.getPackageName(), name);
if (classNode.isInterface()) {
modifiers |= Opcodes.ACC_STATIC;
}
classNode = new InnerClassNode(classNode, fullName, modifiers, superClass, interfaces, mixins);
} else {
classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, mixins);
}
classNode.addAnnotations(annotations);
classNode.setGenericsTypes(genericsType);
classNode.setSyntheticPublic(syntheticPublic);
configureAST(classNode, classDef);
// we put the class already in output to avoid the most inner classes
// will be used as first class later in the loader. The first class
// there determines what GCL#parseClass for example will return, so we
// have here to ensure it won't be the inner class
output.addClass(classNode);
int oldClassCount = innerClassCounter;
assertNodeType(OBJBLOCK, node);
objectBlock(node);
classNode = outerClass;
innerClassCounter = oldClassCount;
}
Aggregations