|
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