13
13
14
14
package com .ibm .northstar ;
15
15
16
-
17
16
import com .github .javaparser .Problem ;
17
+ import com .google .common .reflect .TypeToken ;
18
18
import com .google .gson .*;
19
19
import com .ibm .northstar .entities .JavaCompilationUnit ;
20
20
import com .ibm .northstar .utils .BuildProject ;
27
27
import picocli .CommandLine .Option ;
28
28
29
29
import java .io .File ;
30
+ import java .io .FileReader ;
30
31
import java .io .FileWriter ;
31
32
import java .io .IOException ;
33
+ import java .lang .reflect .Type ;
32
34
import java .nio .file .Files ;
33
35
import java .nio .file .Path ;
34
36
import java .nio .file .Paths ;
@@ -44,6 +46,9 @@ public class CodeAnalyzer implements Runnable {
44
46
@ Option (names = {"-i" , "--input" }, description = "Path to the project root directory." )
45
47
private static String input ;
46
48
49
+ @ Option (names = {"-t" , "--target-files" }, description = "Paths to files to be analyzed from the input application." )
50
+ private static List <String > targetFiles ;
51
+
47
52
@ Option (names = {"-s" , "--source-analysis" }, description = "Analyze a single string of java source code instead the project." )
48
53
private static String sourceAnalysis ;
49
54
@@ -62,6 +67,8 @@ public class CodeAnalyzer implements Runnable {
62
67
@ Option (names = {"-v" , "--verbose" }, description = "Print logs to console." )
63
68
private static boolean verbose = false ;
64
69
70
+ private static final String outputFileName = "analysis.json" ;
71
+
65
72
66
73
public static Gson gson = new GsonBuilder ()
67
74
.setFieldNamingPolicy (FieldNamingPolicy .LOWER_CASE_WITH_UNDERSCORES )
@@ -109,11 +116,46 @@ private static void analyze() throws IOException, ClassHierarchyException, CallG
109
116
} else {
110
117
Log .warn ("Failed to download library dependencies of project" );
111
118
}
112
- // construct symbol table for project, write parse problems to file in output directory if specified
113
- Pair <Map <String , JavaCompilationUnit >, Map <String , List <Problem >>> symbolTableExtractionResult =
114
- SymbolTable .extractAll (Paths .get (input ));
119
+ boolean analysisFileExists = output != null && Files .exists (Paths .get (output + File .separator + outputFileName ));
120
+
121
+ // if target files are specified, compute symbol table information for the given files
122
+ if (targetFiles != null ) {
123
+ Log .info (targetFiles .size () + "target files specified for analysis: " + targetFiles );
124
+
125
+ // if target files specified for analysis level 2, downgrade to analysis level 1
126
+ if (analysisLevel > 1 ) {
127
+ Log .warn ("Incremental analysis is supported at analysis level 1 only; " +
128
+ "performing analysis level 1 for target files" );
129
+ analysisLevel = 1 ;
130
+ }
131
+
132
+ // extract symbol table for the specified files
133
+ symbolTable = SymbolTable .extract (Paths .get (input ), targetFiles .stream ().map (Paths ::get ).toList ()).getLeft ();
134
+
135
+ // if analysis file exists, update it with new symbol table information for the specified fiels
136
+ if (analysisFileExists ) {
137
+ // read symbol table information from existing analysis file
138
+ Map <String , JavaCompilationUnit > existingSymbolTable = readSymbolTableFromFile (
139
+ new File (output , outputFileName ));
140
+ if (existingSymbolTable != null ) {
141
+ // for each file, tag its symbol table information as "updated" and update existing symbol table
142
+ for (String targetFile : targetFiles ) {
143
+ String targetPathAbs = Paths .get (targetFile ).toAbsolutePath ().toString ();
144
+ JavaCompilationUnit javaCompilationUnit = symbolTable .get (targetPathAbs );
145
+ javaCompilationUnit .setModified (true );
146
+ existingSymbolTable .put (targetPathAbs , javaCompilationUnit );
147
+ }
148
+ }
149
+ symbolTable = existingSymbolTable ;
150
+ }
151
+ }
152
+ else {
153
+ // construct symbol table for project, write parse problems to file in output directory if specified
154
+ Pair <Map <String , JavaCompilationUnit >, Map <String , List <Problem >>> symbolTableExtractionResult =
155
+ SymbolTable .extractAll (Paths .get (input ));
115
156
116
- symbolTable = symbolTableExtractionResult .getLeft ();
157
+ symbolTable = symbolTableExtractionResult .getLeft ();
158
+ }
117
159
118
160
if (analysisLevel > 1 ) {
119
161
// Save SDG, and Call graph as JSON
@@ -166,4 +208,15 @@ private static void emit(String consolidatedJSONString) throws IOException {
166
208
}
167
209
}
168
210
}
211
+
212
+ private static Map <String , JavaCompilationUnit > readSymbolTableFromFile (File analysisJsonFile ) {
213
+ Type symbolTableType = new TypeToken <Map <String , JavaCompilationUnit >>() {}.getType ();
214
+ try (FileReader reader = new FileReader (analysisJsonFile )) {
215
+ JsonObject jsonObject = JsonParser .parseReader (reader ).getAsJsonObject ();
216
+ return gson .fromJson (jsonObject .get ("symbol_table" ), symbolTableType );
217
+ } catch (IOException e ) {
218
+ Log .error ("Error reading analysis file: " + e .getMessage ());
219
+ }
220
+ return null ;
221
+ }
169
222
}
0 commit comments