|
Groovy example source code file (InnerClassVisitor.java)
The Groovy InnerClassVisitor.java source code/* * Copyright 2003-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.groovy.classgen; import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.BinaryExpression; import org.codehaus.groovy.ast.expr.ConstructorCallExpression; import org.codehaus.groovy.ast.expr.Expression; import org.codehaus.groovy.ast.expr.FieldExpression; import org.codehaus.groovy.ast.expr.PropertyExpression; import org.codehaus.groovy.ast.expr.TupleExpression; import org.codehaus.groovy.ast.expr.VariableExpression; import org.codehaus.groovy.ast.stmt.BlockStatement; import org.codehaus.groovy.ast.stmt.ExpressionStatement; import org.codehaus.groovy.ast.stmt.Statement; import org.codehaus.groovy.control.CompilationUnit; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.syntax.Token; import org.codehaus.groovy.syntax.Types; import org.objectweb.asm.Opcodes; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcodes { private final SourceUnit sourceUnit; private ClassNode classNode; private static final int PUBLIC_SYNTHETIC = Opcodes.ACC_PUBLIC + Opcodes.ACC_SYNTHETIC; private FieldNode thisField = null; private MethodNode currentMethod; private FieldNode currentField; private boolean processingObjInitStatements = false; public InnerClassVisitor(CompilationUnit cu, SourceUnit su) { sourceUnit = su; } @Override protected SourceUnit getSourceUnit() { return sourceUnit; } @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(), null); } if (innerClass.getVariableScope() == null && innerClass.getDeclaredConstructors().isEmpty()) { // add dummy constructor innerClass.addConstructor(PUBLIC_SYNTHETIC, new Parameter[0], null, 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); } } @Override protected void visitObjectInitializerStatements(ClassNode node) { processingObjInitStatements = true; super.visitObjectInitializerStatements(node); processingObjInitStatements = false; } @Override public void visitConstructor(ConstructorNode node) { addThisReference(node); super.visitConstructor(node); } private boolean shouldHandleImplicitThisForInnerClass(ClassNode cn) { if (cn.isEnum() || cn.isInterface()) return false; if ((cn.getModifiers() & Opcodes.ACC_STATIC) != 0) return false; if (!(cn instanceof InnerClassNode)) return false; InnerClassNode innerClass = (InnerClassNode) cn; // scope != null means aic, we don't handle that here if (innerClass.getVariableScope() != null) return false; // static inner classes don't need this$0 if ((innerClass.getModifiers() & ACC_STATIC) != 0) return false; return true; } private void addThisReference(ConstructorNode node) { if (!shouldHandleImplicitThisForInnerClass(classNode)) return; Statement code = node.getCode(); // add "this$0" field init //add this parameter to node Parameter[] params = node.getParameters(); Parameter[] newParams = new Parameter[params.length + 1]; System.arraycopy(params, 0, newParams, 1, params.length); Parameter thisPara = new Parameter(classNode.getOuterClass(), getUniqueName(params, node)); newParams[0] = thisPara; node.setParameters(newParams); BlockStatement block = null; if (code == null) { block = new BlockStatement(); } else if (!(code instanceof BlockStatement)) { block = new BlockStatement(); block.addStatement(code); } else { block = (BlockStatement) code; } BlockStatement newCode = new BlockStatement(); addFieldInit(thisPara, thisField, newCode); ConstructorCallExpression cce = getFirstIfSpecialConstructorCall(block); if (cce == null) { cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression()); block.getStatements().add(0, new ExpressionStatement(cce)); } if (shouldImplicitlyPassThisPara(cce)) { // add thisPara to this(...) TupleExpression args = (TupleExpression) cce.getArguments(); List<Expression> expressions = args.getExpressions(); VariableExpression ve = new VariableExpression(thisPara.getName()); ve.setAccessedVariable(thisPara); expressions.add(0, ve); } if (cce.isSuperCall()) { // we have a call to super here, so we need to add // our code after that block.getStatements().add(1, newCode); } node.setCode(block); } private boolean shouldImplicitlyPassThisPara(ConstructorCallExpression cce) { boolean pass = false; ClassNode superCN = classNode.getSuperClass(); if (cce.isThisCall()) { pass = true; } else if (cce.isSuperCall()) { // if the super class is another non-static inner class in the same outer class, implicit this // needs to be passed if (!superCN.isEnum() && !superCN.isInterface() && superCN instanceof InnerClassNode) { InnerClassNode superInnerCN = (InnerClassNode) superCN; if (!isStatic(superInnerCN) && superCN.getOuterClass().equals(classNode.getOuterClass())) { pass = true; } } } return pass; } private String getUniqueName(Parameter[] params, ConstructorNode node) { String namePrefix = "$p"; outer: for (int i = 0; i < 100; i++) { namePrefix = namePrefix + "$"; for (Parameter p : params) { if (p.getName().equals(namePrefix)) continue outer; } return namePrefix; } addError("unable to find a unique prefix name for synthetic this reference", node); return namePrefix; } private ConstructorCallExpression getFirstIfSpecialConstructorCall(BlockStatement code) { if (code == null) return null; final List<Statement> statementList = code.getStatements(); if (statementList.isEmpty()) return null; final Statement statement = statementList.get(0); if (!(statement instanceof ExpressionStatement)) return null; Expression expression = ((ExpressionStatement) statement).getExpression(); if (!(expression instanceof ConstructorCallExpression)) return null; ConstructorCallExpression cce = (ConstructorCallExpression) expression; if (cce.isSpecialCall()) return cce; return null; } @Override protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) { this.currentMethod = node; super.visitConstructorOrMethod(node, isConstructor); this.currentMethod = null; } @Override public void visitField(FieldNode node) { this.currentField = node; super.visitField(node); this.currentField = null; } @Override public void visitProperty(PropertyNode node) { final FieldNode field = node.getField(); final Expression init = field.getInitialExpression(); field.setInitialValueExpression(null); super.visitProperty(node); field.setInitialValueExpression(init); } @Override public void visitConstructorCallExpression(ConstructorCallExpression call) { super.visitConstructorCallExpression(call); if (!call.isUsingAnonymousInnerClass()) { passThisReference(call); return; } InnerClassNode innerClass = (InnerClassNode) call.getType(); if (!innerClass.getDeclaredConstructors().isEmpty()) return; if ((innerClass.getModifiers() & ACC_STATIC) != 0) return; VariableScope scope = innerClass.getVariableScope(); if (scope == null) return; boolean isStatic = scope.isInStaticContext(); // expressions = constructor call arguments List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions(); // block = init code for the constructor we produce BlockStatement block = new BlockStatement(); // parameters = parameters of the constructor final int additionalParamCount = 1 + scope.getReferencedLocalVariablesCount(); List<Parameter> parameters = new ArrayList Other Groovy examples (source code examples)Here is a short list of links related to this Groovy InnerClassVisitor.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.