code: /**
   * Copyright (C) . - All Rights Reserved.
   * Unauthorized copying of this file via any medium is
   * strictly prohibited Proprietary and Confidential.
   * Written by .
   */
  
  package pda.core.trace.inst.visitor;
  
  import org.eclipse.jdt.core.dom.*;
  import pda.common.conf.Constant;
  import pda.common.utils.Identifier;
  import pda.common.utils.LevelLogger;
  
  import java.util.List;
  import java.util.Set;
  
  /**
   * Traverse a {@code CompilationUnit}
   * 
   * @author
   *
   */
  public abstract class TraversalVisitor extends ASTVisitor {
  
  	private final String __name__ = "@TraversalVisitor ";
  
  	protected CompilationUnit _cu;
  	protected Set<Integer> _methods;
  	protected String _clazzName;
  	protected String _methodFlag = Constant.INSTRUMENT_K_SOURCE;
  
  	public void setFlag(String methodFlag) {
  		_methodFlag = methodFlag;
  	}
  
  	public void setMethod(Set<Integer> methods) {
  		_methods = methods;
  	}
  
  	public final boolean traverse(CompilationUnit compilationUnit) {
  		compilationUnit.accept(this);
  		return true;
  	}
  
  	public void reset() {
  		_methodFlag = Constant.INSTRUMENT_K_SOURCE;
  		_methods = null;
  		_clazzName = "";
  		_cu = null;
  	}
  
  	@Override
  	public boolean visit(CompilationUnit node) {
  		_cu = node;
  		// // jdt bug : when parse package with reserved keywords
  		// if(node.getPackage() == null) {
  		// AST ast = AST.newAST(Constant.AST_LEVEL);
  		// PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
  		// // for lang project
  		// packageDeclaration.setName(ast.newName("org.apache.commons.lang.enum"));
  		// node.setPackage((PackageDeclaration) ASTNode.copySubtree(node.getAST(),
  		// packageDeclaration));
  		// }
  		if (node.getPackage().getName() != null
  				&& node.getPackage().getName().getFullyQualifiedName().equals("auxiliary")) {
  			return false;
  		}
  		// filter unrelative files
  		if (_methods != null) {
  			boolean continueVisit = false;
  			for (Integer method : _methods) {
  				String methodInfo = Identifier.getMessage(method);
  				if (methodInfo.contains(_cu.getPackage().getName().getFullyQualifiedName())) {
  					continueVisit = true;
  					break;
  				}
  			}
  			if (!continueVisit) {
  				return false;
  			}
  		}
  		_clazzName = null;
  		String packageName = node.getPackage().getName().getFullyQualifiedName();
  		List<Object> types = node.types();
  		if (types.size() == 1) {
  			if (types.get(0) instanceof TypeDeclaration) {
  				TypeDeclaration typeDeclaration = (TypeDeclaration) types.get(0);
  				_clazzName = packageName + Constant.INSTRUMENT_DOT_SEPARATOR
  						+ typeDeclaration.getName().getFullyQualifiedName();
  			}
  		} else {
  			for (Object object : node.types()) {
  				if (object instanceof TypeDeclaration) {
  					TypeDeclaration type = (TypeDeclaration) object;
  					if (Modifier.isPublic(type.getModifiers())) {
  						_clazzName = packageName + Constant.INSTRUMENT_DOT_SEPARATOR
  								+ type.getName().getFullyQualifiedName();
  					}
  				}
  			}
  		}
  		if (_clazzName == null) {
  			// LevelLogger.warn(__name__ + "#visit(CompilationUnit) no public
  			// type declaration exists.");
  			return false;
  		}
  		return true;
  	}
  
  	/**
  	 * judging the current {@code MethodDeclaration} whether should be skipped
  	 * or not. return {@code true} when : 1. if the current method is not
  	 * contained by the given methods (if have). 2. it is not a concrete test
  	 * method in test classes, e.g., {@code setUp}. otherwise, return false;
  	 * 
  	 * @param node
  	 *                 : {@code MethodDeclaration}
  	 * @param methodID
  	 *                 : method id of the {@code MethodDeclaration}
  	 * @return
  	 */
  	protected boolean shouldSkip(MethodDeclaration node, int methodID) {
  
  		if (_methods != null) {
  			if (!_methods.contains(methodID)) {
  				return true;
  			}
  		}
  
  		String name = node.getName().getFullyQualifiedName();
  		// if(Modifier.isStatic(node.getModifiers())){
  		// return true;
  		// }
  
  		if (_methodFlag.equals(Constant.INSTRUMENT_K_TEST) && (name.equals("setUp") || name.equals("countTestCases")
  				|| name.equals("createResult") || name.equals("run") || name.equals("runBare") || name.equals("runTest")
  				|| name.equals("tearDown") || name.equals("toString") || name.equals("getName")
  				|| name.equals("setName"))) {
  			return true;
  		}
  
  		// filter those functional methods in test class path, test method name
  		// starting with "test" in Junit 3 while with annotation as "@Test" in
  		// Junit 4,
  		// TODO should be optimized since the "contain" method is time consuming
  		if (_methodFlag.equals(Constant.INSTRUMENT_K_TEST) && !name.startsWith("test")
  				&& !node.toString().contains("@Test")) {
  			return true;
  		}
  
  		return false;
  	}
  
  	/**
  	 * build full class information based on the given method declaration
  	 * 
  	 * @param node
  	 *             : {@code MethodDeclaration}
  	 * @return full class name for the method declaration, e.g.,
  	 *         "package.Clazz$InnerClazz"
  	 */
  	private String getFullClazzName(MethodDeclaration node) {
  		// filter those methods that defined in anonymous classes
  		ASTNode parent = node.getParent();
  		while (parent != null && !(parent instanceof TypeDeclaration) && !(parent instanceof EnumDeclaration)) {
  			if (parent instanceof ClassInstanceCreation) {
  				return null;
  			}
  			parent = parent.getParent();
  		}
  		String currentClassName = _clazzName;
  		if (parent != null && parent instanceof TypeDeclaration) {
  			TypeDeclaration typeDeclaration = (TypeDeclaration) parent;
  			String parentName = typeDeclaration.getName().getFullyQualifiedName();
  			if (!_clazzName.endsWith(parentName)) {
  				currentClassName = _clazzName + "$" + parentName;
  			}
  		} else if (parent != null && parent instanceof EnumDeclaration) {
  			EnumDeclaration enumDeclaration = (EnumDeclaration) parent;
  			String enumName = enumDeclaration.getName().getFullyQualifiedName();
  			if (!_clazzName.endsWith(enumName)) {
  				currentClassName = _clazzName + "$" + enumName;
  			}
  		}
  		return currentClassName;
  	}
  
  	/**
  	 * build string representation for the given method declaration
  	 * 
  	 * @param node
  	 *             : {@code MethodDeclaration}
  	 * @return a string represent the method
  	 */
  	protected String buildMethodInfoString(MethodDeclaration node) {
  		String currentClassName = getFullClazzName(node);
  		if (currentClassName == null) {
  			return null;
  		}
  		StringBuffer buffer = new StringBuffer(currentClassName + "#");
  
  		String retType = "?";
  		if (node.getReturnType2() != null) {
  			retType = node.getReturnType2().toString();
  		}
  		StringBuffer param = new StringBuffer("?");
  		for (Object object : node.parameters()) {
  			if (!(object instanceof SingleVariableDeclaration)) {
  				LevelLogger
  						.error(__name__ + "#visit Parameter is not a SingleVariableDeclaration : " + object.toString());
  				param.append(",?");
  			} else {
  				SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) object;
  				param.append("," + singleVariableDeclaration.getType().toString());
  			}
  		}
  		// add method return type
  		buffer.append(retType + "#");
  		// add method name
  		buffer.append(node.getName().getFullyQualifiedName() + "#");
  		// add method params, NOTE: the first parameter starts at index 1.
  		buffer.append(param);
  		return buffer.toString();
  	}
  }
  