/*
* Copyright (C) 2007, 2009 Martin Kempf, Reto Kleeb, Michael Klenk
*
* IFS Institute for Software, HSR Rapperswil, Switzerland
* http://ifs.hsr.ch/
*
* 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.eclipse.refactoring.core.utils.astScanner;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ConstructorNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.GenericsType;
import org.codehaus.groovy.ast.ImportNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.ast.PropertyNode;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import org.codehaus.groovy.ast.expr.ArrayExpression;
import org.codehaus.groovy.ast.expr.AttributeExpression;
import org.codehaus.groovy.ast.expr.BinaryExpression;
import org.codehaus.groovy.ast.expr.BitwiseNegationExpression;
import org.codehaus.groovy.ast.expr.BooleanExpression;
import org.codehaus.groovy.ast.expr.CastExpression;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ClosureExpression;
import org.codehaus.groovy.ast.expr.ClosureListExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
import org.codehaus.groovy.ast.expr.DeclarationExpression;
import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.FieldExpression;
import org.codehaus.groovy.ast.expr.GStringExpression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.MapEntryExpression;
import org.codehaus.groovy.ast.expr.MapExpression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.MethodPointerExpression;
import org.codehaus.groovy.ast.expr.NotExpression;
import org.codehaus.groovy.ast.expr.PostfixExpression;
import org.codehaus.groovy.ast.expr.PrefixExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.ast.expr.RangeExpression;
import org.codehaus.groovy.ast.expr.SpreadExpression;
import org.codehaus.groovy.ast.expr.SpreadMapExpression;
import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
import org.codehaus.groovy.ast.expr.TernaryExpression;
import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
import org.codehaus.groovy.ast.expr.UnaryPlusExpression;
import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.AssertStatement;
import org.codehaus.groovy.ast.stmt.BlockStatement;
import org.codehaus.groovy.ast.stmt.BreakStatement;
import org.codehaus.groovy.ast.stmt.CaseStatement;
import org.codehaus.groovy.ast.stmt.CatchStatement;
import org.codehaus.groovy.ast.stmt.ContinueStatement;
import org.codehaus.groovy.ast.stmt.DoWhileStatement;
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.ForStatement;
import org.codehaus.groovy.ast.stmt.IfStatement;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.ast.stmt.SwitchStatement;
import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
import org.codehaus.groovy.ast.stmt.ThrowStatement;
import org.codehaus.groovy.ast.stmt.TryCatchStatement;
import org.codehaus.groovy.ast.stmt.WhileStatement;
public abstract class RefactoringCodeVisitorSupport extends AbstractRefactoringCodeVisitor {
protected ModuleNode rootNode;
public RefactoringCodeVisitorSupport(ModuleNode rootNode) {
this.rootNode = rootNode;
}
@Override
public void visitClassImport(ClassImport classImport) {
}
protected void analyzeNode(ASTNode node) {
}
protected void clear(ASTNode node) {
}
@Override
public void visitStaticClassImport(StaticClassImport staticClassImport) {
}
@Override
public void visitStaticFieldImport(StaticFieldImport staticAliasImport) {
}
@Override
public void scanAST() {
analyseClassImports();
analyseStaticClassImport();
analyseStaticFieldImport();
if (!rootNode.getStatementBlock().isEmpty()) {
for (Statement statement : (Iterable<Statement>) rootNode.getStatementBlock().getStatements()) {
statement.visit(this);
}
}
List<ClassNode> classes = rootNode.getClasses();
for (ClassNode classNode : classes) {
if (!classNode.isScript()) {
visitClass(classNode);
} else {
List<MethodNode> methods = rootNode.getMethods();
for ( MethodNode method : methods) {
visitMethod(method);
}
}
}
}
private void analyseStaticFieldImport() {
//visit static imports like import java.lang.Math.cos
for (Entry<String, ImportNode> aliasOrField : rootNode.getStaticImports().entrySet()) {
StaticFieldImport staticAliasImport = new StaticFieldImport(aliasOrField.getValue().getType(), aliasOrField.getKey(),
aliasOrField.getValue().getFieldName());
staticAliasImport.setSourcePosition(aliasOrField.getValue());
visitStaticFieldImport(staticAliasImport);
}
}
private void analyseStaticClassImport() {
//visit static imports like import java.lang.Math.*
Collection<ImportNode> staticImportClasses = rootNode.getStaticImports().values();
for (ImportNode staticImp : staticImportClasses) {
ClassNode type = staticImp.getType();
StaticClassImport staticClassImport = new StaticClassImport(type);
staticClassImport.setSourcePosition(type);
visitStaticClassImport(staticClassImport);
}
}
private void analyseClassImports() {
//visit imports like import java.io.File and import java.io.File as MyFile
List<ImportNode> imports = rootNode.getImports();
for(ImportNode importNode : imports) {
ClassImport classImport = new ClassImport(importNode);
classImport.setSourcePosition(importNode.getType());
visitClassImport(classImport);
}
}
protected void analyzeNodes(ASTNode[] nodes) {
if (nodes != null) {
for(int i = 0; i < nodes.length; i++){
analyzeNode(nodes[i]);
clear(nodes[i]);
}
}
}
protected void analyzeTypes(ClassNode[] classNodes) {
if (classNodes != null) {
for(int i = 0; i < classNodes.length; i++){
if (classNodes[i] != null) {
analyzeType(classNodes[i]);
clear(classNodes[i]);
}
}
}
}
private void analyzeTypeInternal(ClassNode classNode) {
ClassNode node = classNode;
//visit all classNodes for arrays
while (node.isArray()) {
node = node.getComponentType();
}
analyzeNode(node);
analyzeGenerics(node);
}
@Override
public void analyzeType(ClassNode node) {
analyzeTypeInternal(node);
}
@Override
public void analyzeParameter(Parameter parameter) {
analyzeNode(parameter);
}
protected void analyzeGenerics(ClassNode node) {
if (node.getGenericsTypes() != null) {
GenericsType[] generics = node.getGenericsTypes();
for (int i = 0; i < generics.length; i++) {
GenericsType genericType = generics[i];
// bottoms out recursion when a type parameter refers to itself, eg- java.lang.Enum
if (! node.getName().equals(genericType.getType().getName())) {
analyzeType(genericType.getType());
clear(genericType.getType());
if (genericType.getLowerBound() != null) {
analyzeType(genericType.getLowerBound());
clear(genericType.getLowerBound());
}
if (genericType.getUpperBounds() != null) {
ClassNode[] upperBounds = genericType.getUpperBounds().clone();
// prevent recursion by nulling out duplicates
for (int j = 0; j < upperBounds.length; j++) {
if (upperBounds[i].getName().equals(node.getName())) {
upperBounds[i] = null;
}
}
analyzeTypes(upperBounds);
}
}
}
}
}
protected void analyseParameters(Parameter[] parameters) {
if(parameters != null) {
for(Parameter parameter : parameters) {
analyzeParameter(parameter);
analyzeType(parameter.getOriginType());
clear(parameter.getOriginType());
if (parameter.hasInitialExpression()) {
parameter.getInitialExpression().visit(this);
}
clear(parameter);
}
}
}
public void visitAnnotations(AnnotatedNode node) {
List<AnnotationNode> annotionMap = node.getAnnotations();
if (annotionMap.isEmpty()) return;
Iterator<AnnotationNode> it = annotionMap.iterator();
while (it.hasNext()) {
AnnotationNode an = it.next();
//skip builtin properties
if (an.isBuiltIn()) continue;
for (Entry<String, Expression> element : (Iterable<Entry<String, Expression>>) an.getMembers().entrySet()) {
element.getValue().visit(this);
}
}
}
public void visitClass(ClassNode node) {
analyzeTypeInternal(node);
analyzeType(node.getUnresolvedSuperClass());
clear(node.getUnresolvedSuperClass());
analyzeTypes(node.getInterfaces());
node.visitContents(this);
clear(node);
}
public void visitField(FieldNode node) {
analyzeNode(node);
analyzeType(node.getOriginType());
clear(node.getOriginType());
Expression initExp = node.getInitialValueExpression();
if (initExp != null) {
analyzeNode(initExp);
initExp.visit(this);
clear(initExp);
}
clear(node);
}
protected void visitClassCodeContainer(Statement code) {
if (code != null) code.visit(this);
}
protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
visitAnnotations(node);
analyseMethodHead(node);
Statement code = node.getCode();
visitClassCodeContainer(code);
}
public void visitConstructor(ConstructorNode node) {
analyzeNode(node);
visitConstructorOrMethod(node, true);
clear(node);
}
public void visitMethod(MethodNode node) {
analyzeNode(node);
visitConstructorOrMethod(node, false);
clear(node);
}
private void analyseMethodHead(MethodNode node) {
analyzeType(node.getReturnType());
clear(node.getReturnType());
analyseParameters(node.getParameters());
analyzeTypes(node.getExceptions());
}
public void visitProperty(PropertyNode node) {
}
@Override
public void visitVariableExpression(VariableExpression expression) {
analyzeNode(expression);
analyzeType(expression.getOriginType());
clear(expression.getOriginType());
super.visitVariableExpression(expression);
clear(expression);
}
@Override
public void visitClosureExpression(ClosureExpression expression) {
analyzeNode(expression);
analyseParameters(expression.getParameters());
super.visitClosureExpression(expression);
clear(expression);
}
@Override
public void visitArgumentlistExpression(ArgumentListExpression ale) {
analyzeNode(ale);
super.visitArgumentlistExpression(ale);
clear(ale);
}
@Override
public void visitArrayExpression(ArrayExpression expression) {
analyzeNode(expression);
analyzeType(expression.getElementType());
clear(expression.getElementType());
super.visitArrayExpression(expression);
clear(expression);
}
@Override
public void visitAssertStatement(AssertStatement statement) {
analyzeNode(statement);
super.visitAssertStatement(statement);
clear(statement);
}
@Override
public void visitAttributeExpression(AttributeExpression expression) {
analyzeNode(expression);
super.visitAttributeExpression(expression);
clear(expression);
}
@Override
public void visitBinaryExpression(BinaryExpression expression) {
analyzeNode(expression);
super.visitBinaryExpression(expression);
clear(expression);
}
@Override
public void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
analyzeNode(expression);
super.visitBitwiseNegationExpression(expression);
clear(expression);
}
@Override
public void visitBlockStatement(BlockStatement block) {
analyzeNode(block);
super.visitBlockStatement(block);
clear(block);
}
@Override
public void visitBooleanExpression(BooleanExpression expression) {
analyzeNode(expression);
super.visitBooleanExpression(expression);
clear(expression);
}
@Override
public void visitBreakStatement(BreakStatement statement) {
analyzeNode(statement);
super.visitBreakStatement(statement);
clear(statement);
}
// @Override
// public void visitBytecodeExpression(BytecodeExpression cle) {
// analyzeNode(cle);
// super.visitBytecodeExpression(cle);
// clear(cle);
// }
@Override
public void visitCaseStatement(CaseStatement statement) {
analyzeNode(statement);
super.visitCaseStatement(statement);
clear(statement);
}
@Override
public void visitCastExpression(CastExpression expression) {
analyzeNode(expression);
analyzeType(expression.getType());
clear(expression.getType());
super.visitCastExpression(expression);
clear(expression);
}
@Override
public void visitCatchStatement(CatchStatement statement) {
analyzeNode(statement);
analyzeType(statement.getExceptionType());
clear(statement.getExceptionType());
super.visitCatchStatement(statement);
clear(statement);
}
@Override
public void visitClassExpression(ClassExpression expression) {
analyzeNode(expression);
super.visitClassExpression(expression);
clear(expression);
}
@Override
public void visitClosureListExpression(ClosureListExpression cle) {
analyzeNode(cle);
super.visitClosureListExpression(cle);
clear(cle);
}
@Override
public void visitConstantExpression(ConstantExpression expression) {
analyzeNode(expression);
super.visitConstantExpression(expression);
clear(expression);
}
@Override
public void visitConstructorCallExpression(ConstructorCallExpression call) {
analyzeNode(call);
analyzeType(call.getType());
clear(call.getType());
super.visitConstructorCallExpression(call);
clear(call);
}
@Override
public void visitContinueStatement(ContinueStatement statement) {
analyzeNode(statement);
super.visitContinueStatement(statement);
clear(statement);
}
@Override
public void visitDeclarationExpression(DeclarationExpression expression) {
//Do not analyse, since it is analysed in visitBinaryExpression
//analyzeNode(expression);
super.visitDeclarationExpression(expression);
//clear(expression);
}
@Override
public void visitDoWhileLoop(DoWhileStatement loop) {
analyzeNode(loop);
super.visitDoWhileLoop(loop);
clear(loop);
}
@Override
public void visitExpressionStatement(ExpressionStatement statement) {
analyzeNode(statement);
super.visitExpressionStatement(statement);
clear(statement);
}
@Override
public void visitFieldExpression(FieldExpression expression) {
if (!expression.getType().getNameWithoutPackage().equals("MetaClass")) {
analyzeNode(expression);
super.visitFieldExpression(expression);
clear(expression);
}
}
@Override
public void visitForLoop(ForStatement forLoop) {
analyzeNode(forLoop);
super.visitForLoop(forLoop);
clear(forLoop);
}
@Override
public void visitGStringExpression(GStringExpression expression) {
analyzeNode(expression);
super.visitGStringExpression(expression);
clear(expression);
}
@Override
public void visitIfElse(IfStatement ifElse) {
analyzeNode(ifElse);
super.visitIfElse(ifElse);
clear(ifElse);
}
@Override
public void visitListExpression(ListExpression expression) {
analyzeNode(expression);
super.visitListExpression(expression);
clear(expression);
}
@Override
public void visitMapEntryExpression(MapEntryExpression expression) {
analyzeNode(expression);
super.visitMapEntryExpression(expression);
clear(expression);
}
@Override
public void visitMapExpression(MapExpression expression) {
analyzeNode(expression);
super.visitMapExpression(expression);
clear(expression);
}
@Override
public void visitMethodCallExpression(MethodCallExpression call) {
analyzeNode(call);
super.visitMethodCallExpression(call);
clear(call);
}
@Override
public void visitMethodPointerExpression(MethodPointerExpression expression) {
analyzeNode(expression);
super.visitMethodPointerExpression(expression);
clear(expression);
}
@Override
public void visitNotExpression(NotExpression expression) {
analyzeNode(expression);
super.visitNotExpression(expression);
clear(expression);
}
@Override
public void visitPostfixExpression(PostfixExpression expression) {
analyzeNode(expression);
super.visitPostfixExpression(expression);
clear(expression);
}
@Override
public void visitPrefixExpression(PrefixExpression expression) {
analyzeNode(expression);
super.visitPrefixExpression(expression);
clear(expression);
}
@Override
public void visitPropertyExpression(PropertyExpression expression) {
analyzeNode(expression);
super.visitPropertyExpression(expression);
clear(expression);
}
@Override
public void visitRangeExpression(RangeExpression expression) {
analyzeNode(expression);
super.visitRangeExpression(expression);
clear(expression);
}
@Override
public void visitReturnStatement(ReturnStatement statement) {
analyzeNode(statement);
super.visitReturnStatement(statement);
clear(statement);
}
@Override
public void visitShortTernaryExpression(ElvisOperatorExpression expression) {
analyzeNode(expression);
super.visitShortTernaryExpression(expression);
clear(expression);
}
@Override
public void visitSpreadExpression(SpreadExpression expression) {
analyzeNode(expression);
super.visitSpreadExpression(expression);
clear(expression);
}
@Override
public void visitSpreadMapExpression(SpreadMapExpression expression) {
analyzeNode(expression);
super.visitSpreadMapExpression(expression);
clear(expression);
}
@Override
public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
analyzeNode(call);
super.visitStaticMethodCallExpression(call);
clear(call);
}
@Override
public void visitSwitch(SwitchStatement statement) {
analyzeNode(statement);
super.visitSwitch(statement);
clear(statement);
}
@Override
public void visitSynchronizedStatement(SynchronizedStatement statement) {
analyzeNode(statement);
super.visitSynchronizedStatement(statement);
clear(statement);
}
@Override
public void visitTernaryExpression(TernaryExpression expression) {
analyzeNode(expression);
super.visitTernaryExpression(expression);
clear(expression);
}
@Override
public void visitThrowStatement(ThrowStatement statement) {
analyzeNode(statement);
super.visitThrowStatement(statement);
clear(statement);
}
@Override
public void visitTryCatchFinally(TryCatchStatement statement) {
analyzeNode(statement);
super.visitTryCatchFinally(statement);
clear(statement);
}
@Override
public void visitTupleExpression(TupleExpression expression) {
// do nothing here, TupleExpression is visited in ArgumentListExpression
// analyzeNode(expression);
super.visitTupleExpression(expression);
// clear(expression);
}
@Override
public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
analyzeNode(expression);
super.visitUnaryMinusExpression(expression);
clear(expression);
}
@Override
public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
analyzeNode(expression);
super.visitUnaryPlusExpression(expression);
clear(expression);
}
@Override
public void visitWhileLoop(WhileStatement loop) {
analyzeNode(loop);
super.visitWhileLoop(loop);
clear(loop);
}
}