2017-06-08 3 views
6

Ich schreibe ein IntelliJ-Plugin, um Java-Programmcode zu analysieren. So benutze ich Soot um statische Analysen zu schreiben. Jedes Mal, wenn ein Benutzer die Analyse-Aktion meines Plugin löst, nehme ich den aktuellen VirtualFile des aktuellen Kontext wie folgt aus:Ruß: Reload Klasse nach Quelldatei geändert

FileEditorManager manager = FileEditorManager.getInstance(e.getProject()); 
VirtualFile files[] = manager.getSelectedFiles(); 
toAnalyse = files[0]; [...] 

Wenn ich überprüfen den Inhalt dieser Datei werden alle Änderungen übernommen werden. Danach lade ich die Klasse, die ich analysieren möchte, in Soot.

String dir = toAnalyse.getParent().getPath() ; 
Options.v().setPhaseOption("jb", "use-original-names"); 
Options.v().set_soot_classpath(System.getProperty("java.home")+";"+ dir); 
c = Scene.v().loadClassAndSupport(name); 
/*no analyse c*/ 

Das funktioniert perfekt für mich. Aber jetzt zu meinem Problem: Wenn ich etw. in Testinstanz meines Plugins und die gleiche Analyse erneut auslösen, ändert sich nichts.

Was habe ich bisher versucht?

Ich habe folgende Optionen:

Options.v().set_dump_body(Arrays.asList("jb")); 
Options.v().set_dump_cfg(Arrays.asList("jb")); 
Options.v().set_allow_phantom_refs(true); 
Options.v().set_whole_program(true); 

ich auch alle Klassen von Hand entfernt

wie folgt aus:

Chain<SootClass> classes = Scene.v().getClasses(); 
Stack<SootClass> stack = new Stack<>(); 
for(SootClass s : classes) 
    stack.push(s); 
while(!stack.empty()) 
    Scene.v().removeClass(stack.pop()); 

und fing wieder an das Programm.

Antwort

5

Ich löste dieses Problem.

SootClass c = Scene.v().loadClassAndSupport(name); 
// ... 
c.setResolvingLevel(0); 
G.reset(); 

G.reset() setzt alle Singleton-Instanzen. Daher werden alle zwischengespeicherten Ergebnisse durch erneutes Aufrufen dieser Aktion überschrieben.

public static Scene v() { 
    return G.v().soot_Scene(); 
} 

this.instance_soot_Scene ist null nach G.reset() Aufruf.

daher der folgende Code:

public Scene soot_Scene() { 
    if(this.instance_soot_Scene == null) { 
     synchronized(this) { 
      if(this.instance_soot_Scene == null) { 
       this.instance_soot_Scene = new Scene(this.g); 
      } 
     } 
    } 

    return this.instance_soot_Scene; 
} 

gibt eine neue Instanz mit einer leeren Ergebnis-Cache.