mistupv / JavaSlicer

A program slicer for Java, based on the system dependence graph (SDG).
https://mist.dsic.upv.es/JavaSlicer/demo/
GNU Affero General Public License v3.0
52 stars 18 forks source link

Strategy to resolve method declarations in project dependencies #45

Closed miguelvelezmj25 closed 3 years ago

miguelvelezmj25 commented 3 years ago

Thank you for fixing the usage of option -i!

I was now wondering if JavaSDGSlicer has some option or strategy that I could use to avoid getting an error when the project that I want to analyze has dependencies for which (1) I do not have access to the source code and (2) I am not really interested in the analysis in those methods/classes. For example, if I want to analyze this code

import hello.Hello; // Imported as a maven dependency

public class Example {
    public static void main(String[] args) {
        int sum = Hello.number();
        int n = 10;
        for (int i = 0; i < 10; i++) {
            sum += 1;
        }
        System.out.println(sum);
    }
}

I am not really interested to do any analysis in Hello.number(); and any other calls that happen within that method. Still, I get the following error:

Exception in thread "main" UnsolvedSymbolException{context='Hello.number()', name='Hello', cause='UnsolvedSymbolException{context='Hello', name='Solving Hello', cause='null'}'}
    at com.github.javaparser.symbolsolver.javaparsermodel.contexts.AbstractJavaParserContext.findTypeDeclarations(AbstractJavaParserContext.java:181)
    at com.github.javaparser.symbolsolver.javaparsermodel.contexts.MethodCallExprContext.solveMethod(MethodCallExprContext.java:171)
    at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solve(JavaParserFacade.java:321)
    at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.solve(JavaParserFacade.java:183)
    at com.github.javaparser.symbolsolver.JavaSymbolSolver.resolveDeclaration(JavaSymbolSolver.java:161)
    at com.github.javaparser.ast.expr.MethodCallExpr.resolve(MethodCallExpr.java:313)
    at com.github.javaparser.ast.expr.MethodCallExpr.resolve(MethodCallExpr.java:54)
    at es.upv.mist.slicing.utils.ASTUtils.shouldVisitArgumentsForMethodCalls(ASTUtils.java:121)
    at es.upv.mist.slicing.utils.ASTUtils.shouldVisitArgumentsForMethodCalls(ASTUtils.java:125)
    at es.upv.mist.slicing.nodes.VariableVisitor.visitCall(VariableVisitor.java:255)
    at es.upv.mist.slicing.nodes.VariableVisitor.visit(VariableVisitor.java:249)
    at es.upv.mist.slicing.nodes.VariableVisitor.visit(VariableVisitor.java:24)
    at com.github.javaparser.ast.expr.MethodCallExpr.accept(MethodCallExpr.java:121)
    at es.upv.mist.slicing.nodes.VariableVisitor.lambda$visit$2(VariableVisitor.java:210)
    at java.base/java.util.Optional.ifPresent(Optional.java:183)
    at es.upv.mist.slicing.nodes.VariableVisitor.visit(VariableVisitor.java:209)
    at es.upv.mist.slicing.nodes.VariableVisitor.visit(VariableVisitor.java:24)
    at com.github.javaparser.ast.expr.VariableDeclarationExpr.accept(VariableDeclarationExpr.java:122)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.visit(VoidVisitorAdapter.java:259)
    at es.upv.mist.slicing.graphs.GraphNodeContentVisitor.visit(GraphNodeContentVisitor.java:86)
    at com.github.javaparser.ast.stmt.ExpressionStmt.accept(ExpressionStmt.java:77)
    at es.upv.mist.slicing.graphs.GraphNodeContentVisitor.startVisit(GraphNodeContentVisitor.java:21)
    at es.upv.mist.slicing.nodes.VariableVisitor.startVisit(VariableVisitor.java:86)
    at es.upv.mist.slicing.nodes.GraphNode.extractVariables(GraphNode.java:57)
    at es.upv.mist.slicing.nodes.GraphNode.<init>(GraphNode.java:40)
    at es.upv.mist.slicing.nodes.GraphNode.<init>(GraphNode.java:34)
    at es.upv.mist.slicing.graphs.Graph.addVertex(Graph.java:25)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.connectTo(CFGBuilder.java:84)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.connectTo(CFGBuilder.java:71)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.visit(CFGBuilder.java:131)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.visit(CFGBuilder.java:37)
    at com.github.javaparser.ast.stmt.ExpressionStmt.accept(ExpressionStmt.java:77)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.lambda$visit$19(VoidVisitorAdapter.java:109)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at com.github.javaparser.ast.NodeList.forEach(NodeList.java:290)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.visit(VoidVisitorAdapter.java:109)
    at com.github.javaparser.ast.stmt.BlockStmt.accept(BlockStmt.java:76)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.visitCallableDeclaration(CFGBuilder.java:369)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.visit(CFGBuilder.java:351)
    at es.upv.mist.slicing.graphs.cfg.CFGBuilder.visit(CFGBuilder.java:37)
    at com.github.javaparser.ast.body.MethodDeclaration.accept(MethodDeclaration.java:106)
    at es.upv.mist.slicing.graphs.cfg.CFG.build(CFG.java:129)
    at es.upv.mist.slicing.graphs.sdg.SDG$Builder$1.visit(SDG.java:127)
    at es.upv.mist.slicing.graphs.sdg.SDG$Builder$1.visit(SDG.java:123)
    at com.github.javaparser.ast.body.MethodDeclaration.accept(MethodDeclaration.java:106)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.lambda$visit$31(VoidVisitorAdapter.java:154)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at com.github.javaparser.ast.NodeList.forEach(NodeList.java:290)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.visit(VoidVisitorAdapter.java:154)
    at com.github.javaparser.ast.body.ClassOrInterfaceDeclaration.accept(ClassOrInterfaceDeclaration.java:100)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.lambda$visit$43(VoidVisitorAdapter.java:175)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at com.github.javaparser.ast.NodeList.forEach(NodeList.java:290)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.visit(VoidVisitorAdapter.java:175)
    at com.github.javaparser.ast.CompilationUnit.accept(CompilationUnit.java:138)
    at com.github.javaparser.ast.visitor.VoidVisitorAdapter.visit(VoidVisitorAdapter.java:623)
    at com.github.javaparser.ast.NodeList.accept(NodeList.java:282)
    at es.upv.mist.slicing.graphs.sdg.SDG$Builder.buildCFGs(SDG.java:123)
    at es.upv.mist.slicing.graphs.sdg.SDG$Builder.build(SDG.java:112)
    at es.upv.mist.slicing.graphs.sdg.SDG.build(SDG.java:73)
    at es.upv.mist.slicing.cli.Slicer.slice(Slicer.java:253)
    at es.upv.mist.slicing.cli.Slicer.main(Slicer.java:314)
Caused by: UnsolvedSymbolException{context='Hello', name='Solving Hello', cause='null'}
    at com.github.javaparser.symbolsolver.javaparsermodel.TypeExtractor.visit(TypeExtractor.java:332)
    at com.github.javaparser.symbolsolver.javaparsermodel.TypeExtractor.visit(TypeExtractor.java:97)
    at com.github.javaparser.ast.expr.NameExpr.accept(NameExpr.java:79)
    at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.getTypeConcrete(JavaParserFacade.java:551)
    at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.getType(JavaParserFacade.java:398)
    at com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.getType(JavaParserFacade.java:380)
    at com.github.javaparser.symbolsolver.javaparsermodel.contexts.AbstractJavaParserContext.findTypeDeclarations(AbstractJavaParserContext.java:172)
    ... 61 more

However, I do not get an error when making calls to the Java runtime libraries. I think I do not get an error with the Java runtime libraries because of how Java parser is configured with this TypeSolver.addTypeSolverJRE();.

Is there something similar to resolve project dependencies?

cargaji commented 3 years ago

Currently, all calls must be either to the JRE or to a file included via -c or -i. In the future we may handle library calls, but for the moment you can ask maven to download the sources and include them (you may need to unpack the corresponding jar file).

miguelvelezmj25 commented 3 years ago

I see. However, I do not think that handling library calls will be that difficult. Based on JavaParser's ReflectionTypeSolver's docs: "Uses reflection to resolve types. Classes on the classpath used to run your application will be found. No source code is available for the resolved types". That is why the JRE libraries are resolved, because they are loaded into the JVM when running JavaSDGSlicer.

I change this to false, added the hello.Hello .class files to the classpath when running JavaSDGSlicer for the program above, and I did not get an error!

cargaji commented 3 years ago

I'll document this option for other users, then.

The only problem of including libraries this way is that our handling of JRE calls is somewhat lacking. We assume that all arguments are needed but none are modified. The correct approach would be to assume that all arguments and the scope are read and modified. Our current approach is temporary, to avoid all System.out.println calls being included unnecessarily*.