|
43 | 43 | @Command(name = "codeanalyzer", mixinStandardHelpOptions = true, sortOptions = false, version = "codeanalyzer v1.1", description = "Convert java binary (*.jar, *.ear, *.war) into a comprehensive system dependency graph.")
|
44 | 44 | public class CodeAnalyzer implements Runnable {
|
45 | 45 |
|
46 |
| - @Option(names = {"-i", "--input"}, required = true, description = "Path to the project root directory.") |
| 46 | + @Option(names = {"-i", "--input"}, description = "Path to the project root directory.") |
47 | 47 | private static String input;
|
48 | 48 |
|
| 49 | + @Option(names = {"-s", "--source-analysis"}, description = "Analyze a single string of java source code instead the project.") |
| 50 | + private static String sourceAnalysis; |
| 51 | + |
| 52 | + @Option(names = {"-o", "--output"}, description = "Destination directory to save the output graphs. By default, the SDG formatted as a JSON will be printed to the console.") |
| 53 | + private static String output; |
| 54 | + |
49 | 55 | @Option(names = {"-b", "--build-cmd"}, description = "Custom build command. Defaults to auto build.")
|
50 | 56 | private static String build;
|
51 | 57 |
|
52 | 58 | @Option(names = {"--no-build"}, description = "Do not build your application. Use this option if you have already built your application.")
|
53 | 59 | private static boolean noBuild = false;
|
54 | 60 |
|
55 |
| - @Option(names = {"-a", "--analysis-level"}, description = "[Optional] Level of analysis to perform. Options: 1 (for just symbol table) or 2 (for full analysis including the system depenedency graph). Default: 1") |
| 61 | + @Option(names = {"-a", "--analysis-level"}, description = "Level of analysis to perform. Options: 1 (for just symbol table) or 2 (for full analysis including the system depenedency graph). Default: 1") |
56 | 62 | private static int analysisLevel = 1;
|
57 | 63 |
|
58 |
| - @Option(names = {"-o", "--output"}, description = "[Optional] Destination directory to save the output graphs. By default, the SDG formatted as a JSON will be printed to the console.") |
59 |
| - private static String output; |
60 |
| - |
61 |
| - @Option(names = {"-d", "--dependencies"}, description = "[Optional] Path to the application 3rd party dependencies that may be helpful in analyzing the application.") |
| 64 | + @Option(names = {"-d", "--dependencies"}, description = "Path to the application 3rd party dependencies that may be helpful in analyzing the application.") |
62 | 65 | private static String dependencies;
|
63 | 66 |
|
64 |
| - @Option(names = {"-s", "--source-analysis"}, description = "[Experimental] Analyze the source code instead directly of the binary. Warning: This option is experimental and may not work as expected.") |
65 |
| - private static boolean analyzeSource = false; |
66 |
| - |
67 | 67 | @Option(names = {"-v", "--verbose"}, description = "Print logs to console.")
|
68 | 68 | private static boolean verbose = false;
|
69 | 69 |
|
@@ -96,42 +96,55 @@ public void run() {
|
96 | 96 |
|
97 | 97 | private static void analyze() throws IOException, ClassHierarchyException, CallGraphBuilderCancelException {
|
98 | 98 |
|
99 |
| - // download library dependencies of project for type resolution |
100 |
| - if (!BuildProject.downloadLibraryDependencies(input)) { |
101 |
| - Log.warn("Failed to download library dependencies of project"); |
| 99 | + JsonObject combinedJsonObject = new JsonObject(); |
| 100 | + Map<String, JavaCompilationUnit> symbolTable; |
| 101 | + // First of all if, sourceAnalysis is provided, we will analyze the source code instead of the project. |
| 102 | + if (sourceAnalysis != null) { |
| 103 | + // Construct symbol table for source code |
| 104 | + Log.debug("Single file analysis."); |
| 105 | + Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>> symbolTableExtractionResult = SymbolTable.extractSingle(sourceAnalysis); |
| 106 | + symbolTable = symbolTableExtractionResult.getLeft(); |
102 | 107 | }
|
103 |
| - // construct symbol table for project, write parse problems to file in output directory if specified |
104 |
| - Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>> symbolTableExtractionResult = |
105 |
| - SymbolTable.extractAll(Paths.get(input)); |
106 |
| - Map<String, JavaCompilationUnit> symbolTable = symbolTableExtractionResult.getLeft(); |
107 |
| - if (output != null) { |
108 |
| - Path outputPath = Paths.get(output); |
109 |
| - if (!Files.exists(outputPath)) { |
110 |
| - Files.createDirectories(outputPath); |
| 108 | + |
| 109 | + else { |
| 110 | + |
| 111 | + // download library dependencies of project for type resolution |
| 112 | + if (!BuildProject.downloadLibraryDependencies(input)) { |
| 113 | + Log.warn("Failed to download library dependencies of project"); |
| 114 | + } |
| 115 | + // construct symbol table for project, write parse problems to file in output directory if specified |
| 116 | + Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>> symbolTableExtractionResult = |
| 117 | + SymbolTable.extractAll(Paths.get(input)); |
| 118 | + |
| 119 | + symbolTable = symbolTableExtractionResult.getLeft(); |
| 120 | + if (output != null) { |
| 121 | + Path outputPath = Paths.get(output); |
| 122 | + if (!Files.exists(outputPath)) { |
| 123 | + Files.createDirectories(outputPath); |
| 124 | + } |
| 125 | + gson.toJson(symbolTableExtractionResult.getRight(), new FileWriter(new File(outputPath.toString(), "parse_errors.json"))); |
111 | 126 | }
|
112 |
| - gson.toJson(symbolTableExtractionResult.getRight(), new FileWriter(new File(outputPath.toString(), "parse_errors.json"))); |
113 |
| - } |
114 | 127 |
|
115 |
| - JsonObject combinedJsonObject = new JsonObject(); |
116 |
| - if (analysisLevel > 1) { |
117 |
| - // Save SDG, IPCFG, and Call graph as JSON |
118 |
| - // If noBuild is not true, and build is also not provided, we will use "auto" as the build command |
119 |
| - build = build == null ? "auto" : build; |
120 |
| - // Is noBuild is true, we will not build the project |
121 |
| - build = noBuild ? null : build; |
122 |
| - String sdgAsJSONString = SystemDependencyGraph.construct(input, dependencies, build); |
123 |
| - JsonElement sdgAsJSONElement = gson.fromJson(sdgAsJSONString, JsonElement.class); |
124 |
| - JsonObject sdgAsJSONObject = sdgAsJSONElement.getAsJsonObject(); |
125 |
| - |
126 |
| - // We don't really need these fields, so we'll remove it. |
127 |
| - sdgAsJSONObject.remove("nodes"); |
128 |
| - sdgAsJSONObject.remove("creator"); |
129 |
| - sdgAsJSONObject.remove("version"); |
130 |
| - |
131 |
| - // Remove the 'edges' element and move the list of edges up one level |
132 |
| - JsonElement edges = sdgAsJSONObject.get("edges"); |
133 |
| - combinedJsonObject.add("system_dependency_graph", edges); |
| 128 | + if (analysisLevel > 1) { |
| 129 | + // Save SDG, and Call graph as JSON |
| 130 | + // If noBuild is not true, and build is also not provided, we will use "auto" as the build command |
| 131 | + build = build == null ? "auto" : build; |
| 132 | + // Is noBuild is true, we will not build the project |
| 133 | + build = noBuild ? null : build; |
| 134 | + String sdgAsJSONString = SystemDependencyGraph.construct(input, dependencies, build); |
| 135 | + JsonElement sdgAsJSONElement = gson.fromJson(sdgAsJSONString, JsonElement.class); |
| 136 | + JsonObject sdgAsJSONObject = sdgAsJSONElement.getAsJsonObject(); |
| 137 | + |
| 138 | + // We don't really need these fields, so we'll remove it. |
| 139 | + sdgAsJSONObject.remove("nodes"); |
| 140 | + sdgAsJSONObject.remove("creator"); |
| 141 | + sdgAsJSONObject.remove("version"); |
| 142 | + |
| 143 | + // Remove the 'edges' element and move the list of edges up one level |
| 144 | + JsonElement edges = sdgAsJSONObject.get("edges"); |
| 145 | + combinedJsonObject.add("system_dependency_graph", edges); |
134 | 146 |
|
| 147 | + } |
135 | 148 | }
|
136 | 149 |
|
137 | 150 | // Convert the JavaCompilationUnit to JSON and add to consolidated json object
|
|
0 commit comments