Some more instrumentation, and playing around with chopping (chops when double-click...
[eclipsethinslicer.git] / Svelte / src / edu / berkeley / cs / bodik / svelte / plugin / EclipseUtils.java
blobcdf6c07964ee0e25c1c0b2a14c136ccef559659f
1 /*******************************************************************************
2 * This program and the accompanying materials
3 * are made available under the terms of the Eclipse Public License v1.0
4 * which accompanies this distribution, and is available at
5 * http://www.eclipse.org/legal/epl-v10.html.
6 *
7 * This file is a derivative of code released by the University of
8 * California under the terms listed below.
10 * Refinement Analysis Tools is Copyright ©2007 The Regents of the
11 * University of California (Regents). Provided that this notice and
12 * the following two paragraphs are included in any distribution of
13 * Refinement Analysis Tools or its derivative work, Regents agrees
14 * not to assert any of Regents' copyright rights in Refinement
15 * Analysis Tools against recipient for recipient’s reproduction,
16 * preparation of derivative works, public display, public
17 * performance, distribution or sublicensing of Refinement Analysis
18 * Tools and derivative works, in source code and object code form.
19 * This agreement not to assert does not confer, by implication,
20 * estoppel, or otherwise any license or rights in any intellectual
21 * property of Regents, including, but not limited to, any patents
22 * of Regents or Regents’ employees.
24 * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
25 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
26 * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE
27 * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32 * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY
33 * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING
34 * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
35 * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
36 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
38 package edu.berkeley.cs.bodik.svelte.plugin;
40 import java.io.File;
41 import java.util.List;
42 import java.util.jar.JarFile;
44 import org.eclipse.core.resources.IFile;
45 import org.eclipse.core.resources.IProject;
46 import org.eclipse.core.resources.IProjectNature;
47 import org.eclipse.core.resources.IWorkspace;
48 import org.eclipse.core.resources.ResourcesPlugin;
49 import org.eclipse.core.runtime.CoreException;
50 import org.eclipse.core.runtime.IPath;
51 import org.eclipse.core.runtime.Path;
52 import org.eclipse.jdt.core.IClasspathEntry;
53 import org.eclipse.jdt.core.ICompilationUnit;
54 import org.eclipse.jdt.core.IJavaProject;
55 import org.eclipse.jdt.core.IMethod;
56 import org.eclipse.jdt.core.IType;
57 import org.eclipse.jdt.core.JavaCore;
58 import org.eclipse.jdt.core.JavaModelException;
59 import org.eclipse.jdt.core.Signature;
60 import org.eclipse.jdt.core.dom.AST;
61 import org.eclipse.jdt.core.dom.ASTNode;
62 import org.eclipse.jdt.core.dom.MethodDeclaration;
63 import org.eclipse.jdt.core.dom.Modifier;
64 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
65 import org.eclipse.jdt.internal.corext.dom.NodeFinder;
66 import org.eclipse.ui.IEditorDescriptor;
67 import org.eclipse.ui.IEditorInput;
68 import org.eclipse.ui.IEditorPart;
69 import org.eclipse.ui.IEditorRegistry;
70 import org.eclipse.ui.IFileEditorInput;
71 import org.eclipse.ui.IWorkbenchPage;
72 import org.eclipse.ui.IWorkbenchWindow;
73 import org.eclipse.ui.PartInitException;
74 import org.eclipse.ui.PlatformUI;
75 import org.eclipse.ui.internal.WorkbenchPlugin;
76 import org.eclipse.ui.internal.dialogs.DialogUtil;
77 import org.eclipse.ui.part.FileEditorInput;
78 import org.eclipse.ui.texteditor.AbstractTextEditor;
80 import com.ibm.wala.classLoader.BinaryDirectoryTreeModule;
81 import com.ibm.wala.classLoader.JarFileModule;
82 import com.ibm.wala.classLoader.Module;
83 import com.ibm.wala.ipa.callgraph.CGNode;
84 import com.ibm.wala.ipa.slicer.NormalReturnCallee;
85 import com.ibm.wala.ipa.slicer.NormalStatement;
86 import com.ibm.wala.ipa.slicer.ParamCallee;
87 import com.ibm.wala.ipa.slicer.ParamCaller;
88 import com.ibm.wala.ipa.slicer.Statement;
90 import edu.berkeley.cs.bodik.svelte.CGNodeUtils;
91 import edu.berkeley.cs.bodik.svelte.SourcePosition;
92 import edu.berkeley.cs.bodik.svelte.StatementUtils;
94 /**
95 * Should probably move some of this to SliceEnvironment.
97 * @author evan
100 public class EclipseUtils {
103 * Same as findSourceFileForClass, but arguments must begin with "L", which this function removes before passing on to findSourceFileForClass.
104 * @param classnamePrefixedByL
105 * @param proj
106 * @return
107 * @see findSourceFileForClass
109 public static String findSourceFileForClassStripL(String classnamePrefixedByL, IJavaProject proj) {
110 assert ( classnamePrefixedByL.startsWith("L") );
111 return findSourceFileForClass(classnamePrefixedByL.substring(1), proj);
116 * Hack to find the source filename for a given class, assuming it's one of the source files in the given
117 * project. Looks thru all source directories. Example. for class name com/example/pack/MyClass$InnerClass,
118 * looks for file com/example/pack/MyClass.java in all the project's source directories.
120 * @param classname
121 * Fully qualified classname, e.g. com/example/pack/MyClass$InnerClass. CANNOT HAVE L AT BEGINNING (use
122 * findSourceFileForClassStripL). Separated by either '.' or '/'.
124 * @param proj
126 * @return
127 * The absolute filename which contains the class, or null.
129 public static String findSourceFileForClass(String classname, IJavaProject proj) {
130 if ( classname == null || proj == null )
131 return null;
133 // Strip characters after "$" that is after the last "/" (inner classes), and add ".java"
134 classname = classname.replaceAll("\\.","/"); // java.lang.String -> java/lang/String
135 Path javafilenamepath = new Path(classname.replaceAll("\\$[^/]*$", "")+".java");
136 IClasspathEntry[] classpaths = null;
137 try {
138 classpaths = proj.getResolvedClasspath(true);
139 for ( IClasspathEntry cpe: classpaths ) {
140 if ( cpe.getEntryKind() == IClasspathEntry.CPE_SOURCE ) {
142 IPath srcpath = ResourcesPlugin.getWorkspace().getRoot().getLocation().append(cpe.getPath()).append(javafilenamepath);
143 String srcstr = srcpath.toOSString();
144 if ( new File(srcpath.toOSString()).exists() )
145 return srcstr;
150 } catch (JavaModelException e) {
151 e.printStackTrace();
153 return null;
156 public static String findClassFileForClass(String classname, IJavaProject proj) {
157 if ( classname == null || proj == null )
158 return null;
160 // Strip characters after "$" that is after the last "/" (inner classes), and add ".java"
161 classname = classname.replaceAll("\\.","/"); // java.lang.String -> java/lang/String
162 Path classfilenamepath = new Path(classname+".class");
163 return classPathToFilename(classfilenamepath, proj);
166 private static String classPathToFilename(Path path, IJavaProject proj) {
167 IClasspathEntry[] classpaths = null;
170 // see if it's directly in this project's output location.
171 String inthisbindir;
172 try {
173 inthisbindir = ResourcesPlugin.getWorkspace().getRoot().getLocation().append(proj.getOutputLocation()).append(path).toOSString();
174 if ( new File(inthisbindir).exists() )
175 return inthisbindir;
176 } catch (JavaModelException e1) {
177 e1.printStackTrace();
180 // otherwise, try it's libraries and projects (recursively)
181 try {
182 classpaths = proj.getResolvedClasspath(true);
183 for ( IClasspathEntry cpe: classpaths ) {
184 if ( cpe.getEntryKind() == IClasspathEntry.CPE_PROJECT ) {
185 IProject project = (IProject) ResourcesPlugin.getWorkspace().getRoot().findMember(cpe.getPath());
186 String result = classPathToFilename ( path, JavaCore.create(project) );
187 if ( result != null )
188 return result;
189 } else if ( cpe.getEntryKind() == IClasspathEntry.CPE_LIBRARY ) {
190 // look for it physically
191 IPath srcpath = ResourcesPlugin.getWorkspace().getRoot().getLocation().append(cpe.getPath()).append(path);
192 String srcstr = srcpath.toOSString();
193 if ( new File(srcpath.toOSString()).exists() )
194 return srcstr;
197 } catch (JavaModelException e) {
198 e.printStackTrace();
200 return null;
203 // DELETE THIS SET OF COMMENT CODE NOW!!!
204 //} else if ( cpe.getEntryKind() == IClasspathEntry.CPE_LIBRARY ) {
205 // // System.out.println("DEBUG: adding CPE_LIBRARY " + makeAbsolute(cpe.getPath()).toOSString());
207 // File file = makeAbsolute(cpe.getPath()).toFile();
208 // Module m = null;
209 // if ( file.isDirectory() )
210 // m = new BinaryDirectoryTreeModule(file);
211 // else {
212 // m = new JarFileModule(new JarFile(file));
213 // }
215 // // libraries with absolute paths are assumed to be "system" jars
216 // if ( pathAbsolute ) {
217 // // System.out.println("(as system)");
218 // addSystemModule(m);
219 // } else {
220 // // System.out.println("(as compiled)");
221 // addCompiledModule(m);
222 // }
223 //} else if ( cpe.getEntryKind() == IClasspathEntry.CPE_PROJECT ) {
224 // // TODO -- add as source if not using shrike, maybe.
225 // //addClassDir(makeAbsolute(cpe.getPath()).toOSString()); // could add as source
227 // IProject project = (IProject) ResourcesPlugin.getWorkspace().getRoot().findMember(cpe.getPath());
228 // addEclipseClasspaths ( JavaCore.create(project), true, true );
232 public static IFile findIFileForFilename(String filename) {
233 if ( filename!= null ) {
234 IWorkspace workspace= ResourcesPlugin.getWorkspace();
235 IPath location= Path.fromOSString(filename);
236 IFile f= workspace.getRoot().getFileForLocation(location);
237 return f;
239 return null;
243 public static class MethodSignature {
244 private String packageName;
245 private String className;
246 private String methodName;
247 private String methodParams;
248 private String methodReturnValue;
250 public MethodSignature (String signature) {
251 // find it and go to it!
252 int class_met_boundary = signature.lastIndexOf('.');
254 String pkg_and_classname = signature.substring(0, class_met_boundary);
255 String method_signature = signature.substring(class_met_boundary+1);
257 int pkg_class_boundary = pkg_and_classname.lastIndexOf('.');
259 // TODO: if in default package?
260 this.packageName = pkg_and_classname.substring(0, pkg_class_boundary);
261 this.className = pkg_and_classname.substring(pkg_class_boundary+1);
263 int met_param_boundary = method_signature.indexOf('(');
264 int param_ret_boundary = method_signature.indexOf(')');
266 this.methodName = method_signature.substring(0, met_param_boundary);
267 if ( this.methodName.equals("<init>") )
268 this.methodName = this.className;
269 this.methodParams = method_signature.substring(met_param_boundary+1,param_ret_boundary);
270 this.methodReturnValue = method_signature.substring(param_ret_boundary+1);
273 public String getPackageName() {
274 return packageName;
277 public String getClassName() {
278 return className;
281 public String getMethodSignature() {
282 return methodName + '(' + methodParams + ')' + methodReturnValue;
285 public String getQualifiedClassName() {
286 return packageName+"."+className;
289 public String getSignature() {
290 return packageName+"."+className+"."+getMethodSignature();
293 public String[] getUnqualifiedParameterTypes() {
294 return Signature.getParameterTypes(getMethodSignature().replace('/','.').replaceAll("L[^;]*\\.([^;\\.]*);","Q$1;")); // java/lang/String -> QString
297 public String getMethodName() {
298 return methodName;
302 public static void openFile(IFile file) {
305 // get default editor descriptor
307 IEditorRegistry editorRegistry = WorkbenchPlugin.getDefault().getEditorRegistry();
308 IEditorDescriptor defaultEditorDescriptor = editorRegistry.getDefaultEditor(file.toString());
309 //// || defaultEditorDescriptor.isOpenExternal() is only eclipse 3.x!!!
310 if( defaultEditorDescriptor == null){
311 defaultEditorDescriptor = editorRegistry.getDefaultEditor("dummy.txt");
314 // Open new file in editor
315 IWorkbenchWindow dw = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
316 FileEditorInput fileEditorInput = new FileEditorInput(file);
317 try {
318 IWorkbenchPage page = dw.getActivePage();
319 if (page != null)
320 //page.openEditor(fileEditorInput,"org.eclipse.ui.DefaultTextEditor");
321 page.openEditor(fileEditorInput, defaultEditorDescriptor.getId() );
322 } catch (PartInitException e) {
323 DialogUtil.openError(dw.getShell(), "Could not open new file", e.getMessage(), e);
328 public static void gotoNode(String nodeString, IJavaProject proj) {
329 if ( nodeString == null || proj == null )
330 return;
332 MethodSignature met = new MethodSignature(nodeString);
334 // TODO: associate cgslice with project beforehand
335 // find the method in source
336 try {
337 IFile f = EclipseUtils.findIFileForFilename(EclipseUtils.findSourceFileForClass(met.getQualifiedClassName(), proj));
339 EclipseUtils.openFile(f);
341 IEditorPart iep = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
342 AbstractTextEditor e = (AbstractTextEditor) iep;
344 ICompilationUnit cu = JavaCore.createCompilationUnitFrom(f);
345 IType type = cu.getType(met.getClassName());
346 IMethod m = type.getMethod(met.getMethodName(),met.getUnqualifiedParameterTypes());
347 e.selectAndReveal(m.getNameRange().getOffset(),m.getNameRange().getLength());
348 } catch (NullPointerException e) {
349 System.err.println("couldn't find src method. problem:");
350 e.printStackTrace(System.err);
351 } catch (JavaModelException e) {
352 e.printStackTrace();
356 public static void gotoNodeParam(String nodeString, int arg_index, IJavaProject proj) {
357 if ( nodeString == null || proj == null )
358 return;
360 MethodSignature met = new MethodSignature(nodeString);
362 // TODO: associate cgslice with project beforehand
363 // find the method in source
364 try {
365 IFile f = EclipseUtils.findIFileForFilename(EclipseUtils.findSourceFileForClass(met.getQualifiedClassName(), proj));
367 EclipseUtils.openFile(f);
369 IEditorPart iep = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
370 AbstractTextEditor e = (AbstractTextEditor) iep;
372 ICompilationUnit cu = JavaCore.createCompilationUnitFrom(f);
373 IType type = cu.getType(met.getClassName());
374 IMethod m = type.getMethod(met.getMethodName(),met.getUnqualifiedParameterTypes());
375 // e.selectAndReveal(m.getNameRange().getOffset(),m.getNameRange().getLength());
377 // TODO: hack (should do this right)
378 ASTNode aSTNode = AST.parseCompilationUnit(cu, false);
379 NodeFinder nf = new NodeFinder(m.getNameRange().getOffset(),m.getNameRange().getLength());
380 aSTNode.accept(nf);
381 ASTNode node = nf.getCoveringNode();
382 if ( node.getParent() instanceof MethodDeclaration ) {
383 MethodDeclaration md = (MethodDeclaration) node.getParent();
384 List params = md.parameters();
385 if ( arg_index < params.size() ) {
386 Object param = params.get(arg_index);
387 if ( param instanceof SingleVariableDeclaration ) {
388 SingleVariableDeclaration svd = (SingleVariableDeclaration) param;
389 e.selectAndReveal(svd.getStartPosition(),svd.getLength());
393 } catch (NullPointerException e) {
394 System.err.println("couldn't find src method. problem:");
395 e.printStackTrace(System.err);
396 } catch (JavaModelException e) {
397 e.printStackTrace();
401 public static IJavaProject getJavaProjectFromOpenEditor() {
402 IEditorInput activeEdInput = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getEditorInput();
403 if (activeEdInput instanceof IFileEditorInput) {
404 IProject proj = ((IFileEditorInput)activeEdInput).getFile().getProject();
405 IProjectNature projectnature;
406 try {
407 projectnature = proj.getNature(JavaCore.NATURE_ID);
408 if ( projectnature instanceof IJavaProject )
409 return (IJavaProject) projectnature;
410 } catch (CoreException e) {
411 return null;
414 return null;
418 * Uses the open editor as the project to look for the file.
420 * Passing a ParamCallee statement will highlight the line of the function definition.
422 * @param s
424 public static void gotoStatement(Statement ss) {
425 if ( ss == null )
426 return;
428 if ( ss instanceof ParamCallee ) {
429 ParamCallee pac = (ParamCallee)ss;
430 CGNode node = ((ParamCallee)ss).getNode();
432 int arg_index = pac.getValueNumber() - 1;
433 if ( ! node.getMethod().isStatic() )
434 arg_index --;
436 gotoNodeParam(node.getMethod().getSignature().toString(),arg_index,getJavaProjectFromOpenEditor());
437 } else if ( ss instanceof NormalReturnCallee ) {
438 NormalReturnCallee pac = (NormalReturnCallee)ss;
439 CGNode node = ((NormalReturnCallee)ss).getNode();
440 gotoNode(node.getMethod().getSignature().toString(),getJavaProjectFromOpenEditor());
441 } else if ( !(ss instanceof NormalStatement) )
442 ss = StatementUtils.getCallerStatement(ss);
443 if ( ss != null && ss instanceof NormalStatement ) {
444 SourcePosition sp = CGNodeUtils.getSourcePositionOfInstructionIndex(ss.getNode(), ((NormalStatement)ss).getInstructionIndex() );
445 if ( sp != null ) {
446 if ( sp.filename == null ) {
447 sp.filename = EclipseUtils.findSourceFileForClass(sp.classname, getJavaProjectFromOpenEditor());
449 if ( sp.filename == null )
450 return;
451 IFile f = EclipseUtils.findIFileForFilename(sp.filename);
452 if ( f != null ) {
453 EclipseUtils.openFile(f);
455 IEditorPart iep = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
456 AbstractTextEditor e = (AbstractTextEditor) iep;
457 // TODO -- what if don't have offset (i.e. Shrike) ?
458 e.selectAndReveal(sp.offsetStart,sp.offsetEnd-sp.offsetStart);
468 public static String findClassFileForClassStripL(String classnamePrefixedByL,
469 IJavaProject javaProject) {
470 assert ( classnamePrefixedByL.startsWith("L") );
471 return findClassFileForClass(classnamePrefixedByL.substring(1), javaProject);