Skip to content

Commit

Permalink
fix: JavaParser not understanding the diff between inner class and pa…
Browse files Browse the repository at this point in the history
…ckage separators. Brute-force approach is bad but it works.
  • Loading branch information
Col-E committed Aug 12, 2020
1 parent 69faab6 commit 9e18a58
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import javassist.*;
import me.coley.recaf.util.StringUtil;
import me.coley.recaf.workspace.Workspace;

import java.io.*;
Expand Down Expand Up @@ -51,13 +52,21 @@ public SymbolReference<ResolvedReferenceTypeDeclaration> tryToSolveType(String n
// IDK, JavaParser is weird.
if (name.equals("java.lang.Object"))
return SymbolReference.solved(new ReflectionClassDeclaration(Object.class, getRoot()));
// JavaParser has no understanding of the difference between
// a package separator and an inner class separator...
// I mean, its designed to mimic source-level constructs but this is still disappointing...
// I would like to not have to have a loop like this here for performance reasons.
String internal = name.replace('.','/');
if(workspace.hasClass(internal)) {
InputStream is = new ByteArrayInputStream(workspace.getRawClass(internal));
ResolvedReferenceTypeDeclaration dec = toTypeDeclaration(classPool.makeClass(is), getRoot());
SymbolReference<ResolvedReferenceTypeDeclaration> solved = SymbolReference.solved(dec);
if (solved.isSolved())
return solved;
while (internal.indexOf('/') > 0) {
if (workspace.hasClass(internal)) {
InputStream is = new ByteArrayInputStream(workspace.getRawClass(internal));
ResolvedReferenceTypeDeclaration dec = toTypeDeclaration(classPool.makeClass(is), getRoot());
SymbolReference<ResolvedReferenceTypeDeclaration> solved = SymbolReference.solved(dec);
if (solved.isSolved())
return solved;
} else {
internal = StringUtil.replaceLast(internal, "/", "$");
}
}
} catch(IOException ex) {
throw new IllegalStateException("Failed to resolve type: " + name, ex);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/me/coley/recaf/util/JavaParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ private static String typeToDesc(Type type) {
try {
key = toInternal(((ClassOrInterfaceType) type).resolve().getTypeDeclaration().get());
} catch(UnsolvedSymbolException ex) {
Log.warn("Failed to resolve type '{}'", ex.getName());
Log.warn("JavaParser failed to resolve type '{}'", ex.getName());
} catch(UnsupportedOperationException ex) {
// Ok, so it may be "unsupported" however it may not technically be unresolvable.
// For instance, generic types like "<T>" are "unsupported" but do get resolved
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/me/coley/recaf/util/StringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ public static String[] splitNewlineSkipEmpty(String input) {
return split;
}

/**
* Replace the last match of some text in the given string.
*
* @param string
* Text containing items to replace.
* @param toReplace
* Pattern to match.
* @param replacement
* Text to replace pattern with.
*
* @return Modified string.
*/
public static String replaceLast(String string, String toReplace, String replacement) {
int i = string.lastIndexOf(toReplace);
if (i > -1)
return string.substring(0, i) + replacement + string.substring(i + toReplace.length());
return string;
}

/**
* Creates a string incrementing in numerical value.
* Example: a, b, c, ... z, aa, ab ...
Expand Down

0 comments on commit 9e18a58

Please sign in to comment.