use of org.codehaus.groovy.ast.InnerClassNode in project groovy by apache.
the class StaticTypeCheckingVisitor method visitClass.
@Override
public void visitClass(final ClassNode node) {
if (shouldSkipClassNode(node))
return;
if (extension.beforeVisitClass(node)) {
extension.afterVisitClass(node);
return;
}
Object type = node.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
if (type != null) {
// transformation has already been run on this class node
// so we'll use a silent collector in order not to duplicate errors
typeCheckingContext.pushErrorCollector();
}
typeCheckingContext.pushEnclosingClassNode(node);
Set<MethodNode> oldVisitedMethod = typeCheckingContext.alreadyVisitedMethods;
typeCheckingContext.alreadyVisitedMethods = new LinkedHashSet<MethodNode>();
super.visitClass(node);
Iterator<InnerClassNode> innerClasses = node.getInnerClasses();
while (innerClasses.hasNext()) {
InnerClassNode innerClassNode = innerClasses.next();
visitClass(innerClassNode);
}
typeCheckingContext.alreadyVisitedMethods = oldVisitedMethod;
node.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, node);
// works in a two pass sequence and we don't want to skip the second pass
for (MethodNode methodNode : node.getMethods()) {
methodNode.putNodeMetaData(StaticTypeCheckingVisitor.class, Boolean.TRUE);
}
for (ConstructorNode constructorNode : node.getDeclaredConstructors()) {
constructorNode.putNodeMetaData(StaticTypeCheckingVisitor.class, Boolean.TRUE);
}
extension.afterVisitClass(node);
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
the class ClosureWriter method createClosureClass.
protected ClassNode createClosureClass(ClosureExpression expression, int mods) {
ClassNode classNode = controller.getClassNode();
ClassNode outerClass = controller.getOutermostClass();
MethodNode methodNode = controller.getMethodNode();
String name = classNode.getName() + "$" + // add a more informative name
controller.getContext().getNextClosureInnerName(outerClass, classNode, methodNode);
boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass();
Parameter[] parameters = expression.getParameters();
if (parameters == null) {
parameters = Parameter.EMPTY_ARRAY;
} else if (parameters.length == 0) {
// let's create a default 'it' parameter
Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
parameters = new Parameter[] { it };
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
if (ref != null)
it.setClosureSharedVariable(ref.isClosureSharedVariable());
}
Parameter[] localVariableParams = getClosureSharedVariables(expression);
removeInitialValues(localVariableParams);
InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
answer.setEnclosingMethod(controller.getMethodNode());
answer.setSynthetic(true);
answer.setUsingGenerics(outerClass.isUsingGenerics());
answer.setSourcePosition(expression);
if (staticMethodOrInStaticClass) {
answer.setStaticClass(true);
}
if (controller.isInScriptBody()) {
answer.setScriptBody(true);
}
MethodNode method = answer.addMethod("doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode());
method.setSourcePosition(expression);
VariableScope varScope = expression.getVariableScope();
if (varScope == null) {
throw new RuntimeException("Must have a VariableScope by now! for expression: " + expression + " class: " + name);
} else {
method.setVariableScope(varScope.copy());
}
if (parameters.length > 1 || (parameters.length == 1 && parameters[0].getType() != null && parameters[0].getType() != ClassHelper.OBJECT_TYPE && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType()))) {
// let's add a typesafe call method
MethodNode call = answer.addMethod("call", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, new ReturnStatement(new MethodCallExpression(VariableExpression.THIS_EXPRESSION, "doCall", new ArgumentListExpression(parameters))));
call.setSourcePosition(expression);
}
// let's make the constructor
BlockStatement block = new BlockStatement();
// this block does not get a source position, because we don't
// want this synthetic constructor to show up in corbertura reports
VariableExpression outer = new VariableExpression("_outerInstance");
outer.setSourcePosition(expression);
block.getVariableScope().putReferencedLocalVariable(outer);
VariableExpression thisObject = new VariableExpression("_thisObject");
thisObject.setSourcePosition(expression);
block.getVariableScope().putReferencedLocalVariable(thisObject);
TupleExpression conArgs = new TupleExpression(outer, thisObject);
block.addStatement(new ExpressionStatement(new ConstructorCallExpression(ClassNode.SUPER, conArgs)));
// let's assign all the parameter fields from the outer context
for (Parameter param : localVariableParams) {
String paramName = param.getName();
ClassNode type = param.getType();
if (true) {
VariableExpression initialValue = new VariableExpression(paramName);
initialValue.setAccessedVariable(param);
initialValue.setUseReferenceDirectly(true);
ClassNode realType = type;
type = ClassHelper.makeReference();
param.setType(ClassHelper.makeReference());
FieldNode paramField = answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue);
paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType()));
paramField.setHolder(true);
String methodName = Verifier.capitalize(paramName);
// let's add a getter & setter
Expression fieldExp = new FieldExpression(paramField);
answer.addMethod("get" + methodName, ACC_PUBLIC, realType.getPlainNodeReference(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new ReturnStatement(fieldExp));
}
}
Parameter[] params = new Parameter[2 + localVariableParams.length];
params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance");
params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject");
System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
sn.setSourcePosition(expression);
correctAccessedVariable(answer, expression);
return answer;
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
the class AsmClassGenerator method visitAttributeOrProperty.
private void visitAttributeOrProperty(PropertyExpression expression, MethodCallerMultiAdapter adapter) {
MethodVisitor mv = controller.getMethodVisitor();
Expression objectExpression = expression.getObjectExpression();
ClassNode classNode = controller.getClassNode();
if (isThisOrSuper(objectExpression)) {
// let's use the field expression if it's available
String name = expression.getPropertyAsString();
if (name != null) {
FieldNode field = null;
boolean privateSuperField = false;
if (isSuperExpression(objectExpression)) {
field = classNode.getSuperClass().getDeclaredField(name);
if (field != null && ((field.getModifiers() & ACC_PRIVATE) != 0)) {
privateSuperField = true;
}
} else {
if (controller.isNotExplicitThisInClosure(expression.isImplicitThis())) {
field = classNode.getDeclaredField(name);
if (field == null && classNode instanceof InnerClassNode) {
ClassNode outer = classNode.getOuterClass();
FieldNode outerClassField;
while (outer != null) {
outerClassField = outer.getDeclaredField(name);
if (outerClassField != null && outerClassField.isStatic() && outerClassField.isFinal()) {
if (outer != classNode.getOuterClass() && Modifier.isPrivate(outerClassField.getModifiers())) {
throw new GroovyBugError("Trying to access private constant field [" + outerClassField.getDeclaringClass() + "#" + outerClassField.getName() + "] from inner class");
}
PropertyExpression pexp = new PropertyExpression(new ClassExpression(outer), expression.getProperty());
pexp.visit(controller.getAcg());
return;
}
outer = outer.getSuperClass();
}
}
if (field == null && expression instanceof AttributeExpression && isThisExpression(objectExpression) && controller.isStaticContext()) {
// GROOVY-6183
ClassNode current = classNode.getSuperClass();
while (field == null && current != null) {
field = current.getDeclaredField(name);
current = current.getSuperClass();
}
if (field != null && (field.isProtected() || field.isPublic())) {
visitFieldExpression(new FieldExpression(field));
return;
}
}
}
}
if (field != null && !privateSuperField) {
//GROOVY-4497: don't visit super field if it is private
visitFieldExpression(new FieldExpression(field));
return;
}
}
if (isSuperExpression(objectExpression)) {
String prefix;
if (controller.getCompileStack().isLHS()) {
throw new GroovyBugError("Unexpected super property set for:" + expression.getText());
} else {
prefix = "get";
}
String propName = prefix + MetaClassHelper.capitalize(name);
visitMethodCallExpression(new MethodCallExpression(objectExpression, propName, MethodCallExpression.NO_ARGUMENTS));
return;
}
}
final String propName = expression.getPropertyAsString();
//TODO: add support for super here too
if (expression.getObjectExpression() instanceof ClassExpression && propName != null && propName.equals("this")) {
// we have something like A.B.this, and need to make it
// into this.this$0.this$0, where this.this$0 returns
// A.B and this.this$0.this$0 return A.
ClassNode type = objectExpression.getType();
ClassNode iterType = classNode;
if (controller.getCompileStack().isInSpecialConstructorCall() && classNode instanceof InnerClassNode) {
boolean staticInnerClass = classNode.isStaticClass();
// Outer.this in a special constructor call
if (classNode.getOuterClass().equals(type)) {
ConstructorNode ctor = controller.getConstructorNode();
Expression receiver = !staticInnerClass ? new VariableExpression(ctor.getParameters()[0]) : new ClassExpression(type);
receiver.setSourcePosition(expression);
receiver.visit(this);
return;
}
}
mv.visitVarInsn(ALOAD, 0);
while (!iterType.equals(type)) {
String ownerName = BytecodeHelper.getClassInternalName(iterType);
if (iterType.getOuterClass() == null)
break;
FieldNode thisField = iterType.getField("this$0");
if (thisField == null)
break;
ClassNode thisFieldType = thisField.getType();
iterType = iterType.getOuterClass();
if (ClassHelper.CLOSURE_TYPE.equals(thisFieldType)) {
mv.visitFieldInsn(GETFIELD, ownerName, "this$0", BytecodeHelper.getTypeDescription(ClassHelper.CLOSURE_TYPE));
mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ClassHelper.CLOSURE_TYPE), "getThisObject", "()Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(iterType));
} else {
String typeName = BytecodeHelper.getTypeDescription(iterType);
mv.visitFieldInsn(GETFIELD, ownerName, "this$0", typeName);
}
}
controller.getOperandStack().push(type);
return;
}
if (adapter == getProperty && !expression.isSpreadSafe() && propName != null) {
controller.getCallSiteWriter().makeGetPropertySite(objectExpression, propName, expression.isSafe(), expression.isImplicitThis());
} else if (adapter == getGroovyObjectProperty && !expression.isSpreadSafe() && propName != null) {
controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression, propName, expression.isSafe(), expression.isImplicitThis());
} else {
// todo: for improved modularity and extensibility, this should be moved into a writer
if (controller.getCompileStack().isLHS())
controller.getOperandStack().box();
controller.getInvocationWriter().makeCall(expression, // receiver
objectExpression, // messageName
new CastExpression(ClassHelper.STRING_TYPE, expression.getProperty()), MethodCallExpression.NO_ARGUMENTS, adapter, expression.isSafe(), expression.isSpreadSafe(), expression.isImplicitThis());
}
}
use of org.codehaus.groovy.ast.InnerClassNode in project groovy-core by groovy.
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;
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-core by groovy.
the class AsmClassGenerator method visitStdMethod.
private void visitStdMethod(MethodNode node, boolean isConstructor, Parameter[] parameters, Statement code) {
MethodVisitor mv = controller.getMethodVisitor();
final ClassNode superClass = controller.getClassNode().getSuperClass();
if (isConstructor && (code == null || !((ConstructorNode) node).firstStatementIsSpecialConstructorCall())) {
boolean hasCallToSuper = false;
if (code != null && controller.getClassNode() instanceof InnerClassNode) {
// so we must ensure not to add it twice (see GROOVY-4471)
if (code instanceof BlockStatement) {
for (Statement statement : ((BlockStatement) code).getStatements()) {
if (statement instanceof ExpressionStatement) {
final Expression expression = ((ExpressionStatement) statement).getExpression();
if (expression instanceof ConstructorCallExpression) {
ConstructorCallExpression call = (ConstructorCallExpression) expression;
if (call.isSuperCall()) {
hasCallToSuper = true;
break;
}
}
}
}
}
}
if (!hasCallToSuper) {
// invokes the super class constructor
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superClass), "<init>", "()V", false);
}
}
controller.getCompileStack().init(node.getVariableScope(), parameters);
controller.getCallSiteWriter().makeSiteEntry();
// handle body
super.visitConstructorOrMethod(node, isConstructor);
controller.getCompileStack().clear();
if (node.isVoidMethod()) {
mv.visitInsn(RETURN);
} else {
// we make a dummy return for label ranges that reach here
ClassNode type = node.getReturnType().redirect();
if (ClassHelper.isPrimitiveType(type)) {
mv.visitLdcInsn(0);
controller.getOperandStack().push(ClassHelper.int_TYPE);
controller.getOperandStack().doGroovyCast(type);
BytecodeHelper.doReturn(mv, type);
controller.getOperandStack().remove(1);
} else {
mv.visitInsn(ACONST_NULL);
BytecodeHelper.doReturn(mv, type);
}
}
}
Aggregations