use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class StaticCompilationVisitor method visitClass.
@Override
public void visitClass(final ClassNode node) {
boolean skip = shouldSkipClassNode(node);
if (!skip && !anyMethodSkip(node)) {
node.putNodeMetaData(MopWriter.Factory.class, StaticCompilationMopWriter.FACTORY);
}
ClassNode previousClassNode = classNode;
classNode = node;
classNode.getInnerClasses().forEachRemaining(innerClassNode -> {
boolean innerStaticCompile = !(skip || isSkippedInnerClass(innerClassNode));
innerClassNode.putNodeMetaData(STATIC_COMPILE_NODE, Boolean.valueOf(innerStaticCompile));
innerClassNode.putNodeMetaData(WriterControllerFactory.class, node.getNodeMetaData(WriterControllerFactory.class));
if (innerStaticCompile && !anyMethodSkip(innerClassNode)) {
innerClassNode.putNodeMetaData(MopWriter.Factory.class, StaticCompilationMopWriter.FACTORY);
}
});
super.visitClass(node);
addPrivateFieldAndMethodAccessors(node);
if (isStaticallyCompiled(node)) {
ClassNode outerClass = node.getOuterClass();
addDynamicOuterClassAccessorsCallback(outerClass);
}
classNode = previousClassNode;
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class StaticCompilationTransformer method visitClass.
@Override
public void visitClass(final ClassNode node) {
ClassNode prev = classNode;
classNode = node;
super.visitClass(node);
for (Iterator<InnerClassNode> innerClasses = classNode.getInnerClasses(); innerClasses.hasNext(); ) {
visitClass(innerClasses.next());
}
classNode = prev;
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class InitializerStrategy method createInnerHelperClass.
private static ClassNode createInnerHelperClass(ClassNode buildee, String builderClassName, int fieldsSize) {
final String fullName = buildee.getName() + "$" + builderClassName;
ClassNode builder = new InnerClassNode(buildee, fullName, ACC_PUBLIC | ACC_STATIC, OBJECT_TYPE);
GenericsType[] gtypes = new GenericsType[fieldsSize];
for (int i = 0; i < gtypes.length; i++) {
gtypes[i] = makePlaceholder(i);
}
builder.setGenericsTypes(gtypes);
return builder;
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class LazyASTTransformation method addHolderClassIdiomBody.
private static void addHolderClassIdiomBody(BlockStatement body, FieldNode fieldNode, Expression initExpr) {
final ClassNode declaringClass = fieldNode.getDeclaringClass();
final ClassNode fieldType = fieldNode.getType();
final int visibility = ACC_PRIVATE | ACC_STATIC;
final String fullName = declaringClass.getName() + "$" + fieldType.getNameWithoutPackage() + "Holder_" + fieldNode.getName().substring(1);
final InnerClassNode holderClass = new InnerClassNode(declaringClass, fullName, visibility, ClassHelper.OBJECT_TYPE);
final String innerFieldName = "INSTANCE";
// we have two options:
// (1) embed initExpr within holder class but redirect field access/method calls to declaring class members
// (2) keep initExpr within a declaring class method that is only called by the holder class
// currently we have gone with (2) for simplicity with only a slight memory footprint increase in the declaring class
final String initializeMethodName = (fullName + "_initExpr").replace('.', '_');
addGeneratedMethod(declaringClass, initializeMethodName, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, fieldType, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, returnS(initExpr));
holderClass.addField(innerFieldName, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, fieldType, callX(declaringClass, initializeMethodName));
final Expression innerField = propX(classX(holderClass), innerFieldName);
declaringClass.getModule().addClass(holderClass);
body.addStatement(returnS(innerField));
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class AstBuilder method visitClassDeclaration.
@Override
public ClassNode visitClassDeclaration(final ClassDeclarationContext ctx) {
String packageName = Optional.ofNullable(moduleNode.getPackageName()).orElse("");
String className = this.visitIdentifier(ctx.identifier());
if (VAR_STR.equals(className)) {
throw createParsingFailedException("var cannot be used for type declarations", ctx.identifier());
}
boolean isAnnotation = asBoolean(ctx.AT());
if (isAnnotation) {
if (asBoolean(ctx.typeParameters())) {
throw createParsingFailedException("annotation declaration cannot have type parameters", ctx.typeParameters());
}
if (asBoolean(ctx.EXTENDS())) {
throw createParsingFailedException("No extends clause allowed for annotation declaration", ctx.EXTENDS());
}
if (asBoolean(ctx.IMPLEMENTS())) {
throw createParsingFailedException("No implements clause allowed for annotation declaration", ctx.IMPLEMENTS());
}
}
boolean isEnum = asBoolean(ctx.ENUM());
if (isEnum) {
if (asBoolean(ctx.typeParameters())) {
throw createParsingFailedException("enum declaration cannot have type parameters", ctx.typeParameters());
}
if (asBoolean(ctx.EXTENDS())) {
throw createParsingFailedException("No extends clause allowed for enum declaration", ctx.EXTENDS());
}
}
boolean isInterface = (asBoolean(ctx.INTERFACE()) && !isAnnotation);
if (isInterface) {
if (asBoolean(ctx.IMPLEMENTS())) {
throw createParsingFailedException("No implements clause allowed for interface declaration", ctx.IMPLEMENTS());
}
}
List<ModifierNode> modifierNodeList = ctx.getNodeMetaData(TYPE_DECLARATION_MODIFIERS);
Objects.requireNonNull(modifierNodeList, "modifierNodeList should not be null");
ModifierManager modifierManager = new ModifierManager(this, modifierNodeList);
Optional<ModifierNode> finalModifierNodeOptional = modifierManager.get(FINAL);
Optional<ModifierNode> sealedModifierNodeOptional = modifierManager.get(SEALED);
Optional<ModifierNode> nonSealedModifierNodeOptional = modifierManager.get(NON_SEALED);
boolean isFinal = finalModifierNodeOptional.isPresent();
boolean isSealed = sealedModifierNodeOptional.isPresent();
boolean isNonSealed = nonSealedModifierNodeOptional.isPresent();
boolean isRecord = asBoolean(ctx.RECORD());
boolean hasRecordHeader = asBoolean(ctx.formalParameters());
if (isRecord) {
if (asBoolean(ctx.EXTENDS())) {
throw createParsingFailedException("No extends clause allowed for record declaration", ctx.EXTENDS());
}
if (!hasRecordHeader) {
throw createParsingFailedException("header declaration of record is expected", ctx.identifier());
}
if (isSealed) {
throw createParsingFailedException("`sealed` is not allowed for record declaration", sealedModifierNodeOptional.get());
}
if (isNonSealed) {
throw createParsingFailedException("`non-sealed` is not allowed for record declaration", nonSealedModifierNodeOptional.get());
}
} else {
if (hasRecordHeader) {
throw createParsingFailedException("header declaration is only allowed for record declaration", ctx.formalParameters());
}
}
if (isSealed && isNonSealed) {
throw createParsingFailedException("type cannot be defined with both `sealed` and `non-sealed`", nonSealedModifierNodeOptional.get());
}
if (isFinal && (isSealed || isNonSealed)) {
throw createParsingFailedException("type cannot be defined with both " + (isSealed ? "`sealed`" : "`non-sealed`") + " and `final`", finalModifierNodeOptional.get());
}
if ((isAnnotation || isEnum) && (isSealed || isNonSealed)) {
ModifierNode mn = isSealed ? sealedModifierNodeOptional.get() : nonSealedModifierNodeOptional.get();
throw createParsingFailedException("modifier `" + mn.getText() + "` is not allowed for " + (isEnum ? "enum" : "annotation definition"), mn);
}
boolean hasPermits = asBoolean(ctx.PERMITS());
if (!isSealed && hasPermits) {
throw createParsingFailedException("only sealed type declarations should have `permits` clause", ctx);
}
int modifiers = modifierManager.getClassModifiersOpValue();
boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
modifiers &= ~Opcodes.ACC_SYNTHETIC;
ClassNode classNode, outerClass = classNodeStack.peek();
if (isEnum) {
classNode = EnumHelper.makeEnumNode(asBoolean(outerClass) ? className : packageName + className, modifiers, null, outerClass);
} else if (asBoolean(outerClass)) {
if (outerClass.isInterface())
modifiers |= Opcodes.ACC_STATIC;
classNode = new InnerClassNode(outerClass, outerClass.getName() + "$" + className, modifiers, ClassHelper.OBJECT_TYPE.getPlainNodeReference());
} else {
classNode = new ClassNode(packageName + className, modifiers, ClassHelper.OBJECT_TYPE.getPlainNodeReference());
}
configureAST(classNode, ctx);
classNode.setSyntheticPublic(syntheticPublic);
classNode.setGenericsTypes(this.visitTypeParameters(ctx.typeParameters()));
boolean isInterfaceWithDefaultMethods = (isInterface && this.containsDefaultMethods(ctx));
if (isSealed) {
AnnotationNode sealedAnnotationNode = new AnnotationNode(ClassHelper.makeCached(Sealed.class));
if (asBoolean(ctx.ps)) {
ListExpression permittedSubclassesListExpression = listX(Arrays.stream(this.visitTypeList(ctx.ps)).map(ClassExpression::new).collect(Collectors.toList()));
sealedAnnotationNode.setMember("permittedSubclasses", permittedSubclassesListExpression);
configureAST(sealedAnnotationNode, ctx.PERMITS());
sealedAnnotationNode.setNodeMetaData("permits", true);
}
classNode.addAnnotation(sealedAnnotationNode);
} else if (isNonSealed) {
classNode.addAnnotation(new AnnotationNode(ClassHelper.makeCached(NonSealed.class)));
}
if (isInterfaceWithDefaultMethods || asBoolean(ctx.TRAIT())) {
classNode.addAnnotation(new AnnotationNode(ClassHelper.makeCached(Trait.class)));
}
if (isRecord) {
classNode.addAnnotation(new AnnotationNode(RECORD_TYPE_CLASS));
}
classNode.addAnnotations(modifierManager.getAnnotations());
if (isInterfaceWithDefaultMethods) {
classNode.putNodeMetaData(IS_INTERFACE_WITH_DEFAULT_METHODS, Boolean.TRUE);
}
classNode.putNodeMetaData(CLASS_NAME, className);
if (asBoolean(ctx.CLASS()) || asBoolean(ctx.TRAIT())) {
if (asBoolean(ctx.scs)) {
ClassNode[] scs = this.visitTypeList(ctx.scs);
if (scs.length > 1) {
throw createParsingFailedException("Cannot extend multiple classes", ctx.EXTENDS());
}
classNode.setSuperClass(scs[0]);
}
classNode.setInterfaces(this.visitTypeList(ctx.is));
this.initUsingGenerics(classNode);
} else if (isInterfaceWithDefaultMethods) {
// GROOVY-9259
classNode.setInterfaces(this.visitTypeList(ctx.scs));
this.initUsingGenerics(classNode);
} else if (isInterface) {
classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT);
classNode.setInterfaces(this.visitTypeList(ctx.scs));
this.initUsingGenerics(classNode);
this.hackMixins(classNode);
} else if (isEnum || isRecord) {
classNode.setInterfaces(this.visitTypeList(ctx.is));
this.initUsingGenerics(classNode);
if (isRecord) {
transformRecordHeaderToProperties(ctx, classNode);
}
} else if (isAnnotation) {
classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_ANNOTATION);
classNode.addInterface(ClassHelper.Annotation_TYPE);
this.hackMixins(classNode);
} else {
throw createParsingFailedException("Unsupported class declaration: " + ctx.getText(), ctx);
}
// have here to ensure it won't be the inner class
if (asBoolean(ctx.CLASS()) || asBoolean(ctx.TRAIT())) {
classNodeList.add(classNode);
}
classNodeStack.push(classNode);
ctx.classBody().putNodeMetaData(CLASS_DECLARATION_CLASS_NODE, classNode);
this.visitClassBody(ctx.classBody());
if (isRecord) {
Optional<FieldNode> fieldNodeOptional = classNode.getFields().stream().filter(f -> !isTrue(f, IS_RECORD_GENERATED) && !f.isStatic()).findFirst();
if (fieldNodeOptional.isPresent()) {
createParsingFailedException("Instance field is not allowed in `record`", fieldNodeOptional.get());
}
}
classNodeStack.pop();
if (!(asBoolean(ctx.CLASS()) || asBoolean(ctx.TRAIT()))) {
classNodeList.add(classNode);
}
groovydocManager.handle(classNode, ctx);
return classNode;
}
Aggregations