Java tutorial
/* This file is part of Green. * * Copyright (C) 2005 The Research Foundation of State University of New York * All Rights Under Copyright Reserved, The Research Foundation of S.U.N.Y. * * Green is free software, licensed under the terms of the Eclipse * Public License, version 1.0. The license is available at * http://www.eclipse.org/legal/epl-v10.html */ package edu.buffalo.cse.green.relationships; import static org.eclipse.jdt.core.IJavaElement.FIELD; import static org.eclipse.jdt.core.IJavaElement.LOCAL_VARIABLE; import static org.eclipse.jdt.core.dom.Modifier.STATIC; import java.util.AbstractList; import java.util.ArrayList; import java.util.List; import java.util.Stack; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTMatcher; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.EnumDeclaration; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.Initializer; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.ui.actions.OrganizeImportsAction; import edu.buffalo.cse.green.editor.DiagramEditor; /** * A parent for generators/recognizer/removers. * * The functionality of this class is as follows: * -It must allow subclasses visit only appropriate nodes. For example, nodes * that represent type declarations and methods. * -It must keep an up-to-the-minute listing of accessible fields and methods * for the purposes of preventing duplicate field/method names in code * generation and removing pieces of code, as well as helping the * relationship recognizers extract pieces of code that uniquely identify a * relationship's constituents. * * @author bcmartin * @author dk29 */ public abstract class RelationshipVisitor extends ASTVisitor { private ASTMatcher _matcher = new ASTMatcher(); private MethodDeclaration _methodDeclaration; private AST _ast; private CompilationUnit _cu; // private boolean _inConstructor = false; private List<String> _locals; private List<String> _parameters; private List<ILocalVariable> _parameterVars; private Stack<DeclarationInfoProvider> _typeStack; /** * @param element - The member element. * @return A <code>CompilationUnit</code> representing the structure of the * source code of the element. */ public static CompilationUnit getCompilationUnit(IMember element) { ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setResolveBindings(true); if (element.isBinary()) { parser.setSource((IClassFile) element.getAncestor(IJavaElement.CLASS_FILE)); } else { parser.setSource((ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT)); } return (CompilationUnit) parser.createAST(null); } protected RelationshipVisitor() { _typeStack = new Stack<DeclarationInfoProvider>(); _locals = new ArrayList<String>(); _parameters = new ArrayList<String>(); _parameterVars = new ArrayList<ILocalVariable>(); } /** * Runs the visitor on the given <code>CompilationUnit</code>. * * @param cu - The compilation unit. */ public void accept(CompilationUnit cu) { _ast = cu.getAST(); _cu = cu; preVisit(); run(cu, null); } /** * This method is called before visiting occurs to allow a visitor to * collect any information necessary to perform the desired behavior. */ protected void preVisit() { } /** * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.MethodDeclaration) */ public final void endVisit(MethodDeclaration node) { _methodDeclaration = null; _parameters.clear(); _parameterVars.clear(); // _inConstructor = false; // why is this needed? } /** * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.TypeDeclaration) */ public final void endVisit(EnumDeclaration node) { endVisit((TypeDeclaration) null); } /** * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.TypeDeclaration) */ public /*final*/ void endVisit(TypeDeclaration node) { _typeStack.pop(); } public /*final*/ void endVisit(AnonymousClassDeclaration node) { _typeStack.pop(); } /** * @return The AST for the compilation unit. */ protected AST getAST() { return _ast; } /** * @return The compilation unit. */ protected CompilationUnit getCompilationUnit() { return _cu; } /** * @param element - The element. * @return The <code>CompilationUnit</code> representing the given element. */ public CompilationUnit getCompilationUnit(IClassFile element) { ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setResolveBindings(true); parser.setSource(element); return (CompilationUnit) parser.createAST(null); } /** * @param element - The element. * @return The <code>CompilationUnit</code> representing the given element. */ public CompilationUnit getCompilationUnit(ICompilationUnit element) { ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setResolveBindings(true); parser.setSource(element); return (CompilationUnit) parser.createAST(null); } /** * @param element - The element. * @return The <code>CompilationUnit</code> representing the given element. */ public CompilationUnit getCompilationUnit(IType element) { if (element.isBinary()) { return getCompilationUnit((IClassFile) element.getAncestor(IJavaElement.CLASS_FILE)); } else { return getCompilationUnit((ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT)); } } /** * @param provider - The type information provider. * @return the Java element representing the given type. */ public IType getType(DeclarationInfoProvider provider) { return getType(provider.resolveBinding()); } /** * @param type - The given <code>Type</code>. * @return The <code>IType</code> bound to the given type. */ public IType getType(Type type) { return getType(type.resolveBinding()); } /** * @param binding - The given <code>ITypeBinding</code>. * @return The <code>IType</code> bound to the given type. */ public IType getType(ITypeBinding binding) { return (IType) binding.getJavaElement(); } /** * Handles visiting the given node in subclasses. * * @param node - The node. * @return True if further processing should occur, false otherwise. */ protected abstract boolean process(DeclarationInfoProvider node); /** * Called to run the visitor. * * @param cu - The compilation unit to visit. * @param cache - The cache of relationships. */ protected abstract void run(CompilationUnit cu, RelationshipCache cache); /** * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration) * * @author Gene Wang */ @Override public /*final*/ boolean visit(MethodDeclaration node) { // System.out.println("visiting MethodDeclaration node"); //Ignore all static children if ((node.getModifiers() & STATIC) != 0) return false; // _inConstructor = node.isConstructor(); _methodDeclaration = node; // retrieve the simple names of local variables and the elements they // represent for (SingleVariableDeclaration varDec : (AbstractList<SingleVariableDeclaration>) node.parameters()) { SimpleName parameter = varDec.getName(); _parameters.add(parameter.getIdentifier()); _parameterVars.add((ILocalVariable) parameter.resolveBinding().getJavaElement()); } return true; } /** * Ensures no recognizers attempt to use initializer blocks for relationships * * @author Gene Wang */ public boolean visit(Initializer node) { System.out.println("visiting Initializer node"); return false; } /** * Ensures no recognizers attempt to use static fields for relationships * * @author Gene Wang */ public boolean visit(SingleVariableDeclaration svd) { // System.out.println("visiting SingleVariableDeclaration node"); if (isField(svd.getName()) && (svd.getModifiers() & STATIC) != 0) return false; return true; } public final boolean visit(AnonymousClassDeclaration node) { System.out.println("visiting AnonymousClassDeclaration node"); return visit(DeclarationInfoProvider.getInfoProvider(node)); } /** * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration) */ public final boolean visit(EnumDeclaration node) { System.out.println("visiting EnumDeclaration node"); return visit(DeclarationInfoProvider.getInfoProvider(node)); } /** * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration) */ public final boolean visit(TypeDeclaration node) { System.out.println("visiting TypeDeclaration (class/interface) node"); return visit(DeclarationInfoProvider.getInfoProvider(node)); } /** * Processes type info as an <code>AbstractTypeDeclaration</code> node is * visited. This is necessary to get around the problem caused by enums * having a different node from classes and interfaces. * * @param node - The <code>DeclarationInfoProvider</code> being visited. * @return <code>true</code> if the children of this node should be visited, * and <code>false</code> if the children of this node should be skipped. */ public final boolean visit(DeclarationInfoProvider node) { _typeStack.push(node); System.out.println("visiting DeclarationInfoProvider node"); return process(node); } /** * @param var - The <code>ILocalVariable</code> to check * @return True if the name is bound to a local variable, false otherwise */ private boolean isLocalVariable(ILocalVariable var) { return !isParameter(var); } /** * @param var - The <code>ILocalVariable</code> to check * @return True if the name is bound to a parameter, false otherwise */ private boolean isParameter(ILocalVariable var) { for (ILocalVariable param : _parameterVars) { if (param.equals(var)) { return true; } } return false; } /** * @param name - The <code>Name</code> to check * @return True if the name is bound to a field, false otherwise */ protected boolean isField(Name name) { IBinding binding = name.resolveBinding(); if (binding == null) return false; IJavaElement ije = binding.getJavaElement(); // System.out.println("binding is "+binding); // System.out.println("ije is "+ije); int type = ije.getElementType(); return type == FIELD; } /** * @param name - The <code>Name</code> to check * @return True if the name is bound to a parameter, false otherwise */ protected boolean isParameter(Name name) { IBinding binding = name.resolveBinding(); if (binding == null) return false; IJavaElement element = binding.getJavaElement(); if (!(element.getElementType() == LOCAL_VARIABLE)) return false; return isParameter((ILocalVariable) element); } /** * @param name - The <code>Name</code> to check * @return True if the name is bound to a local variable, false otherwise */ protected boolean isLocalVariable(Name name) { IBinding binding = name.resolveBinding(); if (binding == null) return false; IJavaElement element = binding.getJavaElement(); if (element == null) return false; if (!(element.getElementType() == LOCAL_VARIABLE)) return false; return isLocalVariable((ILocalVariable) element); } /** * @param name - The name of the field * @return True if the field is already declared, false otherwise */ protected boolean isFieldDeclared(String name) { return getFieldNames().contains(name); } /** * Performs import organization on the given <code>ICompilationUnit</code>. * * @param cu - The <code>ICompilationUnit</code>. */ protected void organizeImports(ICompilationUnit cu) { new OrganizeImportsAction(DiagramEditor.getActiveEditor().getSite()) .runOnMultiple(new ICompilationUnit[] { cu }); } /** * Performs import organization on the given <code>IType</code>'s * compilation unit. * * @param type - The <code>IType</code>. */ protected void organizeImports(IType type) { organizeImports(type.getCompilationUnit()); } public static MethodDeclaration containingMethod(ASTNode node) { if (node.getClass().equals(MethodDeclaration.class)) { return (MethodDeclaration) node; } return containingMethod(node.getParent()); } /** * @return The <code>IType</code> corresponding to the current type being * visited. */ protected IType getCurrentType() { ITypeBinding typeBinding = getCurrentTypeInfo().resolveBinding(); List<Type> types = getCurrentTypeInfo().getSuperInterfaceTypes(); String typeList = ""; if (types.isEmpty()) { return (IType) getCurrentTypeInfo().resolveBinding().getJavaElement(); } else { for (Type nextType : types) { if (nextType.resolveBinding().isInterface()) { typeList += " " + nextType.toString() + "(interface)"; System.out.println("Implements: " + typeList); } } } return (IType) typeBinding.getJavaElement(); } /** * @return A list of <code>String</code>s representing the names of * local variables in the scope of the current method. */ protected List<String> getLocalDeclarations() { return _locals; } /** * @return A list of <code>String</code>s representing the names of * parameters in the scope of the current method. */ protected List<String> getParameterDeclarations() { return _parameters; } /** * @return The <code>MethodDeclaration</code> of the method most recently * visited. */ protected MethodDeclaration getMethodDeclaration() { return _methodDeclaration; } /** * @return The shared AST subtree matcher instance. */ protected ASTMatcher getMatcher() { return _matcher; } /** * @return The type info of the currently visited type. */ protected DeclarationInfoProvider getCurrentTypeInfo() { return _typeStack.peek(); } /** * @return The body declarations of the currently visited type. */ protected List<BodyDeclaration> getBodyDeclarations() { return (AbstractList<BodyDeclaration>) getCurrentTypeInfo().bodyDeclarations(); } // /** // * @return The <code>AbstractTypeDeclaration</code> corresponding to the // * current type. // */ // protected AbstractTypeDeclaration getCurrentTypeDeclaration() { // return getCurrentTypeInfo().getDeclaration(); // } /** * @return A list of names of the fields in the compilation unit as String * objects. */ protected List<String> getFieldNames() { List<String> fieldNames = new ArrayList<String>(); for (DeclarationInfoProvider typeInfo : _typeStack) { fieldNames.addAll(DeclarationInfoProvider.getFieldNames(typeInfo.getFields())); } return fieldNames; } /** * @return A list of all the <code>FieldDeclaration</code> nodes in the * current type. */ protected List<FieldDeclaration> getFields() { return getCurrentTypeInfo().getFields(); } }