Skip to content

Commit

Permalink
analysisScope toJson function (#1355)
Browse files Browse the repository at this point in the history
Added a new function to serialize an `AnalysisScope` to JSON format.

---------

Co-authored-by: Manu Sridharan <[email protected]>
  • Loading branch information
aakgna and msridhar authored Mar 7, 2024
1 parent 0e3068a commit ae3b95d
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ dependencies {
api(projects.util) { because("public interface CallGraph extends interface NumberedGraph") }
testFixturesImplementation(libs.ant)
testFixturesImplementation(libs.junit.platform.launcher)
implementation(libs.gson)
testImplementation(libs.assertj.core)
testImplementation(libs.hamcrest)
testRuntimeOnly(sourceSets["testSubjects"].output.classesDirs)
Expand Down
37 changes: 37 additions & 0 deletions core/src/main/java/com/ibm/wala/ipa/callgraph/AnalysisScope.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/
package com.ibm.wala.ipa.callgraph;

import com.google.gson.Gson;
import com.ibm.wala.classLoader.ArrayClassLoader;
import com.ibm.wala.classLoader.BinaryDirectoryTreeModule;
import com.ibm.wala.classLoader.ClassFileModule;
Expand Down Expand Up @@ -345,6 +346,42 @@ public String toString() {
return result.toString();
}

/**
* An AnalysisScope is converted to a JSON formatted variable using the loaders and exclusions
* hierarchy using ToJson. (Loaders) Primordial, Extension, Application, and Synthetic are the
* loaders keys; each one contains an arraylist of Strings. The exclusions contains an arraylist
* of strings.
*
* @return json variable containing contents of the AnalysisScope
*/
public String toJson() {
LinkedHashMap<String, Object> res = new LinkedHashMap<>();
LinkedHashMap<String, ArrayList<String>> loaders = new LinkedHashMap<>();
for (ClassLoaderReference loader : loadersByName.values()) {
ArrayList<String> arr = new ArrayList<>();
for (Module m : getModules(loader)) {
arr.add(m.toString());
}
loaders.put(loader.getName().toString(), arr);
}
res.put("Loaders", loaders);
ArrayList<String> arr2 = new ArrayList<>();
if (getExclusions() == null) {
res.put("Exclusions", arr2);
} else {
String[] exclusions = getExclusions().toString().split("\\|");
for (int i = 0; i < exclusions.length; i++) {
String word = exclusions[i];
word = word.replace("(", "");
word = word.replace(")", "");
arr2.add(word);
}
res.put("Exclusions", arr2);
}
Gson gson = new Gson();
return gson.toJson(res);
}

/**
* @return a String that describes exclusions from the analysis scope.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
package com.ibm.wala.core.tests.cha;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ibm.wala.core.tests.util.TestConstants;
import com.ibm.wala.core.util.config.AnalysisScopeReader;
import com.ibm.wala.core.util.io.FileProvider;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
import com.ibm.wala.properties.WalaProperties;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.TypeReference;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import org.junit.jupiter.api.Test;

public class AnalysisScopeTest {
Expand Down Expand Up @@ -55,4 +70,63 @@ public void testBaseScope() throws IOException, ClassHierarchyException {
ClassLoaderReference.Application, "Ljava/awt/AlphaComposite")),
"found unexpected class");
}

@Test
public void testToJson() throws IOException {
AnalysisScope scope =
AnalysisScopeReader.instance.readJavaScope(
TestConstants.WALA_TESTDATA,
new FileProvider().getFile("GUIExclusions.txt"),
AnalysisScopeTest.class.getClassLoader());
Gson gson = new Gson();
Type type = new TypeToken<LinkedHashMap<String, Object>>() {}.getType();
LinkedHashMap<String, Object> map = gson.fromJson(scope.toJson(), type);
assertEquals(
List.of("java\\/awt\\/.*", "javax\\/swing\\/.*", "sun\\/awt\\/.*", "sun\\/swing\\/.*"),
map.get("Exclusions"));

@SuppressWarnings("unchecked")
Map<String, List<String>> loaders = (Map<String, List<String>>) map.get("Loaders");
Set<String> loaderKeys =
new HashSet<>(List.of("Primordial", "Extension", "Application", "Synthetic"));
assertEquals(loaders.keySet(), loaderKeys);
assertEquals(2, loaders.get("Primordial").size());
assertThat(loaders.get("Primordial"), hasItem("Nested Jar File:primordial.jar.model"));
assertEquals(1, loaders.get("Application").size());
assertThat(
loaders.get("Application").get(0), containsString("com.ibm.wala.core.testdata_1.0.0.jar"));
assertEquals(0, loaders.get("Extension").size());
assertEquals(0, loaders.get("Synthetic").size());
}

@Test
public void testToJsonCustom() throws IOException {
AnalysisScope scope;
scope = AnalysisScope.createJavaAnalysisScope();
String[] stdlibs = WalaProperties.getJ2SEJarFiles();
Arrays.sort(stdlibs);
for (String stdlib : stdlibs) {
scope.addToScope(ClassLoaderReference.Primordial, new JarFile(stdlib));
scope.addToScope(ClassLoaderReference.Application, new JarFile(stdlib));
}
scope.setExclusions(null);
Gson gson = new Gson();
Type type = new TypeToken<LinkedHashMap<String, Object>>() {}.getType();
LinkedHashMap<String, Object> map = gson.fromJson(scope.toJson(), type);
assertEquals(List.of(), map.get("Exclusions"));

@SuppressWarnings("unchecked")
Map<String, List<String>> loaders = (Map<String, List<String>>) map.get("Loaders");
Set<String> loaderKeys =
new HashSet<>(List.of("Primordial", "Extension", "Application", "Synthetic"));
assertEquals(loaders.keySet(), loaderKeys);
assertEquals(stdlibs.length, loaders.get("Primordial").size());
assertEquals(stdlibs.length, loaders.get("Application").size());
for (int i = 0; i < stdlibs.length; i++) {
assertThat(loaders.get("Primordial"), hasItem("JarFileModule:" + stdlibs[i]));
assertThat(loaders.get("Application"), hasItem("JarFileModule:" + stdlibs[i]));
}
assertEquals(0, loaders.get("Extension").size());
assertEquals(0, loaders.get("Synthetic").size());
}
}

0 comments on commit ae3b95d

Please sign in to comment.