Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

analysisScope toJson function #1355

Merged
merged 29 commits into from
Mar 7, 2024
Merged

analysisScope toJson function #1355

merged 29 commits into from
Mar 7, 2024

Conversation

aakgna
Copy link
Contributor

@aakgna aakgna commented Jan 4, 2024

Added a new function to serialize an AnalysisScope to JSON format.

@msridhar msridhar self-requested a review January 22, 2024 20:42
Copy link
Member

@msridhar msridhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looking good! I have a few comments. Also, we need to write a test for this new code. You can add it in the AnalysisScopeTest class: https://github.com/wala/WALA/blob/master/core/src/test/java/com/ibm/wala/core/tests/cha/AnalysisScopeTest.java#L21-L21 The test should create an AnalysisScope and then confirm the JSON generated by toJSON() matches what we expect

Comment on lines 60 to 62


// import com.google.gson.Gson;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete these lines

@@ -345,6 +351,30 @@ public String toString() {
return result.toString();
}

public String toJson() {
HashMap<String, Object> res = new HashMap<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this code, let's used LinkedHashMap instead of HashMap to ensure a deterministic iteration order https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html

@@ -680,4 +680,4 @@ public boolean hasEdge(MethodReference src, MethodReference dst) {
}
};
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this change

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not addressed

@@ -55,4 +55,4 @@ public void testBaseScope() throws IOException, ClassHierarchyException {
ClassLoaderReference.Application, "Ljava/awt/AlphaComposite")),
"found unexpected class");
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this change

@@ -5,4 +5,4 @@ distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStorePath=wrapper/dists
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this change

Comment on lines 365 to 372
String[] exclusions = getExclusions().toString().split("\\|");
ArrayList<String> arr2 = new ArrayList<>();
for(int i = 0; i < exclusions.length; i++){
String word = exclusions[i];
word = word.replace("(", "");
word = word.replace(")", "");
arr2.add(word);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, way to go the extra mile to parse the exclusions!

Copy link

github-actions bot commented Jan 30, 2024

Test Results

  572 files  ± 0    572 suites  ±0   3h 37m 54s ⏱️ + 29m 35s
  734 tests + 2    717 ✅ + 2  17 💤 ±0  0 ❌ ±0 
3 554 runs  +10  3 467 ✅ +10  87 💤 ±0  0 ❌ ±0 

Results for commit efad143. ± Comparison against base commit 0e3068a.

♻️ This comment has been updated with latest results.

@@ -680,4 +680,4 @@ public boolean hasEdge(MethodReference src, MethodReference dst) {
}
};
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not addressed

// new FileProvider().getFile("J2SEClassHierarchyExclusions.txt"),
new FileProvider().getFile("GUIExclusions.txt"),
AnalysisScopeTest.class.getClassLoader());
String exp = "{\"Loaders\":{\"Primordial\":[\"JarFileModule:/opt/homebrew/Cellar/openjdk/21.0.1/libexec/openjdk.jdk/Contents/Home/jmods/java.base.jmod\",\"Nested Jar File:primordial.jar.model\"],\"Extension\":[],\"Application\":[\"JarFileModule:/Users/aakgna/Documents/WALA-Research/WALA/core/build/resources/test/com.ibm.wala.core.testdata_1.0.0.jar\"],\"Synthetic\":[]},\"Exclusions\":[\"java\\\\/awt\\\\/.*\",\"javax\\\\/swing\\\\/.*\",\"sun\\\\/awt\\\\/.*\",\"sun\\\\/swing\\\\/.*\"]}";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking better! But I expect this test will not pass in general, since we have absolute paths in it. So I guess a straightforward string comparison won't work. Here's an alternate approach:

  1. Call scope.toJson() to get the JSON string
  2. Re-parse this String using Gson
  3. Check that specific parts of the resulting Map match what we expect

Can you try that? Let me know if it doesn't make sense

Copy link
Member

@msridhar msridhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there! A couple more comments on the tests

assertEquals(arr2, map.get("Exclusions"));
}
Type type2 = new TypeToken<LinkedHashMap<String, ArrayList<String>>>(){}.getType();
LinkedHashMap<String, ArrayList<String>> loaders = gson.fromJson(gson.toJson(map.get("Loaders")), type2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I am confused, why do you need to serialize the data in the map back to JSON and then parse it again? I think you can get rid of this and just use some downcasts to get the data you want out of the map directly

LinkedHashMap<String, Object> map = gson.fromJson(scope.toJson(), type);
System.out.println(map);
if(map.containsKey("Exclusions")) {
String[] exclusions = scope.getExclusions().toString().split("\\|");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we know what is in GUIExclusions.txt. So I think we can simplify this code. We can just do something like assertEquals(List.of("java\/awt\/.*", "javax\/swing\/.*", "sun\/awt\/.*", "sun\/swing\/.*"), map.get("Exclusions")). We can then get rid of this whole loop that re-parses the exclusions string

}
Type type2 = new TypeToken<LinkedHashMap<String, ArrayList<String>>>(){}.getType();
LinkedHashMap<String, ArrayList<String>> loaders = gson.fromJson(gson.toJson(map.get("Loaders")), type2);
if(loaders.containsKey("Primordial")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again we can simplify this code. We know the contents of wala.testdata.txt:

Primordial,Java,stdlib,base
Primordial,Java,jarFile,primordial.jar.model
Application,Java,jarFile,com.ibm.wala.core.testdata_1.0.0.jar

So I think we can write assertions like:

  • The keys of loaders should be exactly "Primordial","Application","Extension","Synthetic"
  • Extension and Synthetic should be mapped to empty lists
  • Primordial should be mapped to a list of length two. And one of the elements should contain `"primordial.jar.model"
  • Application should be mapped to a list of length 1, and that element should contain "com.ibm.wala.core.testdata_1.0.0.jar"

Copy link
Member

@msridhar msridhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more comments

LinkedHashMap<String, ArrayList<String>> loaders = new LinkedHashMap<>();
for (ClassLoaderReference loader : loadersByName.values()) {
ArrayList<String> arr = new ArrayList<>();

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove blank line

Comment on lines 106 to 110
AnalysisScope tempScope =
AnalysisScopeReader.instance.readJavaScope(
TestConstants.WALA_TESTDATA,
new FileProvider().getFile("GUIExclusions.txt"),
AnalysisScopeTest.class.getClassLoader());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to create this temp scope just to test the exclusions. Just skip testing the exclusions here

scope.setExclusions(tempScope.getExclusions());
String[] stdlibs = WalaProperties.getJ2SEJarFiles();
Arrays.sort(stdlibs);
int cnt = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment explaining why you are stopping at 5. Also the value 5 should be stored in a local variable and then that variable should be used in multiple places

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this code would be simpler if you just got rid of the cnt variable and added everything. Is there any reason to add the limit?

assertThat(
loaders.get("Primordial"),
hasItem(
"JarFileModule:/Users/aakgna/Library/Java/JavaVirtualMachines/corretto-11.0.15/Contents/Home/jmods/java.base.jmod"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check will not pass on other machines. You have the stdlibs array above. You should use the strings there (which give the full paths to the jars where the tests are running) to check that the right strings are in the JSON.

.get("Primordial")
.get(0)
.contains(
"Java/JavaVirtualMachines/corretto-11.0.15/Contents/Home/jmods/java.base.jmod"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not fully address my comment. Please take the paths directly from the stdlibs array and check that they match.

new HashSet<>(List.of("Primordial", "Extension", "Application", "Synthetic"));
assertEquals(loaders.keySet(), loaderKeys);
assertEquals(stdlibs.length, loaders.get("Primordial").size());
assertTrue(loaders.get("Primordial").get(0).contains("/Contents/Home/jmods/java.base.jmod"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still wrong, and tests are still failing. You need to take the relevant strings from the stdlibs array for this comparison, rather than just doing get(0) and comparing to a constant string.

@msridhar msridhar merged commit ae3b95d into wala:master Mar 7, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants