use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class TraitComposer method applyTrait.
private static void applyTrait(final ClassNode trait, final ClassNode cNode, final TraitHelpersTuple helpers) {
ClassNode helperClassNode = helpers.getHelper();
ClassNode fieldHelperClassNode = helpers.getFieldHelper();
Map<String, ClassNode> genericsSpec = GenericsUtils.createGenericsSpec(cNode);
genericsSpec = GenericsUtils.createGenericsSpec(trait, genericsSpec);
for (MethodNode methodNode : helperClassNode.getAllDeclaredMethods()) {
String name = methodNode.getName();
Parameter[] helperMethodParams = methodNode.getParameters();
boolean isAbstract = methodNode.isAbstract();
if (!isAbstract && helperMethodParams.length > 0 && ((methodNode.getModifiers() & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) && (!name.contains("$") || (methodNode.getModifiers() & Opcodes.ACC_SYNTHETIC) == 0)) {
ArgumentListExpression argList = new ArgumentListExpression();
argList.addExpression(new VariableExpression("this"));
Parameter[] origParams = new Parameter[helperMethodParams.length - 1];
Parameter[] params = new Parameter[helperMethodParams.length - 1];
System.arraycopy(methodNode.getParameters(), 1, params, 0, params.length);
Map<String, ClassNode> methodGenericsSpec = new LinkedHashMap<String, ClassNode>(genericsSpec);
MethodNode originalMethod = trait.getMethod(name, params);
// Original method may be null for the case of private or static methods
if (originalMethod != null) {
methodGenericsSpec = GenericsUtils.addMethodGenerics(originalMethod, methodGenericsSpec);
}
for (int i = 1; i < helperMethodParams.length; i++) {
Parameter parameter = helperMethodParams[i];
ClassNode originType = parameter.getOriginType();
ClassNode fixedType = correctToGenericsSpecRecurse(methodGenericsSpec, originType);
Parameter newParam = new Parameter(fixedType, "arg" + i);
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
GeneralUtils.copyAnnotatedNodeAnnotations(parameter, copied, notCopied);
newParam.addAnnotations(copied);
params[i - 1] = newParam;
origParams[i - 1] = parameter;
argList.addExpression(new VariableExpression(params[i - 1]));
}
createForwarderMethod(trait, cNode, methodNode, originalMethod, helperClassNode, methodGenericsSpec, helperMethodParams, origParams, params, argList);
}
}
cNode.addObjectInitializerStatements(new ExpressionStatement(new MethodCallExpression(new ClassExpression(helperClassNode), Traits.INIT_METHOD, new ArgumentListExpression(new VariableExpression("this")))));
MethodCallExpression staticInitCall = new MethodCallExpression(new ClassExpression(helperClassNode), Traits.STATIC_INIT_METHOD, new ArgumentListExpression(new ClassExpression(cNode)));
MethodNode staticInitMethod = new MethodNode(Traits.STATIC_INIT_METHOD, Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, ClassHelper.VOID_TYPE, new Parameter[] { new Parameter(ClassHelper.CLASS_Type, "clazz") }, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
staticInitMethod.setDeclaringClass(helperClassNode);
staticInitCall.setMethodTarget(staticInitMethod);
cNode.addStaticInitializerStatements(Collections.<Statement>singletonList(new ExpressionStatement(staticInitCall)), false);
if (fieldHelperClassNode != null && !cNode.declaresInterface(fieldHelperClassNode)) {
// we should implement the field helper interface too
cNode.addInterface(fieldHelperClassNode);
// implementation of methods
List<MethodNode> declaredMethods = new LinkedList<MethodNode>();
for (MethodNode declaredMethod : fieldHelperClassNode.getAllDeclaredMethods()) {
if (declaredMethod.getName().endsWith(Traits.DIRECT_GETTER_SUFFIX)) {
declaredMethods.add(0, declaredMethod);
} else {
declaredMethods.add(declaredMethod);
}
}
for (MethodNode methodNode : declaredMethods) {
String fieldName = methodNode.getName();
if (fieldName.endsWith(Traits.DIRECT_GETTER_SUFFIX) || fieldName.endsWith(Traits.DIRECT_SETTER_SUFFIX)) {
int suffixIdx = fieldName.lastIndexOf("$");
fieldName = fieldName.substring(0, suffixIdx);
String operation = methodNode.getName().substring(suffixIdx + 1);
boolean getter = "get".equals(operation);
ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, methodNode.getReturnType());
int fieldMods = 0;
int isStatic = 0;
boolean publicField = true;
FieldNode helperField = null;
fieldMods = 0;
isStatic = 0;
// look first for field with encoded modifier information
for (Integer mod : Traits.FIELD_PREFIXES) {
helperField = fieldHelperClassNode.getField(String.format("$0x%04x", mod) + fieldName);
if (helperField != null) {
if ((mod & Opcodes.ACC_STATIC) != 0)
isStatic = Opcodes.ACC_STATIC;
fieldMods = fieldMods | mod;
break;
}
}
if (helperField == null) {
// look for possible legacy fields (trait compiled pre 2.4.8)
helperField = fieldHelperClassNode.getField(Traits.FIELD_PREFIX + Traits.PUBLIC_FIELD_PREFIX + fieldName);
if (helperField == null) {
publicField = false;
helperField = fieldHelperClassNode.getField(Traits.FIELD_PREFIX + Traits.PRIVATE_FIELD_PREFIX + fieldName);
}
if (helperField == null) {
publicField = true;
// try to find a static one
helperField = fieldHelperClassNode.getField(Traits.STATIC_FIELD_PREFIX + Traits.PUBLIC_FIELD_PREFIX + fieldName);
if (helperField == null) {
publicField = false;
helperField = fieldHelperClassNode.getField(Traits.STATIC_FIELD_PREFIX + Traits.PRIVATE_FIELD_PREFIX + fieldName);
}
fieldMods = fieldMods | Opcodes.ACC_STATIC;
isStatic = Opcodes.ACC_STATIC;
}
fieldMods = fieldMods | (publicField ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE);
}
if (getter) {
// add field
if (helperField != null) {
List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
GeneralUtils.copyAnnotatedNodeAnnotations(helperField, copied, notCopied);
FieldNode fieldNode = cNode.addField(fieldName, fieldMods, returnType, (fieldMods & Opcodes.ACC_FINAL) == 0 ? null : helperField.getInitialExpression());
fieldNode.addAnnotations(copied);
// so instead set within (static) initializer
if (fieldNode.isFinal() && !(helperClassNode instanceof InnerClassNode)) {
String baseName = fieldNode.isStatic() ? Traits.STATIC_INIT_METHOD : Traits.INIT_METHOD;
Expression mce = callX(helperClassNode, baseName + fieldNode.getName());
Statement stmt = stmt(assignX(varX(fieldNode.getName(), fieldNode.getType()), mce));
if (isStatic == 0) {
cNode.addObjectInitializerStatements(stmt);
} else {
cNode.addStaticInitializerStatements(Collections.<Statement>singletonList(stmt), false);
}
}
}
}
Parameter[] newParams;
if (getter) {
newParams = Parameter.EMPTY_ARRAY;
} else {
ClassNode originType = methodNode.getParameters()[0].getOriginType();
ClassNode fixedType = originType.isGenericsPlaceHolder() ? ClassHelper.OBJECT_TYPE : correctToGenericsSpecRecurse(genericsSpec, originType);
newParams = new Parameter[] { new Parameter(fixedType, "val") };
}
Expression fieldExpr = varX(cNode.getField(fieldName));
boolean finalSetter = !getter && (fieldMods & Opcodes.ACC_FINAL) != 0;
Statement body = getter ? returnS(fieldExpr) : (finalSetter ? null : stmt(new BinaryExpression(fieldExpr, Token.newSymbol(Types.EQUAL, 0, 0), varX(newParams[0]))));
// add getter/setter even though setter not strictly needed for final fields
// but add empty body for setter for legacy compatibility
MethodNode impl = new MethodNode(methodNode.getName(), Opcodes.ACC_PUBLIC | isStatic, returnType, newParams, ClassNode.EMPTY_ARRAY, body);
AnnotationNode an = new AnnotationNode(COMPILESTATIC_CLASSNODE);
impl.addAnnotation(an);
cNode.addTransform(StaticCompileTransformation.class, an);
cNode.addMethod(impl);
}
}
}
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class SortableASTTransformation method createComparatorFor.
private static void createComparatorFor(ClassNode classNode, PropertyNode property) {
String propName = property.getName();
String className = classNode.getName() + "$" + StringGroovyMethods.capitalize(propName) + "Comparator";
ClassNode superClass = makeClassSafeWithGenerics(AbstractComparator.class, classNode);
InnerClassNode cmpClass = new InnerClassNode(classNode, className, ACC_PRIVATE | ACC_STATIC, superClass);
classNode.getModule().addClass(cmpClass);
cmpClass.addMethod(new MethodNode("compare", ACC_PUBLIC, ClassHelper.int_TYPE, params(param(newClass(classNode), ARG0), param(newClass(classNode), ARG1)), ClassNode.EMPTY_ARRAY, createCompareMethodBody(property)));
String fieldName = "this$" + StringGroovyMethods.capitalize(propName) + "Comparator";
// private final Comparator this$<property>Comparator = new <type>$<property>Comparator();
FieldNode cmpField = classNode.addField(fieldName, ACC_STATIC | ACC_FINAL | ACC_PRIVATE | ACC_SYNTHETIC, COMPARATOR_TYPE, ctorX(cmpClass));
classNode.addMethod(new MethodNode("comparatorBy" + StringGroovyMethods.capitalize(propName), ACC_PUBLIC | ACC_STATIC, COMPARATOR_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, returnS(fieldX(cmpField))));
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovity by disney.
the class GroovityASTTransformation method visit.
public void visit(ASTNode[] nodes, final SourceUnit sourceUnit) {
ModuleNode mn = sourceUnit.getAST();
try {
if (mn != null) {
ClassNode scriptClassNode = mn.getScriptClassDummy();
LoadFieldVisitor loadFieldVisitor = new LoadFieldVisitor(sourceUnit);
loadFieldVisitor.visitClass(scriptClassNode);
if (mn.getStatementBlock().isEmpty()) {
// System.out.println("Adding dummy statement to force script");
mn.getStatementBlock().addStatement(new ExpressionStatement(new DeclarationExpression(new VariableExpression("___groovy__run__stub___"), Token.newSymbol(Types.EQUAL, 1, 1), new ConstantExpression(null))));
} else {
// check whether script body really does anything, if so add ScriptBody marker API
final AtomicBoolean runnable = new AtomicBoolean(false);
mn.getStatementBlock().visit(new CodeVisitorSupport() {
public void visitExpressionStatement(ExpressionStatement statement) {
Expression expression = statement.getExpression();
if (expression instanceof DeclarationExpression) {
List<AnnotationNode> fa = expression.getAnnotations();
for (AnnotationNode n : fa) {
if ("Field".equals(n.getClassNode().getName()) || Field.class.equals(n.getClassNode().getTypeClass())) {
// short-circuit and ignore the field declaration
return;
}
}
DeclarationExpression de = (DeclarationExpression) expression;
if ((de.getVariableExpression().getModifiers() & ACC_STATIC) != 0) {
// static declarations are implied fields
return;
}
}
runnable.set(true);
}
public void visitReturnStatement(ReturnStatement statement) {
runnable.set(true);
}
public void visitAssertStatement(AssertStatement statement) {
runnable.set(true);
}
});
if (runnable.get()) {
scriptClassNode.addInterface(new ClassNode(ScriptBody.class));
}
}
LoadFinder loadFinder = new LoadFinder(sourceUnit);
loadFinder.visitClass(scriptClassNode);
if (loadFinder.loadMethod != null) {
scriptClassNode.addInterface(new ClassNode(Loadable.class));
}
LineNumberVisitor lineNumberVisitor = null;
if (sourceLineNumbers != null) {
lineNumberVisitor = new LineNumberVisitor(sourceUnit);
}
boolean isLibrary = false;
ArgVisitor argVisitor = new ArgVisitor(sourceUnit);
InitDependencyVisitor initVisitor = new InitDependencyVisitor(sourceUnit);
TagFinder tagFinder = new TagFinder(sourceUnit);
TagCallFinder tagCallFinder = new TagCallFinder(sourceUnit, scriptClassNode, factory.getTaggables());
StaticBindingTransformer staticBindingTransformer = new StaticBindingTransformer(sourceUnit);
StaticFieldVisitor staticFieldVisitor = new StaticFieldVisitor(sourceUnit);
staticFieldVisitor.visitClass(scriptClassNode);
List<MethodNode> methods = mn.getMethods();
if (methods != null) {
for (MethodNode method : methods) {
boolean isFunction = false;
for (AnnotationNode annotation : method.getAnnotations()) {
if ("Function".equals(annotation.getClassNode().getName())) {
// If this script contains at least one Function declaration, mark it as a library
isFunction = true;
break;
}
}
if (isFunction) {
isLibrary = true;
break;
}
}
}
List<ClassNode> cnodes = mn.getClasses();
iterateClassNodes: for (final ClassNode cn : cnodes) {
// remap GSP line numbers so they match up with original source
if (lineNumberVisitor != null) {
lineNumberVisitor.visitClass(cn);
}
tagCallFinder.visitClass(cn);
// add arg annotations to methods to preserve parameter names
argVisitor.visitClass(cn);
if (cn.isInterface()) {
continue;
}
// Skip further processing for Traits as they don't handle static things well yet ...
if (cn.getAnnotations() != null) {
for (AnnotationNode anno : cn.getAnnotations()) {
if (anno.getClassNode().getName().equals("groovy.transform.Trait")) {
// System.out.println("SKIPPING TRAIT "+cn.getName());
continue iterateClassNodes;
}
}
}
staticBindingTransformer.visitClass(cn);
// add statistics gathering to methods and closures
initVisitor.visitClass(cn);
tagFinder.visitClass(cn);
final String internalClassName = BytecodeHelper.getClassInternalName(cn);
// add static missing property support to all classes
BytecodeExpression staticGetPropertyMissingExpression = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
// BytecodeHelper.visitClassLiteral(mv, cn);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), "staticPropertyMissing", BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode staticGetPropMethod = new MethodNode("$static_propertyMissing", ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, new ClassNode(Object.class), new Parameter[] { new Parameter(ClassHelper.make(String.class), "propertyName") }, new ClassNode[] {}, new BlockStatement(new Statement[] { new ReturnStatement(staticGetPropertyMissingExpression) }, new VariableScope()));
staticGetPropMethod.setSynthetic(true);
staticGetPropMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(staticGetPropMethod);
// add static missing method support to all classes
BytecodeExpression staticGetMethodMissingExpression = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
// BytecodeHelper.visitClassLiteral(mv, cn);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), "invokeMethod", BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class, Object.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode staticGetMissingMethod = new MethodNode("$static_methodMissing", ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, new ClassNode(Object.class), new Parameter[] { new Parameter(ClassHelper.make(String.class), "methodName"), new Parameter(ClassHelper.make(Object.class), "methodArgs") }, new ClassNode[] {}, new BlockStatement(new Statement[] { new ReturnStatement(staticGetMethodMissingExpression) }, new VariableScope()));
staticGetMissingMethod.setSynthetic(true);
staticGetMissingMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(staticGetMissingMethod);
if (!(cn instanceof InnerClassNode) || cn.isStaticClass()) {
FieldNode gsfNode = new FieldNode(GROOVITY_SCRIPT_HELPER_FIELD, ACC_PROTECTED | ACC_STATIC, new ClassNode(ScriptHelper.class), cn, ConstantExpression.NULL);
cn.addField(gsfNode);
// add missing method support to all classes
BytecodeExpression getMethodMissingExpression = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
// BytecodeHelper.visitClassLiteral(mv, cn);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), "invokeMethod", BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class, Object.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode getMissingMethod = new MethodNode("methodMissing", ACC_PUBLIC | ACC_SYNTHETIC, new ClassNode(Object.class), new Parameter[] { new Parameter(ClassHelper.make(String.class), "methodName"), new Parameter(ClassHelper.make(Object.class), "methodArgs") }, new ClassNode[] { new ClassNode(Exception.class) }, new BlockStatement(new Statement[] { new ReturnStatement(getMethodMissingExpression) }, new VariableScope()));
getMissingMethod.setSynthetic(true);
getMissingMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(getMissingMethod);
// add missing property lookup to top-level classes
BytecodeExpression instanceGetPropertyMissingExpression = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), "getProperty", BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode instanceGetMethod = new MethodNode("propertyMissing", ACC_PUBLIC | ACC_SYNTHETIC, new ClassNode(Object.class), new Parameter[] { new Parameter(ClassHelper.make(String.class), "propertyName") }, new ClassNode[] {}, new BlockStatement(new Statement[] { new ReturnStatement(instanceGetPropertyMissingExpression) }, new VariableScope()));
instanceGetMethod.setSynthetic(true);
instanceGetMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(instanceGetMethod);
BytecodeExpression instanceSetPropertyMissingExpression = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), "setProperty", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class), Type.getType(Object.class)), false);
mv.visitInsn(RETURN);
}
};
MethodNode setMethod = new MethodNode("propertyMissing", ACC_PUBLIC | ACC_SYNTHETIC, ClassHelper.VOID_TYPE, new Parameter[] { new Parameter(ClassHelper.make(String.class), "propertyName"), new Parameter(new ClassNode(Object.class), "newValue") }, new ClassNode[] {}, new BlockStatement(new Statement[] { new ExpressionStatement(instanceSetPropertyMissingExpression) }, new VariableScope()));
setMethod.setSynthetic(true);
setMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(setMethod);
if (cn != scriptClassNode) {
// add getBinding to other classes
BytecodeExpression getFactoryCall = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), "getBinding", BytecodeHelper.getMethodDescriptor(Binding.class, new Class[] {}), false);
mv.visitInsn(ARETURN);
}
};
MethodNode getMethod = new MethodNode("getBinding", ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, new ClassNode(Binding.class), new Parameter[] {}, new ClassNode[] {}, new BlockStatement(new Statement[] { new ReturnStatement(getFactoryCall) }, new VariableScope()));
getMethod.setSynthetic(true);
getMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(getMethod);
}
// add load, run and tag methods to all top level classes
BytecodeExpression loadFactoryCall = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), LOAD, BytecodeHelper.getMethodDescriptor(Script.class, new Class[] { String.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode loadMethod = new MethodNode(LOAD, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, new ClassNode(Script.class), new Parameter[] { new Parameter(new ClassNode(String.class), "path") }, new ClassNode[] { new ClassNode(InstantiationException.class), new ClassNode(IllegalAccessException.class), new ClassNode(ClassNotFoundException.class) }, new BlockStatement(new Statement[] { new ReturnStatement(loadFactoryCall) }, new VariableScope()));
loadMethod.setSynthetic(true);
loadMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(loadMethod);
BytecodeExpression runFactoryCall = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), RUN, BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode runMethod = new MethodNode(RUN, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, new Parameter[] { new Parameter(new ClassNode(String.class), "path") }, new ClassNode[] { new ClassNode(InstantiationException.class), new ClassNode(IllegalAccessException.class), new ClassNode(ClassNotFoundException.class), new ClassNode(IOException.class) }, new BlockStatement(new Statement[] { new ReturnStatement(runFactoryCall) }, new VariableScope()));
runMethod.setSynthetic(true);
runMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(runMethod);
BytecodeExpression doStreamCall = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), STREAM, Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Object.class)), false);
mv.visitInsn(RETURN);
}
};
MethodNode doStreamMethod = new MethodNode(STREAM, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.VOID_TYPE, new Parameter[] { new Parameter(ClassHelper.make(Object.class), "obj") }, new ClassNode[] {}, new BlockStatement(new Statement[] { new ExpressionStatement(doStreamCall) }, new VariableScope()));
doStreamMethod.setSynthetic(true);
doStreamMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(doStreamMethod);
BytecodeExpression doTagFullFactoryCall = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), TAG, BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class, Map.class, Closure.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode doTagFullMethod = new MethodNode(TAG, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, new Parameter[] { new Parameter(ClassHelper.make(String.class), "tagName"), new Parameter(new ClassNode(Map.class), "attributes"), new Parameter(new ClassNode(Closure.class), "body") }, new ClassNode[] { new ClassNode(Exception.class) }, new BlockStatement(new Statement[] { new ReturnStatement(doTagFullFactoryCall) }, new VariableScope()));
doTagFullMethod.setSynthetic(true);
doTagFullMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(doTagFullMethod);
BytecodeExpression doTagShortBodyFactoryCall = new BytecodeExpression() {
@Override
public void visit(MethodVisitor mv) {
mv.visitFieldInsn(GETSTATIC, internalClassName, GROOVITY_SCRIPT_HELPER_FIELD, BytecodeHelper.getTypeDescription(ScriptHelper.class));
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ScriptHelper.class), TAG, BytecodeHelper.getMethodDescriptor(Object.class, new Class[] { String.class, Closure.class }), false);
mv.visitInsn(ARETURN);
}
};
MethodNode doTagShortBodyMethod = new MethodNode(TAG, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, new Parameter[] { new Parameter(ClassHelper.make(String.class), "tagName"), new Parameter(new ClassNode(Closure.class), "body") }, new ClassNode[] { new ClassNode(Exception.class) }, new BlockStatement(new Statement[] { new ReturnStatement(doTagShortBodyFactoryCall) }, new VariableScope()));
doTagShortBodyMethod.setSynthetic(true);
doTagShortBodyMethod.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, true);
cn.addMethod(doTagShortBodyMethod);
}
}
// Record whether the class is a library with @Functions in a static final boolean.
final FieldNode isLibraryFieldNode = new FieldNode("isGroovyLibrary", ACC_PUBLIC | ACC_STATIC | ACC_FINAL, new ClassNode(Boolean.class), scriptClassNode, new ConstantExpression(isLibrary));
scriptClassNode.addField(isLibraryFieldNode);
ListExpression dependencyExpression = new ListExpression();
for (String dep : initDependencies) {
dependencyExpression.addExpression(new ConstantExpression(dep));
}
// Store pointers to all dependencies to help control load order
final FieldNode initDependenciesFieldNode = new FieldNode("initDependencies", ACC_PUBLIC | ACC_STATIC | ACC_FINAL, new ClassNode(new ArrayList<String>().getClass()), scriptClassNode, dependencyExpression);
scriptClassNode.addField(initDependenciesFieldNode);
}
} catch (Exception e) {
log.error("Error generating stats AST: ", e);
}
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
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";
holderClass.addField(innerFieldName, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, fieldType, initExpr);
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-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