slice from formal parameter. probably other misc changes
[eclipsethinslicer.git] / Svelte / src / edu / berkeley / cs / bodik / svelte / plugin / PluginWALADriver.java
blobf84f152cac4f0f37abd6d49270d588265ba0b46c
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.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 {
82 /**
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.
90 * @param filename
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.
97 * @return
98 * The CallGraph and associated PointerAnalysis, useful for all kinds of analyses.
100 public static Pair<CallGraph,PointerAnalysis> generateCallGraphPolyglot ( String filename, String mainClassName ) {
101 // Set up the scope
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();
118 se.addRtJar();
120 try {
121 se.addJavaDirExcept(sourcedirectory, sdexclusions);
122 se.addJars(jarfiles);
123 se.findEntrypointFromClassnameOfMain(mainClassName);
124 } catch ( IOException e ) {
125 e.printStackTrace();
129 // builds if not already built
130 // se.rebuild();
132 return Pair.make(se.getCallGraph(),se.getPointerAnalysis());
135 private static boolean useShrike = false;
136 public static void setUseShrike(boolean val) {
137 useShrike = val;
139 public static boolean getUseShrike() {
140 return useShrike;
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).
151 * @param project
152 * @param tryFirst
153 * A classname. If this listed as a main class for some launcher, use this.
155 * @return
157 public static String findLauncherMainClass ( IJavaProject project, String tryFirst ) {
158 String firstencountered = null;
159 ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
160 try {
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) )
167 return tryFirst;
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
180 * all main classes.
181 * The currently opened class should probably be used too, if it has a main method.
183 * @param project
185 * @return
187 public static ArrayList<String> findLauncherMainClasses ( IJavaProject project ) {
188 ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
189 ArrayList<String> classes = new ArrayList<String>();
190 try {
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();
201 return classes;
204 public static Pair<CallGraph,PointerAnalysis> generateCallGraph ( String filename, String openEditorClassname, IJavaProject project ) {
205 // hack: exceptions
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);
216 if ( !alreadyin )
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!
230 * @param file
231 * @param mainClassName
232 * @param linenum
233 * @return
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);
243 if ( cgn == null )
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(
256 IFile file) {
257 return CallGraphUpdater.CallGraphProjectCache.getInstance().getCallGraph(file);
262 * Make a slice.
264 * @author evan
266 * @param filename
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
273 * @param linenum
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.
280 * @param slicerType
281 * Slicer.CI_THIN_SLICE, Slicer.CS_THIN_SLICE, Slicer.CS_THICK_SLICE
283 * @return
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);
298 if ( cgn == null )
299 System.out.println("ERROR: couldn't find method including line " + linenum + " in class " + mainClassName );
301 Slice seed;
302 if ( formalParameter != -1 )
303 seed = new Slice(CGNodeUtils.getFormalParameterStatement(cgn, formalParameter));
304 else
305 seed = new Slice(CGNodeUtils.getStatementsFromLineNumber(cgn, linenum));
307 seed.dumpConcise();
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);
321 // }
322 // }
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);
332 //// }
333 // ((ExplicitNode) nod).redoDU();
334 // }
335 // //retake slice
336 // s = Slicing.doSlice(slicerType,cg,pa,seed);
338 s.dump();
340 s.prune(true);
342 // check if added anything visible for a subslice, and if not, add one more level of depth.
343 // TODO: TEST THIS!!!
344 if ( depth == 2 ) {
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.
348 return s;
351 return getPositionsOfThinSliceForLineNumInMain(file, filename, mainClassName, linenum, formalParameter, slicerType, depth+1);
354 s.dump();
356 return s;
357 // ArrayList<SourcePosition> hpos = s.getPositions(true);
358 // return hpos;