From 5291651ff771a6d0129c8d2e546add6a4f6a79ac Mon Sep 17 00:00:00 2001 From: Cody <6558800+Bl3nd@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:05:41 -0600 Subject: [PATCH] Add parsing for things that are not in a method or class declaration. --- .../parser/visitors/FieldAccessParser.java | 58 ++++++++++++++++++- .../parser/visitors/MyVoidVisitor.java | 12 ++++ .../parser/visitors/ParameterParser.java | 15 ++++- .../parser/visitors/ParserUtil.java | 42 ++++++++++++-- 4 files changed, 119 insertions(+), 8 deletions(-) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/FieldAccessParser.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/FieldAccessParser.java index e8d4d78db..188e63a31 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/FieldAccessParser.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/FieldAccessParser.java @@ -4,9 +4,12 @@ import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.expr.*; import com.github.javaparser.resolution.UnsolvedSymbolException; +import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; import com.github.javaparser.resolution.types.ResolvedType; import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer; import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassFieldLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassLocalVariableLocation; +import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassParameterLocation; import the.bytecode.club.bytecodeviewer.resources.classcontainer.locations.ClassReferenceLocation; import java.util.Objects; @@ -20,6 +23,58 @@ class FieldAccessParser { + /** + * Solve a field that is accessed through a lambda and not within a method or constructor + * + * @param container The {@link ClassFileContainer} + * @param expr The {@link FieldAccessExpr} + * @param className The class name of the class that is accessing the field + */ + static void parse(ClassFileContainer container, FieldAccessExpr expr, String className) + { + Range fieldRange = Objects.requireNonNull(expr.getTokenRange().orElse(null)).getEnd().getRange().orElse(null); + if (fieldRange == null) + return; + + Value fieldValue = new Value(expr.getName(), fieldRange); + + Expression scope = expr.getScope(); + if (scope instanceof NameExpr) + { + NameExpr nameExpr = (NameExpr) scope; + Range scopeRange = nameExpr.getRange().orElse(null); + if (scopeRange == null) + return; + + Value scopeValue = new Value(nameExpr.getName(), scopeRange); + try + { + ResolvedValueDeclaration vd = nameExpr.resolve(); + if (vd.isField()) + { + container.putField(scopeValue.name, new ClassFieldLocation(getOwner(container), "reference", + scopeValue.line, scopeValue.columnStart, scopeValue.columnEnd + 1)); + } + else if (vd.isVariable()) + { + container.putLocalVariable(scopeValue.name, new ClassLocalVariableLocation(getOwner(container), + className, "reference", scopeValue.line, scopeValue.columnStart, scopeValue.columnEnd + 1)); + } + else if (vd.isParameter()) + { + container.putParameter(scopeValue.name, new ClassParameterLocation(getOwner(container), className, + "reference", scopeValue.line, scopeValue.columnStart, scopeValue.columnEnd + 1)); + } + + putFieldResolvedValues(container, expr, nameExpr, fieldValue); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + } + static void parse(ClassFileContainer container, FieldAccessExpr expr, CallableDeclaration method) { Range fieldRange = Objects.requireNonNull(expr.getTokenRange().orElse(null)).getEnd().getRange().orElse(null); @@ -107,7 +162,8 @@ else if (scope instanceof EnclosedExpr) fieldValue.name, "reference", -1, -1, -1)); } - container.putField(fieldValue.name, new ClassFieldLocation(className, "reference", fieldValue.line, fieldValue.columnStart, fieldValue.columnEnd + 1)); + container.putField(fieldValue.name, new ClassFieldLocation(className, "reference", fieldValue.line, + fieldValue.columnStart, fieldValue.columnEnd + 1)); } catch (Exception e) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/MyVoidVisitor.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/MyVoidVisitor.java index d4177ba14..ba45e323d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/MyVoidVisitor.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/MyVoidVisitor.java @@ -560,6 +560,7 @@ public void visit(FieldAccessExpr n, Object arg) try { InitializerDeclaration initializer = findInitializerForExpression(n, this.compilationUnit); + ClassOrInterfaceDeclaration classOrInterfaceDeclaration = findClassOrInterfaceForExpression(n, this.compilationUnit); CallableDeclaration method = findMethodForExpression(n, this.compilationUnit); if (method == null) method = findConstructorForExpression(n, this.compilationUnit); @@ -568,6 +569,8 @@ public void visit(FieldAccessExpr n, Object arg) FieldAccessParser.parse(classFileContainer, n, method); else if (initializer != null) FieldAccessParser.parseStatic(classFileContainer, n); + else if (classOrInterfaceDeclaration != null) + FieldAccessParser.parse(classFileContainer, n, classOrInterfaceDeclaration.getNameAsString()); } catch (Exception e) { @@ -836,12 +839,17 @@ public void visit(MethodCallExpr n, Object arg) { CallableDeclaration method = findMethodForExpression(n, this.compilationUnit); InitializerDeclaration staticInitializer = null; + ClassOrInterfaceDeclaration classOrInterfaceDeclaration = null; if (method == null) { method = findConstructorForExpression(n, this.compilationUnit); if (method == null) { staticInitializer = findInitializerForExpression(n, this.compilationUnit); + if (staticInitializer == null) + { + classOrInterfaceDeclaration = findClassOrInterfaceForExpression(n, this.compilationUnit); + } } } @@ -870,6 +878,10 @@ else if (staticInitializer != null) { MethodCallParser.parseStatic(classFileContainer, n); } + else if (classOrInterfaceDeclaration != null) + { + MethodCallParser.parse(classFileContainer, n, null); + } } catch (Exception e) { diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParameterParser.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParameterParser.java index 729b8dac9..264422374 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParameterParser.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParameterParser.java @@ -2,7 +2,9 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.SimpleName; import the.bytecode.club.bytecodeviewer.resources.classcontainer.ClassFileContainer; @@ -23,14 +25,21 @@ public static void parse(CompilationUnit compilationUnit, Parameter p, ClassFile String methodName = findMethodOwnerFor(compilationUnit, node); if (methodName == null) { - System.err.println("Parameter - Method not found"); - return; + ClassOrInterfaceDeclaration classOrInterfaceForExpression = findClassOrInterfaceForExpression((Expression) node, compilationUnit); + if (classOrInterfaceForExpression == null) + { + System.err.println("Parameter - Method not found"); + return; + } + + methodName = classOrInterfaceForExpression.getNameAsString(); } SimpleName name = p.getName(); + String finalMethodName = methodName; name.getRange().ifPresent(range -> { Value parameter = new Value(name, range); - putParameter(container, parameter, methodName, "declaration"); + putParameter(container, parameter, finalMethodName, "declaration"); }); } } diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParserUtil.java b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParserUtil.java index 20d3a0dc3..f8c565f5d 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParserUtil.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/resources/classcontainer/parser/visitors/ParserUtil.java @@ -3,10 +3,7 @@ import com.github.javaparser.Range; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; -import com.github.javaparser.ast.body.CallableDeclaration; -import com.github.javaparser.ast.body.ConstructorDeclaration; -import com.github.javaparser.ast.body.InitializerDeclaration; -import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.expr.SimpleName; @@ -196,8 +193,16 @@ static void putFieldResolvedValues(ClassFileContainer container, Expression visi Expression resolveExpr, Value fieldValue) { ResolvedType resolvedType = visitedExpr.getSymbolResolver().calculateType(resolveExpr); + if (resolvedType.isConstraint()) + { + resolvedType = resolvedType.asConstraintType().getBound(); + } + if (!resolvedType.isReferenceType()) + { return; + } + String qualifiedName = resolvedType.asReferenceType().getQualifiedName(); String className = qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); @@ -523,4 +528,33 @@ public void visit(InitializerDeclaration n, Void arg) return null; } + + static ClassOrInterfaceDeclaration findClassOrInterfaceForExpression(Expression expression, CompilationUnit cu) + { + final boolean[] contains = {false}; + final ClassOrInterfaceDeclaration[] classOrInterfaceDeclaration = {null}; + cu.accept(new VoidVisitorAdapter() + { + @Override + public void visit(ClassOrInterfaceDeclaration n, Void arg) + { + super.visit(n, arg); + if (contains[0]) + return; + + n.getMembers().forEach(member -> { + if (member.containsWithinRange(expression)) + { + contains[0] = true; + classOrInterfaceDeclaration[0] = n; + } + }); + } + }, null); + + if (contains[0]) + return classOrInterfaceDeclaration[0]; + + return null; + } }