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
;
40 import java
.io
.IOException
;
41 import java
.util
.ArrayList
;
42 import java
.util
.Arrays
;
43 import java
.util
.Collection
;
44 import java
.util
.Hashtable
;
46 import org
.eclipse
.core
.resources
.IFile
;
47 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
48 import org
.eclipse
.core
.runtime
.CoreException
;
49 import org
.eclipse
.debug
.core
.DebugPlugin
;
50 import org
.eclipse
.debug
.core
.ILaunchConfiguration
;
51 import org
.eclipse
.debug
.core
.ILaunchManager
;
52 import org
.eclipse
.jdt
.core
.IJavaProject
;
53 import org
.eclipse
.jface
.viewers
.ArrayContentProvider
;
54 import org
.eclipse
.jface
.viewers
.LabelProvider
;
55 import org
.eclipse
.ui
.PlatformUI
;
56 import org
.eclipse
.ui
.dialogs
.ListSelectionDialog
;
58 import com
.ibm
.wala
.cast
.ir
.ssa
.SSAConversion
;
59 import com
.ibm
.wala
.cast
.ir
.ssa
.AstIRFactory
.AstIR
;
60 import com
.ibm
.wala
.cast
.java
.loader
.JavaSourceLoaderImpl
.ConcreteJavaMethod
;
61 import com
.ibm
.wala
.ipa
.callgraph
.CGNode
;
62 import com
.ibm
.wala
.ipa
.callgraph
.CallGraph
;
63 import com
.ibm
.wala
.ipa
.callgraph
.impl
.ExplicitCallGraph
.ExplicitNode
;
64 import com
.ibm
.wala
.ipa
.callgraph
.propagation
.PointerAnalysis
;
65 import com
.ibm
.wala
.ipa
.slicer
.NormalStatement
;
66 import com
.ibm
.wala
.ipa
.slicer
.Statement
;
67 import com
.ibm
.wala
.ssa
.DefUse
;
68 import com
.ibm
.wala
.ssa
.IR
;
69 import com
.ibm
.wala
.ssa
.SSAInstruction
;
70 import com
.ibm
.wala
.util
.collections
.Pair
;
72 import edu
.berkeley
.cs
.bodik
.svelte
.CGNodeUtils
;
73 import edu
.berkeley
.cs
.bodik
.svelte
.CallGraphUtils
;
74 import edu
.berkeley
.cs
.bodik
.svelte
.SourcePosition
;
75 import edu
.berkeley
.cs
.bodik
.svelte
.Slice
;
76 import edu
.berkeley
.cs
.bodik
.svelte
.Slicing
;
77 import edu
.berkeley
.cs
.bodik
.svelte
.SvelteAnalysisEngine
;
80 public class PluginWALADriver
{
83 * Set up the analysis scope and make a call graph.
85 * For now, source directories, etc. are hard coded, so you have to change this method if you use the
86 * slicer with another project. We'll have to find a solution to this in the future.
88 * WARNING: contains absolute paths on my computer. This may be unneeded, as the polyglot-relate bug may be fixed.
91 * Ignored for now. In the future we'll want to pass in the source directories, jars, etc.
93 * @param mainClassName
94 * The class name which contains the <code>public static void main(String[])</code> function
95 * which we'll use as an entry point for building the call graph.
98 * The CallGraph and associated PointerAnalysis, useful for all kinds of analyses.
100 public static Pair
<CallGraph
,PointerAnalysis
> generateCallGraphPolyglot ( String filename
, String mainClassName
) {
102 String polyglotDir
= "/media/sda6/work/runwork/palante/polyglot-2.3.0-src/";///home/evan/t/runwork/palante/polyglot-2.3.0-src/"; //warning: won't work if uses symlink (eclipse keeps track of one real path only, used for looking up files to add markers)
103 String sourcedirectory
= polyglotDir
+ "src/";
104 String sdexclusions
[] = {
105 "polyglot/ast/AbstractNodeFactory_c.java",
106 "polyglot/types/TypeSystem_c.java",
107 "polyglot/util/InternalCompilerError.java",
109 String jarfiles
[] = {
110 polyglotDir
+ "lib/java_cup.jar",
111 polyglotDir
+ "lib/JFlex.jar",
112 // polyglotDir + "lib/polyglot.jar",
113 polyglotDir
+ "lib/ppg.jar",
114 polyglotDir
+ "classes/problemclasses.jar",
117 SvelteAnalysisEngine se
= new SvelteAnalysisEngine();
121 se
.addJavaDirExcept(sourcedirectory
, sdexclusions
);
122 se
.addJars(jarfiles
);
123 se
.findEntrypointFromClassnameOfMain(mainClassName
);
124 } catch ( IOException e
) {
129 // builds if not already built
132 return Pair
.make(se
.getCallGraph(),se
.getPointerAnalysis());
135 private static boolean useShrike
= false;
136 public static void setUseShrike(boolean val
) {
139 public static boolean getUseShrike() {
144 * Look at the localJavaApplication launchers for a given project and determine
145 * the main class for the "default" launcher. In the future I'd like to have it
146 * be exactly how it is in the run/debug toolbar drop-down menu. But for now,
147 * it just chooses the first launcher of type localJavaApplication for this project,
148 * or returns <code>tryFirst</code> if this is listed as a launcher (usu. will be found
149 * if it has a main method).
153 * A classname. If this listed as a main class for some launcher, use this.
157 public static String
findLauncherMainClass ( IJavaProject project
, String tryFirst
) {
158 String firstencountered
= null;
159 ILaunchManager manager
= DebugPlugin
.getDefault().getLaunchManager();
161 ILaunchConfiguration configs
[] = manager
.getLaunchConfigurations();
162 for ( ILaunchConfiguration cfg
: configs
) {
163 if ( cfg
.getType().getIdentifier().equals("org.eclipse.jdt.launching.localJavaApplication") &&
164 cfg
.getAttribute("org.eclipse.jdt.launching.PROJECT_ATTR", "").equals(project
.getElementName()) ) {
165 String classname
= cfg
.getAttribute("org.eclipse.jdt.launching.MAIN_TYPE",(String
)null);
166 if ( tryFirst
.equals(classname
) )
168 if ( firstencountered
== null )
169 firstencountered
= classname
;
172 } catch (CoreException e2
) {
173 e2
.printStackTrace();
175 return firstencountered
;
179 * Look at the localJavaApplication launchers for a given project and determine
181 * The currently opened class should probably be used too, if it has a main method.
187 public static ArrayList
<String
> findLauncherMainClasses ( IJavaProject project
) {
188 ILaunchManager manager
= DebugPlugin
.getDefault().getLaunchManager();
189 ArrayList
<String
> classes
= new ArrayList
<String
>();
191 ILaunchConfiguration configs
[] = manager
.getLaunchConfigurations();
192 for ( ILaunchConfiguration cfg
: configs
) {
193 if ( cfg
.getType().getIdentifier().equals("org.eclipse.jdt.launching.localJavaApplication") &&
194 cfg
.getAttribute("org.eclipse.jdt.launching.PROJECT_ATTR", "").equals(project
.getElementName()) ) {
195 classes
.add ( cfg
.getAttribute("org.eclipse.jdt.launching.MAIN_TYPE",(String
)null) );
198 } catch (CoreException e2
) {
199 e2
.printStackTrace();
204 public static Pair
<CallGraph
,PointerAnalysis
> generateCallGraph ( String filename
, String openEditorClassname
, IJavaProject project
) {
206 if ( project
.getElementName().equals("polyglot-2.3.0-src") && ! useShrike
)
207 return generateCallGraphPolyglot(filename
, openEditorClassname
);
209 SvelteAnalysisEngine se
= new SvelteAnalysisEngine();
210 se
.addEclipseClasspaths(project
,useShrike
);
212 ArrayList
<String
> mainClasses
= findLauncherMainClasses(project
);
213 boolean alreadyin
= false;
214 for ( String s
: mainClasses
)
215 alreadyin
|= s
.equals(openEditorClassname
);
217 mainClasses
.add(openEditorClassname
);
219 se
.findEntrypointFromClassnamesOfMain(mainClasses
);
220 // if no launchers for project, try open editor's className anyway. the user may get the idea...
222 return Pair
.make(se
.getCallGraph(),se
.getPointerAnalysis());
226 * Finds the seed statements on the specified line number of the Java file whose main class is the qualified mainClassName.
227 * In other words, this functions finds all IR statements for a particular Java statement.
228 * Warning: this function will take a long time if the call graph has not been built!
231 * @param mainClassName
235 public static ArrayList
<Statement
> getSeedStatementsFromLineNum(IFile file
, String mainClassName
, int linenum
) {
236 Pair
<CallGraph
, PointerAnalysis
> cgpa
= getCallGraph(file
);
237 CallGraph cg
= cgpa
.fst
;
238 PointerAnalysis pa
= cgpa
.snd
;
240 // dumpIR(cg, assertReachable);
241 // TODO: does this work for inner classes?
242 CGNode cgn
= CallGraphUtils
.findMethodIncludingLineNumInClass(cg
,linenum
,mainClassName
);
244 System
.out
.println("ERROR: couldn't find method include line " + linenum
+ " in class " + mainClassName
);
246 return CGNodeUtils
.getStatementsFromLineNumber(cgn
, linenum
);
250 * Get a cached call graph thru CallGraphUpdater.CallGraphCache.
251 * If a call graph has not been built, the call graph cache will build one using
252 * <code>generateCallGraph()</code>.
255 public static Pair
<CallGraph
, PointerAnalysis
> getCallGraph(
257 return CallGraphUpdater
.CallGraphProjectCache
.getInstance().getCallGraph(file
);
267 * Filename of the .java file, e.g. /path/to/my/java/stuff/MyFabulousClass.java (currently used only
268 * for locating method -- source directory is hardcoded for loading analysis scope)
270 * @param packageAndClass
271 * The package and class name, e.g. com.example.mypackage.MyFabulousClass
274 * Line number in the original source. This may correlate to many "statements" in the IR.
276 * @param formalParameter
277 * the integer index of the formal parameter to slice from, or -1. If this is not -1, the seed will be chosen as
278 * a PARAM_CALLEE statement for the method including line number linenum, and not as the statements on linenum.
281 * Slicer.CI_THIN_SLICE, Slicer.CS_THIN_SLICE, Slicer.CS_THICK_SLICE
284 * ArrayList of int[4] containing the positions of the slice statements -- firstLine, firstCol, lastLine, lastCol,
285 * e.g. the first statement in the slice starts at line returnvalue[0][1], column returnvalue[0][2]
287 public static Slice
getPositionsOfThinSliceForLineNumInMain(IFile file
, String filename
, String mainClassName
,
288 int linenum
, int formalParameter
, int slicerType
, int depth
) {
289 // load source & binary files to make a CG and PA
290 // replace with generateCallGraph to bypass caching
291 Pair
<CallGraph
, PointerAnalysis
> cgpa
= getCallGraph(file
);
292 CallGraph cg
= cgpa
.fst
;
293 PointerAnalysis pa
= cgpa
.snd
;
295 // dumpIR(cg, assertReachable);
296 // TODO: does this work for inner classes?
297 CGNode cgn
= CallGraphUtils
.findMethodIncludingLineNumInClass(cg
,linenum
,mainClassName
);
299 System
.out
.println("ERROR: couldn't find method including line " + linenum
+ " in class " + mainClassName
);
302 if ( formalParameter
!= -1 )
303 seed
= new Slice(CGNodeUtils
.getFormalParameterStatement(cgn
, formalParameter
));
305 seed
= new Slice(CGNodeUtils
.getStatementsFromLineNumber(cgn
, linenum
));
308 if ( seed
.getStatements().size() == 0 )
309 System
.err
.println("ERROR: slice is size 0");
311 Slice s
= Slicing
.doSlice(slicerType
,cg
,pa
,seed
,depth
);
313 // // determine sliced nodes
314 // Hashtable<CGNode,Boolean> nodes = new Hashtable<CGNode,Boolean>();
315 // Boolean dummy = new Boolean(true);
316 // for (Statement stat: s) {
317 // if ( stat != null ) {
318 // CGNode nod = stat.getNode();
319 // if ( nod.getMethod() instanceof ConcreteJavaMethod )
320 // nodes.put(nod, dummy);
323 // // undo copy prop in these nodes
324 // for ( CGNode nod: nodes.keySet() ) {
325 // IR ir = nod.getIR();
326 //// if ( ir instanceof AstIR ) {
327 //// SSAInstruction instrs[] = ir.getInstructions();
328 //// for ( int i = 0; i < instrs.length; i++ )
329 //// if ( instrs[i] != null )
330 //// for ( int u = 0; u < instrs[i].getNumberOfUses(); u++ )
331 //// SSAConversion.undoCopyPropagation((AstIR)ir,i,u);
333 // ((ExplicitNode) nod).redoDU();
336 // s = Slicing.doSlice(slicerType,cg,pa,seed);
342 // check if added anything visible for a subslice, and if not, add one more level of depth.
343 // TODO: TEST THIS!!!
345 for ( Statement st
: s
) {
346 SourcePosition pos
= CGNodeUtils
.getSourcePositionOfInstructionIndex(st
.getNode(), ((NormalStatement
)st
).getInstructionIndex() );
347 if ( pos
.lineStart
!= linenum
) { // TODO: should really check it it's in the seed.
351 return getPositionsOfThinSliceForLineNumInMain(file
, filename
, mainClassName
, linenum
, formalParameter
, slicerType
, depth
+1);
357 // ArrayList<SourcePosition> hpos = s.getPositions(true);