It is irrational that argument "--main-class" requires not null
djaekim opened this issue · 16 comments
Hello =)
I am trying to run tai-e on a jar project I downloaded from this link. Specifically on commons-io-2.9.0-test-sources.jar.
To run this, I used following argument below.
This is the path of the .jar
-cp "XXX/XX/jar/commons-io-2.9.0-test-sources.jar"
This is the path of the .class file
--input-classes="org/apache/commons/io/input/BoundedInputStreamTest.class"
This is just trying to reproduce example posted on your documentation
-a pta=cs:2-type;merge-string-constants:true
Unfortunately, I got errors below. I was wondering if you could help me to resolve this issue?
Tai-e starts ...
Writing options to output\options.yml
Writing analysis plan to output\tai-e-plan.yml
WorldBuilder starts ...
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.charAt(int)" because "option" is null
at soot.options.Options.parse(Options.java:136)
at soot.Main.processCmdLine(Main.java:85)
at soot.Main.run(Main.java:248)
at pascal.taie.frontend.soot.SootWorldBuilder.runSoot(SootWorldBuilder.java:246)
at pascal.taie.frontend.soot.SootWorldBuilder.build(SootWorldBuilder.java:73)
at pascal.taie.Main.lambda$buildWorld$3(Main.java:121)
at pascal.taie.util.Timer.lambda$runAndCount$0(Timer.java:112)
at pascal.taie.util.Timer.runAndCount(Timer.java:93)
at pascal.taie.util.Timer.runAndCount(Timer.java:111)
at pascal.taie.util.Timer.runAndCount(Timer.java:107)
at pascal.taie.Main.buildWorld(Main.java:116)
at pascal.taie.Main.lambda$main$0(Main.java:55)
at pascal.taie.util.Timer.lambda$runAndCount$0(Timer.java:112)
at pascal.taie.util.Timer.runAndCount(Timer.java:93)
at pascal.taie.util.Timer.runAndCount(Timer.java:111)
at pascal.taie.util.Timer.runAndCount(Timer.java:107)
at pascal.taie.Main.main(Main.java:48)
Process finished with exit code 1
Thank you so much!
This is the path of the .class file
--input-classes="org/apache/commons/io/input/BoundedInputStreamTest.class"
An obvious issue is that argument --input-classes
should follow the format of fully-qualified name in Java, e.g., org.apache.commons.io.input.BoundedInputStreamTest
but not org/apache/commons/io/input/BoundedInputStreamTest.class
.
After changing it to fully qualified name. I still get the same error.
Could you provide the full arguments you used?
Could you provide the fully arguments you used?
-cp XX\jar\commons-io-2.9.0-test-sources.jar --input-classes="org.apache.commons.io.input.BoundedInputStreamTest" -a pta=cs:2-type;merge-string-constants:true
Thank you!
-cp XX\jar\commons-io-2.9.0-test-sources.jar --input-classes="org.apache.commons.io.input.BoundedInputStreamTest" -a pta=cs:2-type;merge-string-constants:true
Hi!
-m
is currently required not null (We will solve this issue shortly, then inform you).
In your scene, a temporary solution now is to choose one of --input-classes
as -m
. That is, with arguments -cp XX\jar\commons-io-2.9.0-test-sources.jar --input-classes=org.apache.commons.io.input.BoundedInputStreamTest -m org.apache.commons.io.input.BoundedInputStreamTest -a pta=cs:2-type;merge-string-constants:true
, Tai-e will run normally.
Hi thank you so much,
I tried to run it based on your suggestion with args below:
-cp XX\jar\commons-io-2.9.0-test-sources.jar --input-classes="org.apache.commons.io.input.BoundedInputStreamTest" -m "org.apache.commons.io.input.BoundedInputStreamTest" -a pta=cs:2-type;merge-string-constants:true
However, there was another error
Exception in thread "main" soot.JavaClassProvider$JarException: Class org.apache.commons.io.input.BoundedInputStreamTest was found in an archive, but Soot doesn't support reading source files out of an archive
at soot.JavaClassProvider.find(JavaClassProvider.java:75)
at soot.SourceLocator.getClassSource(SourceLocator.java:187)
at soot.Scene.tryLoadClass(Scene.java:969)
at soot.Scene.loadBasicClasses(Scene.java:1713)
at soot.Scene.loadNecessaryClasses(Scene.java:1806)
at soot.Main.run(Main.java:254)
at pascal.taie.frontend.soot.SootWorldBuilder.runSoot(SootWorldBuilder.java:247)
Thank you,
kim
I will take a deep look at this issue later.
Currently, a workaround is to pass the decompressed directory (not a jar file) as class path
.
Exception in thread "main" soot.JavaClassProvider$JarException: Class org.apache.commons.io.input.BoundedInputStreamTest was found in an archive, but Soot doesn't support reading source files out of an archive at soot.JavaClassProvider.find(JavaClassProvider.java:75) at soot.SourceLocator.getClassSource(SourceLocator.java:187) at soot.Scene.tryLoadClass(Scene.java:969) at soot.Scene.loadBasicClasses(Scene.java:1713) at soot.Scene.loadNecessaryClasses(Scene.java:1806) at soot.Main.run(Main.java:254) at pascal.taie.frontend.soot.SootWorldBuilder.runSoot(SootWorldBuilder.java:247)
In the above exception, the Soot’s frontend doesn't support reading Java source files out of an archive. So we need pass the decompressed directory (but not a jar) as class path.
In addition, as stated below, we recommend analyzing the bytecode for real-world program. In your case, is that using commons-io-2.9.0-tests.jar instead of commons-io-2.9.0-test-sources.jar? Maybe so, I guess.
Soot’s frontend for Java source files is outdated (only partially supports Java version up to 7) and not very robust. Meanwhile, Soot’s frontend for bytecode files, which does not keep variable names though, is more robust (it virtually works well for the .class files compiled by up to Java 17) than the frontend for Java source files. Thus, for real-world applications, Tai-e usually analyzes bytecode.
-m is currently required not null (We will solve this issue shortly, then inform you).
After the commit d9784e3, it only requires that at least one of --main-class
and --input-classes
be specifie.
That means -m
can be ignored in your case. (You can try on the latest commit)
No response for more than 7 days.
Closing now.
Hello, I apologize for the delay.
For running real world project, I want to run, for instance, inter-procedural analysis for each individual Junit Test Case to see how data might flow from and to the specific test case.
To do this, I want to get minimal execution using existing analyzer before writing some custom analyzer. I am still having trouble running this.
If I want to analyze a specific Junit method (not necessarily static main method), how would I go about instrumenting it?
Currently, my cmd looks like this
-cp C:\Users\djaek\Documents\PhD\Inheritance\inheritance_extractor\analysis_python\jar\some.jar ----input-classes=org.apache.commons.io.input.BoundedInputStreamTest -a pta=cs:2-type;merge-string-constants:true
However, there was issue with was that it must be decompressed or something.
I was wondering, what would be the exact step to go about this?
If I want to analyze a specific Junit method (not necessarily static main method), how would I go about instrumenting it?
see #9.
However, there was issue with was that it must be decompressed or something.
It is not clear I cannot get what you mean. Exception infomation should be provided if it exists.
Hi, I am still getting the same error, when executing command below
--class-path
C:\\Users\\djaek\\Documents\\PhD\\Inheritance\\inheritance_extractor\\analysis_python\\jar\\commons-collections\\
--input-classes=org.apache.commons.collections4.functors.AllPredicateTest
--analysis
pta=cs:2-type
the -class-path is the directory to bytecode
"C:\Program Files\Java\jdk-18.0.2\bin\java.exe" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:55685,suspend=y,server=n -javaagent:C:\Users\djaek\AppData\Local\JetBrains\IdeaIC2022.2\captureAgent\debugger-agent.jar=file:/C:/Users/djaek/AppData/Local/Temp/capture.props -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath "C:\Users\djaek\Documents\...\analysis_python\Snapshot_Analysis\Tai-e\out\production\classes;C:\Users\djaek\Documents\...\Snapshot_Analysis\Tai-e\out\production\resources;C:\Users\djaek\Documents\...\Snapshot_Analysis\Tai-e\lib\sootclasses-modified.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\info.picocli\picocli\4.6.1\49a67ee4b4d9722fa60f3f9ffaffa72861c32966\picocli-4.6.1.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-core\2.16.0\ca12fb3902ecfcba1e1357ebfc55407acec30ede\log4j-core-2.16.0.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.16.0\4727d93a76616ffc4149dffac5801827c0f4ac71\log4j-api-2.16.0.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.dataformat\jackson-dataformat-yaml\2.12.2\8c549fb29f390f6fd0c20cf0a1d83f7e38dc7ffb\jackson-dataformat-yaml-2.12.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.soot-oss\soot\4.3.0-20211223.212205-256\649b6b2af64434fb2659343f06d2893cd25ace91\soot-4.3.0-20211223.212205-256.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-nop\1.7.5\3482f4546a52dc63d0c8e829338f26a77e5eab1b\slf4j-nop-1.7.5.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.12.2\5f9d79e09ebf5d54a46e9f4543924cf7ae7654e0\jackson-databind-2.12.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.12.2\8df50138521d05561a308ec2799cc8dda20c06df\jackson-core-2.12.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.yaml\snakeyaml\1.27\359d62567480b07a679dc643f82fc926b100eed5\snakeyaml-1.27.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\commons-io\commons-io\2.7\3f2bd4ba11c4162733c13cc90ca7c7ea09967102\commons-io-2.7.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.smali\dexlib2\2.5.2\8b664182af455b0757a7f59a42020fa5608c7d0e\dexlib2-2.5.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-util\9.2\fbc178fc5ba3dab50fd7e8a5317b8b647c8e8946\asm-util-9.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-commons\9.2\f4d7f0fc9054386f2893b602454d48e07d4fbead\asm-commons-9.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-tree\9.2\d96c99a30f5e1a19b0e609dbb19a44d8518ac01e\asm-tree-9.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm\9.2\81a03f76019c67362299c40e0ba13405f5467bff\asm-9.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\xmlpull\xmlpull\1.1.3.4d_b4_min\6dcdbef481ff8fbac336a47048048b2b31855015\xmlpull-1.1.3.4d_b4_min.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\de.upb.cs.swt\axml\2.1.0-SNAPSHOT\32374202d6343f6d0de434918469aa7316017168\axml-2.1.0-SNAPSHOT.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\ca.mcgill.sable\polyglot\2006\f0e528051faa260d83f53d58275954d973231ce7\polyglot-2006.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\de.upb.cs.swt\heros\1.2.3-SNAPSHOT\bdea1884d3f1ec9d57dbc03ca99cb17ef5c0819d\heros-1.2.3-SNAPSHOT.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\ca.mcgill.sable\jasmin\3.0.3-SNAPSHOT\573ac2f66d968fd40898b6458e888f2b56351e1d\jasmin-3.0.3-SNAPSHOT.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.slf4j\slf4j-api\1.7.32\cdcff33940d9f2de763bc41ea05a0be5941176c3\slf4j-api-1.7.32.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\javax.annotation\javax.annotation-api\1.3.2\934c04d3cfef185a8008e7bf34331b79730a9d43\javax.annotation-api-1.3.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\jaxb-runtime\2.4.0-b180830.0438\2a0705ce8aa988b691c70e8bdcc1613050a148a2\jaxb-runtime-2.4.0-b180830.0438.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\javax.xml.bind\jaxb-api\2.4.0-b180830.0359\b54184b7dcab2031add3f525550c7f1b7e12209d\jaxb-api-2.4.0-b180830.0359.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-annotations\2.12.2\a770cc4c0a1fb0bfd8a150a6a0004e42bc99fca\jackson-annotations-2.12.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.ow2.asm\asm-analysis\9.2\7487dd756daf96cab9986e44b9d7bcb796a61c10\asm-analysis-9.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.functionaljava\functionaljava\4.2\f26bdd90a8d6b6faeb38ab2ba4c39580c1eb989f\functionaljava-4.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\ca.mcgill.sable\java_cup\0.9.2\f36b758580fb9d472bfd5965aa9ac807fa66d242\java_cup-0.9.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\javax.activation\javax.activation-api\1.2.0\85262acf3ca9816f9537ca47d5adeabaead7cb16\javax.activation-api-1.2.0.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.glassfish.jaxb\txw2\2.4.0-b180830.0438\31bae7fb5924472b3243b265b47cb741da715419\txw2-2.4.0-b180830.0438.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.sun.istack\istack-commons-runtime\3.0.7\c197c86ceec7318b1284bffb49b54226ca774003\istack-commons-runtime-3.0.7.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.jvnet.staxex\stax-ex\1.8\8cc35f73da321c29973191f2cf143d29d26a1df7\stax-ex-1.8.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.sun.xml.fastinfoset\FastInfoset\1.2.15\bb7b7ec0379982b97c62cd17465cb6d9155f68e8\FastInfoset-1.2.15.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.google.guava\failureaccess\1.0.1\1dcf1de382a0bf95a3d8b0849546c88bac1292c9\failureaccess-1.0.1.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.google.guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\b421526c5f297295adef1c886e5246c39d4ac629\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.google.code.findbugs\jsr305\3.0.2\25ea2e8b0c338a877313bd4672d3fe056ea78f0d\jsr305-3.0.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\27.1-android\a80ef47421d6607e749f8b7282dd7dee61adfea7\guava-27.1-android.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.checkerframework\checker-compat-qual\2.5.2\dc0b20906c9e4b9724af29d11604efa574066892\checker-compat-qual-2.5.2.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.google.errorprone\error_prone_annotations\2.2.0\88e3c593e9b3586e1c6177f89267da6fc6986f0c\error_prone_annotations-2.2.0.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\com.google.j2objc\j2objc-annotations\1.1\ed28ded51a8b1c6b112568def5f4b455e6809019\j2objc-annotations-1.1.jar;C:\Users\djaek\.gradle\caches\modules-2\files-2.1\org.codehaus.mojo\animal-sniffer-annotations\1.17\f97ce6decaea32b36101e37979f8b647f00681fb\animal-sniffer-annotations-1.17.jar;C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.2.1\lib\idea_rt.jar" pascal.taie.Main --class-path "C:\\Users\\djaek\\Documents\\...\\jar\\commons-collections\\\\" --input-classes=org.apache.commons.collections4.functors.AllPredicateTest --analysis pta=cs:2-type;only-app:true
Connected to the target VM, address: '127.0.0.1:55685', transport: 'socket'
Tai-e starts ...
Writing options to output\options.yml
Writing analysis plan to output\tai-e-plan.yml
WorldBuilder starts ...
java-benchmarks\JREs\jre1.6\jce.jar;java-benchmarks\JREs\jre1.6\jsse.jar;java-benchmarks\JREs\jre1.6\rt.jar;C:\\Users\\djaek\\Documents\\PhD\\Inheritance\\inheritance_extractor\\analysis_python\\jar\\commons-collections\\
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.charAt(int)" because "option" is null
at soot.options.Options.parse(Options.java:136)
at soot.Main.processCmdLine(Main.java:85)
at soot.Main.run(Main.java:248)
at pascal.taie.frontend.soot.SootWorldBuilder.runSoot(SootWorldBuilder.java:247)
at pascal.taie.frontend.soot.SootWorldBuilder.build(SootWorldBuilder.java:74)
at pascal.taie.Main.lambda$buildWorld$3(Main.java:121)
at pascal.taie.util.Timer.lambda$runAndCount$0(Timer.java:112)
at pascal.taie.util.Timer.runAndCount(Timer.java:93)
at pascal.taie.util.Timer.runAndCount(Timer.java:111)
at pascal.taie.util.Timer.runAndCount(Timer.java:107)
at pascal.taie.Main.buildWorld(Main.java:116)
at pascal.taie.Main.lambda$main$0(Main.java:55)
at pascal.taie.util.Timer.lambda$runAndCount$0(Timer.java:112)
at pascal.taie.util.Timer.runAndCount(Timer.java:93)
at pascal.taie.util.Timer.runAndCount(Timer.java:111)
at pascal.taie.util.Timer.runAndCount(Timer.java:107)
at pascal.taie.Main.main(Main.java:48)
Disconnected from the target VM, address: '127.0.0.1:55685', transport: 'socket'
Finally, I really appreciate the documentations, but I am still having trouble running a simple example. I was wondering if it would be possible to make available some kind of complete example on analyzing a real world apache project, where it runs some reproducible analysis example from start to finish. I feel like this would help make better accessibility of the features. Thank you.
at pascal.taie.frontend.soot.SootWorldBuilder.runSoot(SootWorldBuilder.java:247) at pascal.taie.frontend.soot.SootWorldBuilder.build(SootWorldBuilder.java:74)
I notice that the line number of method runSoot
in the stack frame is line 247.
It seems to imply that the Tai-e you are using is under this commit 9d9d15a but not d9784e3 (as I mentioned in #7 (comment)).
Tai-e/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java
Lines 244 to 248 in 9d9d15a
Tai-e/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java
Lines 252 to 256 in d9784e3
Could you pull the latest code and try it again?
at pascal.taie.frontend.soot.SootWorldBuilder.runSoot(SootWorldBuilder.java:247) at pascal.taie.frontend.soot.SootWorldBuilder.build(SootWorldBuilder.java:74)
I notice that the line number of method
runSoot
in the stack frame is line 247.It seems to imply that the Tai-e you are using is under this commit 9d9d15a but not d9784e3 (as I mentioned in #7 (comment)).
Tai-e/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java
Lines 244 to 248 in 9d9d15a
Tai-e/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java
Lines 252 to 256 in d9784e3
Could you pull the latest code and try it again?
Thank you, it's working now.
Another question I have is I want to use plugin to analyze specific Junit Test Method. What is the general step done to do that? I tried to use existing plugin just as a proof-of-concept. Tai-e\src\main\java\pascal\taie\analysis\pta\plugin\taint\TaintAnalysis.java
For example, let's say my -input-classes="some test.java file to analyze". To access this class's Junit method in the in the TaintAnalysis's onStart to add to the solver.addEntryPoint(), I used below code. It that ok?
Iterable<JClass> iterable = World.get().getClassHierarchy().applicationClasses()::iterator;
for (JClass s : iterable) {
for(JMethod m : s.getDeclaredMethods()){
solver.addEntryPoint(new EntryPoint(m,
new MainEntryPointParamProvider(m, solver)));
}
}
I am also using
-cp
\repo\dubbo\
--input-classes=dubbo-cluster.target.test-classes.org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalanceTest
-a
"pta=action:dump;action-file:output.dump"
-ap
-scope
REACHABLE
I used -ap because I only want to analyze specific junit file, but this file depends on other files. Would this affect analysis? For example, I got the below logs.
Another question I have is, for this above analysis, it gave an output.dump that is for entire source code, but not the specified files. How to only get output for the specified files?
Another question I have is I want to use plugin to analyze specific Junit Test Method. What is the general step done to do that?
Refer to wiki, #9, write a plugin of your own, and activate it.
For example, let's say my -input-classes="some test.java file to analyze". To access this class's Junit method in the in the TaintAnalysis's onStart to add to the solver.addEntryPoint(), I used below code. It that ok?
Iterable<JClass> iterable = World.get().getClassHierarchy().applicationClasses()::iterator; for (JClass s : iterable) { for(JMethod m : s.getDeclaredMethods()){ solver.addEntryPoint(new EntryPoint(m, new MainEntryPointParamProvider(m, solver))); } }
It seems that this would treat all methods of all classes in the World (the classes being analyzed) as public static void main(String[] args)
. I don't think it's what you want. Maybe you can take the following steps:
-
Gets the specific class from ClassHierarchy, e.g., by
World.get().getClassHierarchy().getClass("org.apache.commons.collections4.functors.AllPredicateTest");
-
Gets all methods in the class and filters out the ones with the
@Test
annotation. May need to usepascal.taie.language.classes.JClass#getDeclaredMethods
andpascal.taie.language.classes.ClassMember#hasAnnotation
. -
Adds entrypoint by
pascal.taie.analysis.pta.core.solver.Solver#addEntryPoint
. Note that you may need to mock the parameters of the method. See alsopascal.taie.analysis.pta.core.solver.ParamProvider
and its three subclasses.
I used -ap because I only want to analyze specific junit file, but this file depends on other files. Would this affect analysis? For example, I got the below logs.
See #3.
Another question I have is, for this above analysis, it gave an output.dump that is for entire source code, but not the specified files. How to only get output for the specified files?
There is no option to support this action. If you want to filter the pointers to be dumped, consider modifying the following code:
Tai-e/src/main/java/pascal/taie/analysis/pta/plugin/ResultProcessor.java
Lines 178 to 185 in 283d1ef