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.
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 recipients 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
;
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
;
95 * Should probably move some of this to SliceEnvironment.
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
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.
121 * Fully qualified classname, e.g. com/example/pack/MyClass$InnerClass. CANNOT HAVE L AT BEGINNING (use
122 * findSourceFileForClassStripL). Separated by either '.' or '/'.
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 )
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;
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() )
150 } catch (JavaModelException e
) {
156 public static String
findClassFileForClass(String classname
, IJavaProject proj
) {
157 if ( classname
== null || proj
== 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.
173 inthisbindir
= ResourcesPlugin
.getWorkspace().getRoot().getLocation().append(proj
.getOutputLocation()).append(path
).toOSString();
174 if ( new File(inthisbindir
).exists() )
176 } catch (JavaModelException e1
) {
177 e1
.printStackTrace();
180 // otherwise, try it's libraries and projects (recursively)
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 )
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() )
197 } catch (JavaModelException e
) {
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();
209 // if ( file.isDirectory() )
210 // m = new BinaryDirectoryTreeModule(file);
212 // m = new JarFileModule(new JarFile(file));
215 // // libraries with absolute paths are assumed to be "system" jars
216 // if ( pathAbsolute ) {
217 // // System.out.println("(as system)");
218 // addSystemModule(m);
220 // // System.out.println("(as compiled)");
221 // addCompiledModule(m);
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
);
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() {
277 public String
getClassName() {
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() {
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
);
318 IWorkbenchPage page
= dw
.getActivePage();
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 )
332 MethodSignature met
= new MethodSignature(nodeString
);
334 // TODO: associate cgslice with project beforehand
335 // find the method in source
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
) {
356 public static void gotoNodeParam(String nodeString
, int arg_index
, IJavaProject proj
) {
357 if ( nodeString
== null || proj
== null )
360 MethodSignature met
= new MethodSignature(nodeString
);
362 // TODO: associate cgslice with project beforehand
363 // find the method in source
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());
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
) {
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
;
407 projectnature
= proj
.getNature(JavaCore
.NATURE_ID
);
408 if ( projectnature
instanceof IJavaProject
)
409 return (IJavaProject
) projectnature
;
410 } catch (CoreException e
) {
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.
424 public static void gotoStatement(Statement ss
) {
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() )
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() );
446 if ( sp
.filename
== null ) {
447 sp
.filename
= EclipseUtils
.findSourceFileForClass(sp
.classname
, getJavaProjectFromOpenEditor());
449 if ( sp
.filename
== null )
451 IFile f
= EclipseUtils
.findIFileForFilename(sp
.filename
);
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
);