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
;
41 import java
.io
.FileNotFoundException
;
42 import java
.io
.IOException
;
43 import java
.util
.ArrayList
;
44 import java
.util
.Collection
;
45 import java
.util
.LinkedList
;
46 import java
.util
.List
;
47 import java
.util
.Properties
;
48 import java
.util
.jar
.JarFile
;
50 import org
.eclipse
.core
.resources
.IFile
;
51 import org
.eclipse
.core
.resources
.IProject
;
52 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
53 import org
.eclipse
.core
.runtime
.IPath
;
54 import org
.eclipse
.jdt
.core
.IClasspathEntry
;
55 import org
.eclipse
.jdt
.core
.IJavaProject
;
56 import org
.eclipse
.jdt
.core
.JavaCore
;
57 import org
.eclipse
.jdt
.core
.JavaModelException
;
59 import com
.ibm
.wala
.cast
.java
.client
.JavaSourceAnalysisEngine
;
60 import com
.ibm
.wala
.cast
.java
.client
.JdtJavaSourceAnalysisEngine
;
61 import com
.ibm
.wala
.cast
.java
.client
.impl
.ZeroOneContainerCFABuilderFactory
;
62 import com
.ibm
.wala
.classLoader
.BinaryDirectoryTreeModule
;
63 import com
.ibm
.wala
.classLoader
.EclipseSourceFileModule
;
64 import com
.ibm
.wala
.classLoader
.JarFileModule
;
65 import com
.ibm
.wala
.classLoader
.Module
;
66 import com
.ibm
.wala
.classLoader
.SourceDirectoryTreeModule
;
67 import com
.ibm
.wala
.classLoader
.SourceFileModule
;
68 import com
.ibm
.wala
.core
.tests
.callGraph
.CallGraphTestUtil
;
69 import com
.ibm
.wala
.eclipse
.util
.CancelException
;
70 import com
.ibm
.wala
.eclipse
.util
.EclipseProjectPath
;
71 import com
.ibm
.wala
.ipa
.callgraph
.AnalysisCache
;
72 import com
.ibm
.wala
.ipa
.callgraph
.AnalysisOptions
;
73 import com
.ibm
.wala
.ipa
.callgraph
.AnalysisScope
;
74 import com
.ibm
.wala
.ipa
.callgraph
.CallGraph
;
75 import com
.ibm
.wala
.ipa
.callgraph
.CallGraphBuilder
;
76 import com
.ibm
.wala
.ipa
.callgraph
.Entrypoint
;
77 import com
.ibm
.wala
.ipa
.callgraph
.impl
.Util
;
78 import com
.ibm
.wala
.ipa
.callgraph
.propagation
.PointerAnalysis
;
79 import com
.ibm
.wala
.ipa
.cha
.IClassHierarchy
;
80 import com
.ibm
.wala
.properties
.WalaProperties
;
81 import com
.ibm
.wala
.util
.debug
.Assertions
;
82 import com
.ibm
.wala
.util
.debug
.UnimplementedError
;
84 import edu
.berkeley
.cs
.bodik
.svelte
.plugin
.EclipseJdtUtils
;
87 * A SvelteAnalysisEngine simplifies the process of setting up the analysis scope and getting the
88 * call graph and pointer analysis. To get a CallGraph and PointerAnalysis, add the files you wish
89 * to analyze (e.g. with <code>addSourceDir()</code> and
90 * <code>addJar()<code>, and define the entrypoints. You should probably
91 * also add <code>setExclusionsFile()</code>. You may then <code>getCallGraph()</code> and
92 * <code>getPointerAnalysis()</code>, which implicitly build the call graph if it has not
93 * been build with <code>build()</code>.
98 public class SvelteAnalysisEngine
extends JdtJavaSourceAnalysisEngine
{
100 // /////////////////////////////////////////
101 // /// RT JAR FINDER -- SHOULD REPLACE /////
102 // /////////////////////////////////////////
104 // TODO: why does this throw NullPointerException ? ...
105 // TODO: simplify. all we need is rtJar, get rid of special WALA stuff
106 // All this does is figure out the Java System libraries... what a waste...
107 protected static String javaHomePath
;
108 public static List
<String
> rtJar
;
110 boolean found
= false;
112 rtJar
= new LinkedList
<String
>();
114 Properties p
= WalaProperties
.loadProperties();
115 javaHomePath
= p
.getProperty(WalaProperties
.J2SE_DIR
);
117 if (new File(javaHomePath
).isDirectory()) {
118 if ("Mac OS X".equals(System
.getProperty("os.name"))) { // nick
120 * todo: {@link WalaProperties#getJ2SEJarFiles()}
122 rtJar
.add(javaHomePath
+ "/Classes/classes.jar");
123 rtJar
.add(javaHomePath
+ "/Classes/ui.jar");
125 rtJar
.add(javaHomePath
+ File
.separator
+ "classes.jar");
126 rtJar
.add(javaHomePath
+ File
.separator
+ "rt.jar");
127 rtJar
.add(javaHomePath
+ File
.separator
+ "core.jar");
128 rtJar
.add(javaHomePath
+ File
.separator
+ "vm.jar");
132 } catch (Exception e
) {
137 javaHomePath
= System
.getProperty("java.home");
138 if ("Mac OS X".equals(System
.getProperty("os.name"))) { // nick
139 rtJar
.add(javaHomePath
+ "/../Classes/classes.jar");
140 rtJar
.add(javaHomePath
+ "/../Classes/ui.jar");
142 rtJar
.add(javaHomePath
+ File
.separator
+ "lib" + File
.separator
+ "rt.jar");
143 rtJar
.add(javaHomePath
+ File
.separator
+ "lib" + File
.separator
+ "core.jar");
144 rtJar
.add(javaHomePath
+ File
.separator
+ "lib" + File
.separator
+ "vm.jar");
145 rtJar
.add(javaHomePath
+ File
.separator
+ "lib" + File
.separator
+ "classes.jar");
150 // //////////////////////////////////////////////////////
151 // /// CORE -- CONTRUCTOR AND ANALSYSIS SCOPE SETUP /////
152 // //////////////////////////////////////////////////////
154 protected boolean built
= false;
155 protected CallGraph cg
;
158 protected String mainClassDescriptors
[] = null;
161 * Default constructor. By default, only system jars are added to analysis scope.
163 public SvelteAnalysisEngine() {
164 setExclusionsFile(CallGraphTestUtil
.REGRESSION_EXCLUSIONS
);
165 // setExclusionsFile("dat/Java60RegressionExclusions.txt");
168 public void addRtJar() {
169 for (String lib
: rtJar
) {
170 File libFile
= new File(lib
);
171 if (libFile
.exists()) {
173 addSystemModule(new JarFileModule(new JarFile(libFile
)));
174 } catch (IOException e
) {
181 // called by some WALA thing when making call graph
183 protected Iterable
<Entrypoint
> makeDefaultEntrypoints(AnalysisScope scope
, IClassHierarchy cha
) {
184 if (mainClassDescriptors
== null)
185 throw new UnimplementedError(
186 "Cannot use SvelteAnalysisEngine without defining entrypoints!");
187 return Util
.makeMainEntrypoints(EclipseProjectPath
.SOURCE_REF
, cha
, mainClassDescriptors
);
191 * Tell the analysis engine the entrypoints for the call graph. Given a fully qualified
192 * classname, this function will look for a method
193 * <code>public static void main(String[])</code> in the classname and use that as the sole
196 * @param packageAndClass
197 * A fully qualified class name, such as "com.example.mypackage.MyClass"
200 public void findEntrypointFromClassnameOfMain(String packageAndClass
) {
201 mainClassDescriptors
= new String
[] { "L" + packageAndClass
.replace('.', '/') };
205 * Tell the analysis engine the entrypoints for the call graph. Given a fully qualified
206 * classname, this function will look for a method
207 * <code>public static void main(String[])</code> in the classname and use that as the sole
210 * @param packageAndClass
211 * A fully qualified class name, such as "com.example.mypackage.MyClass"
214 public void findEntrypointFromClassnamesOfMain(Collection
<String
> packagesAndClasses
) {
215 mainClassDescriptors
= new String
[packagesAndClasses
.size()];
217 for (String s
: packagesAndClasses
) {
218 mainClassDescriptors
[i
++] = "L" + s
.replace('.', '/');
222 public boolean isBuilt() {
226 public void build() {
231 public void rebuild() {
233 cg
= buildDefaultCallGraph();
235 } catch (CancelException e
) {
236 // TODO probably should just throw this.
238 } catch (IllegalArgumentException e
) {
239 // TODO what to do here and below?
241 } catch (IOException e
) {
247 public CallGraph
getCallGraph() {
254 public PointerAnalysis
getPointerAnalysis() {
257 return super.getPointerAnalysis();
260 // ////////////////////////////////////////////////////////
261 // /// ADD SOURCE & BINARY CODE TO THE ANALYSIS SCOPE /////
262 // ////////////////////////////////////////////////////////
265 * Add the specified jar file to the analysis scope with addCompiledModule()
268 * @throws IOException
270 public void addJar(String path
) throws IOException
{
271 File f
= new File(path
);
273 throw new FileNotFoundException("SvelteAnalysisEnginge.addJar: Couldn't find jar "
275 addCompiledModule(new JarFileModule(new JarFile(f
)));
279 * Add the specified jar file to the analysis scope with addSystemModule()
282 * @throws IOException
284 public void addSystemJar(String path
) throws IOException
{
285 File f
= new File(path
);
287 throw new FileNotFoundException("SvelteAnalysisEnginge.addJar: Couldn't find jar "
289 addSystemModule(new JarFileModule(new JarFile(f
)));
293 * Add the specified directory of binary .class files to the analysis scope.
296 * Directory name should be the root of a package hierarchy, i.e.
297 * com.example.mypackage.MyClass should be found in <code>path</code>/com/example/mypackage/MyClass.class
299 * @throws FileNotFoundException
301 public void addClassDir(String path
) throws IOException
{
302 File f
= new File(path
);
304 throw new FileNotFoundException();
305 addCompiledModule(new BinaryDirectoryTreeModule(f
));
309 * Add the specified directory full of .java files to the analysis scope. All .java files in the
310 * directory tree will be analyzed with WALA CAst (Polyglot)
313 * @throws FileNotFoundException
315 public void addJavaDir(String path
) throws IOException
{
316 File f
= new File(path
);
318 throw new FileNotFoundException();
319 addSourceModule(new SourceDirectoryTreeModule(f
));
322 public void addJavaDir(IPath path
) throws IOException
{
323 addJavaDir(path
.toOSString());
327 * Add the Java directory referenced by <code>path</code> to the analysis scope, but do not
328 * include any Java files referenced in <code>exceptions</code>, referenced relatively
331 * The path of the directory containing *.java source files.
334 * Java files to specifically not add in the analysis scope. They should by relative
335 * paths, relative to the directory path, e.g. if I want to add
336 * /home/evan/myproj/src, but not /home/evan/myproj/src/foo/Foo.java, an exception
337 * string would be "foo/Foo.java"
339 * @throws IOException
341 public void addJavaDirExcept(final String path
, final String exceptions
[]) throws IOException
{
342 File f
= new File(path
);
344 throw new FileNotFoundException();
345 SourceDirectoryTreeModule sdtm
= new SourceDirectoryTreeModule(f
) {
347 protected boolean includeFile(File file
) {
348 if (!super.includeFile(file
))
350 for (int i
= 0; i
< exceptions
.length
; i
++) {
351 if (file
.compareTo(new File(path
+ exceptions
[i
])) == 0)
357 addSourceModule(sdtm
);
361 * Add the specified .java file to the analysis scope.
364 * @throws FileNotFoundException
366 public void addJavaFile(String path
) throws IOException
{
367 File f
= new File(path
);
369 throw new FileNotFoundException();
371 addSourceModule(new SourceFileModule(f
, f
.getName()));
375 * Add the specified .jar files to the analysis scope.
378 * @throws FileNotFoundException
381 public void addJars(String
[] jarfiles
) throws IOException
{
382 String failedjars
= "";
383 for (String jf
: jarfiles
)
386 } catch (IOException e
) {
387 failedjars
+= " " + jf
;
389 if (!failedjars
.equals(""))
390 throw new FileNotFoundException("Couldn't find jars: " + failedjars
);
394 * Add the specified .jar files to the analysis scope.
397 * @throws FileNotFoundException
400 public void addJars(Iterable
<String
> jarfiles
) throws IOException
{
401 String failedjars
= "";
402 for (String jf
: jarfiles
)
405 } catch (IOException e
) {
406 failedjars
+= " " + jf
;
408 if (!failedjars
.equals(""))
409 throw new FileNotFoundException("Couldn't find jars: " + failedjars
);
412 // ////////////////////////////////////////////////////////////
413 // /// ECLIPSE-PROJECT-BASED ADDITION OF SOURCES/BINARIES /////
414 // ////////////////////////////////////////////////////////////
417 protected IPath
makeAbsolute(IPath p
) {
418 if (p
.toFile().exists()) {
421 return EclipseJdtUtils
.getAbsolutePath(p
); // workspace path
424 public void addEclipseProjectSource(IJavaProject javaProject
) {
425 ArrayList
<IFile
> files
;
427 files
= EclipseJdtUtils
.getProjectCompilationUnits(javaProject
);
428 for (IFile file
: files
)
429 addSourceModule(new EclipseSourceFileModule(file
));
430 } catch (JavaModelException e
) {
432 Assertions
.UNREACHABLE("SvelteAnalysisEngine.addProjectSource");
437 public void addClasspathEntry(IClasspathEntry cpe
, boolean usePolyglot
) throws IOException
{
438 boolean pathAbsolute
= cpe
.getPath().toFile().exists();
440 if (cpe
.getEntryKind() == IClasspathEntry
.CPE_SOURCE
) {
441 // System.out.println("DEBUG: adding CPE_SOURCE " +
442 // makeAbsolute(cpe.getPath()).toOSString());
445 addJavaDir(EclipseJdtUtils
.getAbsolutePath(cpe
)); // done in add EclipseClassPth for jdt
446 } else if (cpe
.getEntryKind() == IClasspathEntry
.CPE_LIBRARY
) {
447 // System.out.println("DEBUG: adding CPE_LIBRARY " +
448 // makeAbsolute(cpe.getPath()).toOSString());
450 File file
= makeAbsolute(cpe
.getPath()).toFile();
452 if (file
.isDirectory())
453 m
= new BinaryDirectoryTreeModule(file
);
455 m
= new JarFileModule(new JarFile(file
));
458 // libraries with absolute paths are assumed to be "system" jars
460 // System.out.println("(as system)");
463 // System.out.println("(as compiled)");
464 addCompiledModule(m
);
466 } else if (cpe
.getEntryKind() == IClasspathEntry
.CPE_PROJECT
) {
467 // TODO -- add as source if not using shrike, maybe.
468 // addClassDir(makeAbsolute(cpe.getPath()).toOSString()); // could
471 IProject project
= (IProject
) ResourcesPlugin
.getWorkspace().getRoot().findMember(
473 addEclipseClasspaths(JavaCore
.create(project
), true, usePolyglot
, true);
478 public void addEclipseClasspaths(IJavaProject project
, boolean useShrike
) {
479 addEclipseClasspaths(project
, useShrike
, false, false);
481 public void addEclipseClasspaths(IJavaProject project
, boolean useShrike
, boolean usePolyglot
) {
482 addEclipseClasspaths(project
, useShrike
, usePolyglot
, false);
485 public void addEclipseClasspaths(IJavaProject project
, boolean useShrike
, boolean usePolyglot
, boolean onlyExported
) {
486 if ( !useShrike
&& !usePolyglot
)
487 addEclipseProjectSource(project
);
489 IClasspathEntry
[] classpaths
= project
.getResolvedClasspath(true);
490 for (IClasspathEntry cpe
: classpaths
) {
492 if (!(cpe
.getEntryKind() == IClasspathEntry
.CPE_SOURCE
&& useShrike
))
493 if (cpe
.isExported() || !onlyExported
)
494 addClasspathEntry(cpe
, usePolyglot
);
495 } catch (IOException e
) {
501 // System.out.println("adding binary directory " +
502 // makeAbsolute(project.getOutputLocation()).toOSString());
503 addClassDir(makeAbsolute(project
.getOutputLocation()).toOSString());
504 } catch (IOException e
) {
507 } catch (JavaModelException e
) {
514 protected CallGraphBuilder
getCallGraphBuilder(IClassHierarchy cha
, AnalysisOptions options
,
515 AnalysisCache cache
) {
516 return new ZeroOneContainerCFABuilderFactory().make(options
, cache
, cha
, scope
, false);