package lapsePlus; /* * CallerFinder.java, version 2.8, 2010 */ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.ClassInstanceCreation; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.MethodInvocation; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.internal.core.JavaProject; import org.eclipse.jdt.internal.core.search.JavaSearchScope; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.ui.PlatformUI; public class CallerFinder { private static IJavaSearchScope fSearchScope; public static Collection/*<Util.ExprUn...>*/ findCallers(final String methodName, final JavaProject project, final boolean isConstructor) { class FindingOp implements IRunnableWithProgress { Collection c = null; public void run(IProgressMonitor monitor) { c = findCallers(monitor, methodName, project, isConstructor); if(c == null) { JavaPlugin.logErrorMessage("Collection is null"); } // notify(); } public Collection/*<MethodDeclarationUnitPair>*/ getCollection() {return c;} } try { FindingOp operation = new FindingOp(); PlatformUI.getWorkbench().getProgressService().run(false, true, operation); // operation.wait(); Collection c = operation.getCollection(); if(c == null) { JavaPlugin.logErrorMessage("No collection is computed"); } return c; } catch (InvocationTargetException e) { JavaPlugin.log(e); } catch (InterruptedException e) { // canceled } return null; } public static Collection/*<Util.ExprUn...>*/ findCallers(final IMethod method, final IJavaProject project) { // TODO Auto-generated method stub return null; } public static Collection/*<MethodDeclarationUnitPair>*/ findMethods(final SimpleName methodName, final JavaProject project, final boolean isConstructor) { class FindingOp implements IRunnableWithProgress { Collection c = null; public void run(IProgressMonitor monitor) { c = findCallees(monitor, methodName.toString(), project, isConstructor); if(c == null) { JavaPlugin.logErrorMessage("Collection is null"); } // notify(); } public Collection/*<MethodDeclarationUnitPair>*/ getCollection() {return c;} } try { FindingOp operation = new FindingOp(); PlatformUI.getWorkbench().getProgressService().run(false, true, operation); // operation.wait(); Collection c = operation.getCollection(); if(c == null) { JavaPlugin.logErrorMessage("No collection is computed"); } return c; } catch (InvocationTargetException e) { JavaPlugin.log(e); } catch (InterruptedException e) { // canceled } return null; } public static Collection/*<MethodDeclarationUnitPair>*/ findCallees(IProgressMonitor progressMonitor, String methodName, IJavaProject project, boolean isConstructor) { try { MethodSearchRequestor.MethodDeclarationsSearchRequestor searchRequestor = new MethodSearchRequestor.MethodDeclarationsSearchRequestor(); SearchEngine searchEngine = new SearchEngine(); IProgressMonitor monitor = new SubProgressMonitor( progressMonitor, 5, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL); monitor.beginTask("Searching for declaration of " + methodName + (project != null ? " in " + project.getProject().getName() : ""), 100); IJavaSearchScope searchScope = getSearchScope(project); int matchType = !isConstructor ? IJavaSearchConstants.METHOD : IJavaSearchConstants.CONSTRUCTOR; SearchPattern pattern = SearchPattern.createPattern( methodName, matchType, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE ); searchEngine.search( pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, searchScope, searchRequestor, monitor ); monitor.done(); return searchRequestor.getMethodUnitPairs(); } catch (CoreException e) { JavaPlugin.log(e); return new LinkedList(); } } /** * Returns a collection of return statements withing @param methodDeclaration. * */ public static Collection<ReturnStatement> findReturns(IProgressMonitor progressMonitor, MethodDeclaration methodDeclaration, JavaProject project) { progressMonitor.setTaskName("Looking for returns in " + methodDeclaration.getName()); final Collection<ReturnStatement> returns = new ArrayList<ReturnStatement>(); ASTVisitor finder = new ASTVisitor() { public boolean visit(ReturnStatement node) { return returns.add(node); } }; methodDeclaration.accept(finder); return returns; } public static String callersToString(IMethod method) { Collection/*<MethodUnitPair>*/ callers = findCallers(method, null); String result = "[ "; for (Iterator iter = callers.iterator(); iter.hasNext();) { Object element = (Object) iter.next(); result += element + " "; } return result + "]"; } public static Collection<Utils.ExpressionUnitPair> getActualsForFormal(IMethod method, Name name, Expression onlyCall, IProgressMonitor monitor, IJavaProject project) { Collection<Utils.ExpressionUnitPair> result = new ArrayList<Utils.ExpressionUnitPair>(); Collection/*<MethodUnitPair>*/ c = findCallers(monitor, method, project); if (c.isEmpty()) { log("No callers for " + method); } else { monitor.beginTask("Getting actuals for " + name + " in " + method.getElementName(), c.size()); int i = 0; for (Iterator iter = c.iterator(); iter.hasNext();) { Utils.ExprUnitResource mi = (Utils.ExprUnitResource) iter.next(); int pos = SlicingUtils.getFormalArgumentPos(method, name); if (pos == SlicingUtils.NO_FORMAL_ARGUMENT) { log("No parameter " + name + " found in " + method); continue; } if (mi.getExpression() == null) { logError("unexpected error: mi.getExpression() == null when looking at " + name + " and " + method); continue; } String s1 = mi.getExpression().toString(); //String s2 = onlyCall.toString(); if ( (onlyCall != null) && (!s1.equals(onlyCall.toString())) ) { log("Skipping " + mi.getExpression() + "while looking for " + onlyCall + " instead"); continue; } Expression expr = SlicingUtils.mapFormal2Actual(mi.getExpression(), pos); if(expr != null) { result.add(new Utils.ExpressionUnitPair(expr, mi.getCompilationUnit(), mi.getResource())); } monitor.worked(++i); } monitor.done(); } return result; } public static Collection/*<ExpressionUnitPair>*/ getActualsForFormal(final IMethod method, final Name name, final Expression onlyCall, final JavaProject project) { class FindingOp implements IRunnableWithProgress { Collection c = null; public void run(IProgressMonitor monitor) { c = getActualsForFormal(method, name, onlyCall, monitor, project); } public Collection getCollection() {return c;} } try { FindingOp operation = new FindingOp(); PlatformUI.getWorkbench().getProgressService().run(false, true, operation); return operation.getCollection(); } catch (InvocationTargetException e) { JavaPlugin.log(e); } catch (InterruptedException e) { // canceled } return null; } public static Collection/*<MethodUnitPair>*/ findCallers(IProgressMonitor progressMonitor, IMethod member, IJavaProject project) { boolean isConstructor = false; try { isConstructor = member.isConstructor(); // interrogate the member itself } catch (JavaModelException e) { JavaPlugin.log(e); } String methodName = isConstructor ? member.getDeclaringType().getElementName() : member.getDeclaringType().getElementName() + "." + member.getElementName(); return findCallers(progressMonitor, methodName, project, isConstructor); } public static Collection/*<MethodUnitPair>*/ findCallers(IProgressMonitor progressMonitor, String methodName, IJavaProject project, boolean isConstructor) { try { MethodSearchRequestor.initializeParserMap(); SearchRequestor searchRequestor = (SearchRequestor)new MethodSearchRequestor.MethodReferencesSearchRequestor(); SearchEngine searchEngine = new SearchEngine(); IProgressMonitor monitor = new SubProgressMonitor(progressMonitor, 5, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); monitor.beginTask("Searching for calls to " + methodName + (project != null ? " in " + project.getProject().getName() : ""), 100); IJavaSearchScope searchScope = getSearchScope(project); // This is kind of hacky: we need to make up a string name for the search to work right log("Looking for calls to " + methodName); int matchType = !isConstructor ? IJavaSearchConstants.METHOD : IJavaSearchConstants.CONSTRUCTOR; SearchPattern pattern = SearchPattern.createPattern( methodName, matchType, IJavaSearchConstants.REFERENCES, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); searchEngine.search( pattern, new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()}, searchScope, searchRequestor, monitor ); if(searchRequestor instanceof MethodSearchRequestor.MethodDeclarationsSearchRequestor){ return ((MethodSearchRequestor.MethodDeclarationsSearchRequestor)searchRequestor).getMethodUnitPairs(); }else{ return ((MethodSearchRequestor.MethodReferencesSearchRequestor)searchRequestor).getMethodUnitPairs(); } } catch (CoreException e) { JavaPlugin.log(e); return new LinkedList(); } } public static Collection/*<MethodUnitPair>*/ findDeclarations(IProgressMonitor progressMonitor, String methodName, IJavaProject project, boolean isConstructor) { try { SearchRequestor searchRequestor = new MethodSearchRequestor.MethodDeclarationsSearchRequestor(); SearchEngine searchEngine = new SearchEngine(); IProgressMonitor monitor = new SubProgressMonitor( progressMonitor, 5, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); monitor.beginTask("Searching for calls to " + methodName + (project != null ? " in " + project.getProject().getName() : ""), 100); IJavaSearchScope searchScope = getSearchScope(project); // This is kind of hacky: we need to make up a string name for the search to work right log("Looking for " + methodName); int matchType = !isConstructor ? IJavaSearchConstants.METHOD : IJavaSearchConstants.CONSTRUCTOR; SearchPattern pattern = SearchPattern.createPattern( methodName, matchType, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE ); searchEngine.search( pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, searchScope, searchRequestor, monitor ); if(searchRequestor instanceof MethodSearchRequestor.MethodDeclarationsSearchRequestor){ return ((MethodSearchRequestor.MethodDeclarationsSearchRequestor)searchRequestor).getMethodUnitPairs(); }else{ return ((MethodSearchRequestor.MethodReferencesSearchRequestor)searchRequestor).getMethodUnitPairs(); } } catch (CoreException e) { JavaPlugin.log(e); return new LinkedList(); } } public static IJavaSearchScope getSearchScope(IJavaProject project) { if (fSearchScope == null) { fSearchScope = SearchEngine.createWorkspaceScope(); //fSearchScope = SearchEngine.createJavaSearchScope(new IResource[] {method.getResource()}); } // return fSearchScope; if(project == null) { return fSearchScope; } else { JavaSearchScope js = new JavaSearchScope(); try { int includeMask = JavaSearchScope.SOURCES | JavaSearchScope.APPLICATION_LIBRARIES | JavaSearchScope.SYSTEM_LIBRARIES ; js.add((JavaProject) project, includeMask, new HashSet()); } catch (JavaModelException e) { log(e.getMessage(), e); return fSearchScope; } return js; } } public static class SlicingUtils { public static final int NO_FORMAL_ARGUMENT = -1; public static Expression mapFormal2Actual(Expression mi, int pos){ //if(mi == null) return null; List args = null; if (mi instanceof ClassInstanceCreation) { args = ((ClassInstanceCreation)mi).arguments(); } else if(mi instanceof MethodInvocation) { args = ((MethodInvocation)mi).arguments(); } else { JavaPlugin.logErrorMessage("Unexpected type in mapFormal2Actual for " + mi); return null; } return (Expression) args.get(pos); } public static SimpleName getVariable(Expression expr){ if (expr instanceof SimpleName) { return (SimpleName) expr; } else { return null; } } /** * @return NO_FORMAL_ARGUMENT signals that there's no matching position in the method declaration. * */ public static int getFormalArgumentPos(IMethod method, Name arg){ String[] names; try { names = method.getParameterNames(); } catch (JavaModelException e) { return NO_FORMAL_ARGUMENT; } for (int i = 0; i < names.length; i++) { if(names[i].equals(arg.toString())) { return i; } } return NO_FORMAL_ARGUMENT; } } private static void log(String message, Throwable e) { LapsePlugin.trace(LapsePlugin.SEARCH, "Call finder: " + message, e); } private static void logError(String message) { log(message, new Throwable()); } private static void log(String message) { log(message, null); } }