Skip to content
Snippets Groups Projects
Commit b70f8c10 authored by jacosro's avatar jacosro
Browse files

Implemented resolving method calls with JavaParser

parent e738cfd5
No related branches found
No related tags found
1 merge request!29Resolve 6-method-call-nodes
package tfm.exec;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.AnnotationDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import tfm.graphs.sdg.SDG;
import tfm.nodes.GraphNode;
import tfm.utils.Context;
import tfm.utils.Logger;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Optional;
public class MethodResolver {
private static class Args {
String file;
String method;
}
public static void main(String[] inputArgs) throws FileNotFoundException {
Args args = parseArgs(inputArgs);
CompilationUnit cu = JavaParser.parse(new File(args.file));
SDG sdg = new SDG();
sdg.build(new NodeList<>(cu));
VoidVisitorAdapter<Void> visitor = new VoidVisitorAdapter<Void>() {
@Override
public void visit(MethodCallExpr n, Void arg) {
TypeSolver solver = new JavaParserTypeSolver(args.file.substring(0, args.file.lastIndexOf('/')));
Logger.log("-- Trying to solve method " + n.getNameAsString() + " --");
Optional<MethodDeclaration> optionalResolvedMethod;
try {
optionalResolvedMethod = getMethodCallWithJavaParserSymbolSolver(n, solver, new ReflectionTypeSolver());
} catch (UnsolvedSymbolException e) {
optionalResolvedMethod = Optional.empty();
}
if (!optionalResolvedMethod.isPresent()) {
Logger.format("Not found: %s", n);
return;
}
Logger.format("Found: %s", n.getNameAsString());
Logger.log(optionalResolvedMethod.get().getSignature().asString());
Logger.log("-- Trying to match with a node from SDG --");
Optional<GraphNode<MethodDeclaration>> methodDeclarationNode = optionalResolvedMethod.flatMap(sdg::findNodeByASTNode);
if (!methodDeclarationNode.isPresent()) {
Logger.log("Failed to find node in SDG");
return;
}
Logger.format("SDG node: %s", methodDeclarationNode.get());
}
};
cu.accept(visitor, null);
}
private static Args parseArgs(String[] args) {
Args res = new Args();
Logger.log(Arrays.asList(args));
try {
res.file = args[0];
// res.method = args[2];
} catch (Exception e) {
Logger.log("Incorrect syntax: java MethodResolver.class <file> <methodName>");
System.exit(1);
}
return res;
}
private static Optional<MethodDeclaration> getMethodCallWithJavaParserSymbolSolver(MethodCallExpr methodCallExpr, TypeSolver... solvers) {
CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(solvers);
SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(combinedTypeSolver).solve(methodCallExpr);
return solver.isSolved() ? solver.getCorrespondingDeclaration().toAst() : Optional.empty();
}
}
package tfm.graphs.sdg;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
......@@ -13,12 +14,25 @@ import com.github.javaparser.ast.expr.VariableDeclarationExpr;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.SourceFileInfoExtractor;
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade;
import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
import com.github.javaparser.symbolsolver.resolution.SymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import tfm.nodes.GraphNode;
import tfm.nodes.TypeNodeFactory;
import tfm.nodes.type.NodeType;
import tfm.utils.Context;
import tfm.utils.Logger;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
......@@ -99,22 +113,16 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {
Logger.log("MethodCallReplacerVisitor", context);
Optional<MethodDeclaration> optionalCallingMethod = methodCallExpr.getScope().isPresent()
? shouldMakeCallWithScope(methodCallExpr, context)
: shouldMakeCallWithNoScope(methodCallExpr, context);
Optional<GraphNode<MethodDeclaration>> optionalNethodDeclarationNode = getMethodDeclarationNodeWithJavaParser(methodCallExpr);
if (!optionalCallingMethod.isPresent()) {
Logger.log("Discarding: " + methodCallExpr);
if (!optionalNethodDeclarationNode.isPresent()) {
Logger.format("Not found: '%s'. Discarding");
return;
}
MethodDeclaration methodCalled = optionalCallingMethod.get();
GraphNode<MethodDeclaration> calledMethodNode = optionalNethodDeclarationNode.get();
Optional<GraphNode<MethodDeclaration>> optionalCalledMethodNode = sdg.findNodeByASTNode(methodCalled);
assert optionalCalledMethodNode.isPresent();
GraphNode<MethodDeclaration> calledMethodNode = optionalCalledMethodNode.get();
MethodDeclaration methodCalled = calledMethodNode.getAstNode();
sdg.addCallArc(methodCallNode, calledMethodNode);
......@@ -157,6 +165,26 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> {
Logger.log("MethodCallReplacerVisitor", String.format("%s | Method '%s' called", methodCallExpr, methodCalled.getNameAsString()));
}
private Optional<GraphNode<MethodDeclaration>> getMethodDeclarationNodeWithJavaParser(MethodCallExpr methodCallExpr) {
TypeSolver typeSolver = new ReflectionTypeSolver();
try {
SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(typeSolver).solve(methodCallExpr);
return solver.isSolved()
? solver.getCorrespondingDeclaration().toAst()
.flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration))
: Optional.empty();
} catch (UnsolvedSymbolException e) {
return Optional.empty();
}
}
/**
* Handles method calls with scope. Examples:
* - System.out.println() -> println() is a method call with scope System.out
* - new A().getB() -> getB() is a method call with scope new A()
*/
private Optional<MethodDeclaration> shouldMakeCallWithScope(MethodCallExpr methodCallExpr, Context context) {
assert methodCallExpr.getScope().isPresent();
......
......@@ -28,7 +28,7 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> {
public static final NodeFactory DEFAULT_FACTORY = TypeNodeFactory.fromType(NodeType.STATEMENT);
private NodeType nodeType;
private final NodeType nodeType;
private final long id;
private final String instruction;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment