Loading src/main/java/tfm/exec/Main.java +5 −1 Original line number Diff line number Diff line Loading @@ -4,6 +4,10 @@ import com.github.javaparser.JavaParser; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.GenericVisitor; import com.github.javaparser.ast.visitor.VoidVisitor; import com.github.javaparser.resolution.types.ResolvedType; import tfm.graphs.cfg.CFG; import tfm.graphs.Graph; import tfm.graphs.pdg.PDG; Loading @@ -20,7 +24,7 @@ public class Main { public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; public static final String GRAPH = GraphLog.PDG; public static final String METHOD = "sum"; public static final String METHOD = "main"; public static void main(String[] args) throws IOException { JavaParser.getStaticConfiguration().setAttributeComments(false); Loading src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java +29 −14 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import tfm.nodes.TypeNodeFactory; import tfm.nodes.type.NodeType; import tfm.utils.Context; import tfm.utils.Logger; import tfm.utils.MethodDeclarationSolver; import java.nio.file.Path; import java.util.List; Loading Loading @@ -114,7 +115,10 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { Logger.log("MethodCallReplacerVisitor", context); Optional<GraphNode<MethodDeclaration>> optionalNethodDeclarationNode = getMethodDeclarationNodeWithJavaParser(methodCallExpr); Optional<GraphNode<MethodDeclaration>> optionalNethodDeclarationNode = MethodDeclarationSolver.getInstance() .findDeclarationFrom(methodCallExpr) .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)); if (!optionalNethodDeclarationNode.isPresent()) { Logger.format("Not found: '%s'. Discarding", methodCallExpr); Loading Loading @@ -191,6 +195,15 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { } // Out expression if (!argument.isNameExpr() && !sdg.findDeclarationsOfVariable(argument.toString(), methodCallNode).isEmpty()) { /* If the argument is not a variable (is a name expression and it is declared in the scope), then there is no OUT node */ continue; } VariableDeclarationExpr outVariableDeclarationExpr = new VariableDeclarationExpr( new VariableDeclarator( parameter.getType(), Loading @@ -205,13 +218,26 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { sdg.addControlDependencyArc(methodCallNode, argumentOutNode); // Now, find the corresponding method declaration's out node and link argument node with it // Now, find the corresponding method call's out node and link argument node with it Optional<GraphNode<ExpressionStmt>> optionalParameterOutNode = sdg.outgoingEdgesOf(methodDeclarationNode).stream() .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc)) .filter(node -> node.getNodeType() == NodeType.VARIABLE_OUT && node.getInstruction().contains(parameter.getNameAsString() + "_out")) .findFirst(); // Handle data dependency: remove arc from method call node and add it to OUT node List<DataDependencyArc> outDataDependencies = sdg.outgoingEdgesOf(methodCallNode).stream() .filter(arc -> arc.isDataDependencyArc() && Objects.equals(arc.getLabel(), argument.toString())) .map(Arc::asDataDependencyArc) .collect(Collectors.toList()); for (DataDependencyArc arc : outDataDependencies) { GraphNode<?> dataDependencyTarget = sdg.getEdgeTarget(arc); sdg.removeEdge(arc); sdg.addDataDependencyArc(argumentOutNode, dataDependencyTarget, argument.toString()); } if (optionalParameterOutNode.isPresent()) { sdg.addParameterInOutArc(optionalParameterOutNode.get(), argumentOutNode); } else { Loading @@ -224,19 +250,8 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { Logger.log("MethodCallReplacerVisitor", String.format("%s | Method '%s' called", methodCallExpr, methodDeclaration.getNameAsString())); } private Optional<GraphNode<MethodDeclaration>> getMethodDeclarationNodeWithJavaParser(MethodCallExpr methodCallExpr) { TypeSolver typeSolver = new ReflectionTypeSolver(); try { SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(typeSolver).solve(methodCallExpr); private void argumentAsNameExpr(GraphNode<ExpressionStmt> methodCallNode) { return solver.isSolved() ? solver.getCorrespondingDeclaration().toAst() .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)) : Optional.empty(); } catch (UnsolvedSymbolException e) { return Optional.empty(); } } @Override Loading src/main/java/tfm/utils/MethodDeclarationSolver.java +15 −17 Original line number Diff line number Diff line package tfm.utils; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.resolution.UnsolvedSymbolException; Loading @@ -9,39 +8,38 @@ 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.ReflectionTypeSolver; import tfm.nodes.GraphNode; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.*; public class SymbolSolverWrapper { public class MethodDeclarationSolver { private static final SymbolSolverWrapper instance = new SymbolSolverWrapper(); private static final List<TypeSolver> typeSolvers = new ArrayList<>(); private static final MethodDeclarationSolver instance = new MethodDeclarationSolver(); private static final List<TypeSolver> usedTypeSolvers = new ArrayList<>(); private SymbolSolverWrapper() { private MethodDeclarationSolver() { } public static void addTypeSolver(TypeSolver typeSolver) { typeSolvers.add(typeSolver); public static void addTypeSolvers(TypeSolver... typeSolvers) { usedTypeSolvers.addAll(Arrays.asList(typeSolvers)); } public static SymbolSolverWrapper getInstance() { public static MethodDeclarationSolver getInstance() { return instance; } private <N extends Node> Optional<N> findNodeFrom(MethodCallExpr methodCallExpr) { CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); public Optional<MethodDeclaration> findDeclarationFrom(MethodCallExpr methodCallExpr) { return this.findDeclarationFrom(methodCallExpr, usedTypeSolvers); } public Optional<MethodDeclaration> findDeclarationFrom(MethodCallExpr methodCallExpr, Collection<? extends TypeSolver> customTypeSolvers) { CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(customTypeSolvers.toArray(new TypeSolver[0])); try { SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(typeSolver).solve(methodCallExpr); SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(combinedTypeSolver).solve(methodCallExpr); return solver.isSolved() ? solver.getCorrespondingDeclaration().toAst() .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)) : Optional.empty(); } catch (UnsolvedSymbolException e) { return Optional.empty(); Loading src/main/java/tfm/variables/VariableVisitor.java +10 −1 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import org.checkerframework.checker.nullness.qual.NonNull; import tfm.variables.actions.VariableAction; import java.awt.*; abstract class VariableVisitor extends VoidVisitorAdapter<VariableAction.Actions> { @Override Loading Loading @@ -101,7 +103,14 @@ abstract class VariableVisitor extends VoidVisitorAdapter<VariableAction.Actions public void visit(MethodCallExpr n, VariableAction.Actions action) { // // Logger.log("On MethodCallExpr: [" + n + "]"); n.getScope().ifPresent(expression -> expression.accept(this, action.or(VariableAction.Actions.USE))); n.getArguments().forEach(expression -> expression.accept(this, action.or(VariableAction.Actions.USE))); n.getArguments().forEach(expression -> { expression.accept(this, action.or(VariableAction.Actions.USE)); if (expression.isNameExpr() || expression.isFieldAccessExpr()) { expression.accept(this, action.or(VariableAction.Actions.DEFINITION)); } }); } @Override Loading src/test/res/programs/sdg/Example1.java +11 −2 Original line number Diff line number Diff line Loading @@ -11,16 +11,25 @@ public class Example1 { */ int num; public static void main(String[] args) { int x = 1; int y = 2; int f = sum(x, y); Example1 example1 = new Example1(); Example1 example2 = new Example1(); int f = sum(example1.getNum(), example2.num); Logger.log(x); Logger.log(example1.num); Logger.log(f); } public int getNum() { return num; } private static int sum(int x, int y) { int res = x + y; return res; Loading Loading
src/main/java/tfm/exec/Main.java +5 −1 Original line number Diff line number Diff line Loading @@ -4,6 +4,10 @@ import com.github.javaparser.JavaParser; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.GenericVisitor; import com.github.javaparser.ast.visitor.VoidVisitor; import com.github.javaparser.resolution.types.ResolvedType; import tfm.graphs.cfg.CFG; import tfm.graphs.Graph; import tfm.graphs.pdg.PDG; Loading @@ -20,7 +24,7 @@ public class Main { public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; public static final String GRAPH = GraphLog.PDG; public static final String METHOD = "sum"; public static final String METHOD = "main"; public static void main(String[] args) throws IOException { JavaParser.getStaticConfiguration().setAttributeComments(false); Loading
src/main/java/tfm/graphs/sdg/MethodCallReplacerVisitor.java +29 −14 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import tfm.nodes.TypeNodeFactory; import tfm.nodes.type.NodeType; import tfm.utils.Context; import tfm.utils.Logger; import tfm.utils.MethodDeclarationSolver; import java.nio.file.Path; import java.util.List; Loading Loading @@ -114,7 +115,10 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { Logger.log("MethodCallReplacerVisitor", context); Optional<GraphNode<MethodDeclaration>> optionalNethodDeclarationNode = getMethodDeclarationNodeWithJavaParser(methodCallExpr); Optional<GraphNode<MethodDeclaration>> optionalNethodDeclarationNode = MethodDeclarationSolver.getInstance() .findDeclarationFrom(methodCallExpr) .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)); if (!optionalNethodDeclarationNode.isPresent()) { Logger.format("Not found: '%s'. Discarding", methodCallExpr); Loading Loading @@ -191,6 +195,15 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { } // Out expression if (!argument.isNameExpr() && !sdg.findDeclarationsOfVariable(argument.toString(), methodCallNode).isEmpty()) { /* If the argument is not a variable (is a name expression and it is declared in the scope), then there is no OUT node */ continue; } VariableDeclarationExpr outVariableDeclarationExpr = new VariableDeclarationExpr( new VariableDeclarator( parameter.getType(), Loading @@ -205,13 +218,26 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { sdg.addControlDependencyArc(methodCallNode, argumentOutNode); // Now, find the corresponding method declaration's out node and link argument node with it // Now, find the corresponding method call's out node and link argument node with it Optional<GraphNode<ExpressionStmt>> optionalParameterOutNode = sdg.outgoingEdgesOf(methodDeclarationNode).stream() .map(arc -> (GraphNode<ExpressionStmt>) sdg.getEdgeTarget(arc)) .filter(node -> node.getNodeType() == NodeType.VARIABLE_OUT && node.getInstruction().contains(parameter.getNameAsString() + "_out")) .findFirst(); // Handle data dependency: remove arc from method call node and add it to OUT node List<DataDependencyArc> outDataDependencies = sdg.outgoingEdgesOf(methodCallNode).stream() .filter(arc -> arc.isDataDependencyArc() && Objects.equals(arc.getLabel(), argument.toString())) .map(Arc::asDataDependencyArc) .collect(Collectors.toList()); for (DataDependencyArc arc : outDataDependencies) { GraphNode<?> dataDependencyTarget = sdg.getEdgeTarget(arc); sdg.removeEdge(arc); sdg.addDataDependencyArc(argumentOutNode, dataDependencyTarget, argument.toString()); } if (optionalParameterOutNode.isPresent()) { sdg.addParameterInOutArc(optionalParameterOutNode.get(), argumentOutNode); } else { Loading @@ -224,19 +250,8 @@ class MethodCallReplacerVisitor extends VoidVisitorAdapter<Context> { Logger.log("MethodCallReplacerVisitor", String.format("%s | Method '%s' called", methodCallExpr, methodDeclaration.getNameAsString())); } private Optional<GraphNode<MethodDeclaration>> getMethodDeclarationNodeWithJavaParser(MethodCallExpr methodCallExpr) { TypeSolver typeSolver = new ReflectionTypeSolver(); try { SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(typeSolver).solve(methodCallExpr); private void argumentAsNameExpr(GraphNode<ExpressionStmt> methodCallNode) { return solver.isSolved() ? solver.getCorrespondingDeclaration().toAst() .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)) : Optional.empty(); } catch (UnsolvedSymbolException e) { return Optional.empty(); } } @Override Loading
src/main/java/tfm/utils/MethodDeclarationSolver.java +15 −17 Original line number Diff line number Diff line package tfm.utils; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.resolution.UnsolvedSymbolException; Loading @@ -9,39 +8,38 @@ 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.ReflectionTypeSolver; import tfm.nodes.GraphNode; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.*; public class SymbolSolverWrapper { public class MethodDeclarationSolver { private static final SymbolSolverWrapper instance = new SymbolSolverWrapper(); private static final List<TypeSolver> typeSolvers = new ArrayList<>(); private static final MethodDeclarationSolver instance = new MethodDeclarationSolver(); private static final List<TypeSolver> usedTypeSolvers = new ArrayList<>(); private SymbolSolverWrapper() { private MethodDeclarationSolver() { } public static void addTypeSolver(TypeSolver typeSolver) { typeSolvers.add(typeSolver); public static void addTypeSolvers(TypeSolver... typeSolvers) { usedTypeSolvers.addAll(Arrays.asList(typeSolvers)); } public static SymbolSolverWrapper getInstance() { public static MethodDeclarationSolver getInstance() { return instance; } private <N extends Node> Optional<N> findNodeFrom(MethodCallExpr methodCallExpr) { CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); public Optional<MethodDeclaration> findDeclarationFrom(MethodCallExpr methodCallExpr) { return this.findDeclarationFrom(methodCallExpr, usedTypeSolvers); } public Optional<MethodDeclaration> findDeclarationFrom(MethodCallExpr methodCallExpr, Collection<? extends TypeSolver> customTypeSolvers) { CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(customTypeSolvers.toArray(new TypeSolver[0])); try { SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(typeSolver).solve(methodCallExpr); SymbolReference<ResolvedMethodDeclaration> solver = JavaParserFacade.get(combinedTypeSolver).solve(methodCallExpr); return solver.isSolved() ? solver.getCorrespondingDeclaration().toAst() .flatMap(methodDeclaration -> sdg.findNodeByASTNode(methodDeclaration)) : Optional.empty(); } catch (UnsolvedSymbolException e) { return Optional.empty(); Loading
src/main/java/tfm/variables/VariableVisitor.java +10 −1 Original line number Diff line number Diff line Loading @@ -7,6 +7,8 @@ import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import org.checkerframework.checker.nullness.qual.NonNull; import tfm.variables.actions.VariableAction; import java.awt.*; abstract class VariableVisitor extends VoidVisitorAdapter<VariableAction.Actions> { @Override Loading Loading @@ -101,7 +103,14 @@ abstract class VariableVisitor extends VoidVisitorAdapter<VariableAction.Actions public void visit(MethodCallExpr n, VariableAction.Actions action) { // // Logger.log("On MethodCallExpr: [" + n + "]"); n.getScope().ifPresent(expression -> expression.accept(this, action.or(VariableAction.Actions.USE))); n.getArguments().forEach(expression -> expression.accept(this, action.or(VariableAction.Actions.USE))); n.getArguments().forEach(expression -> { expression.accept(this, action.or(VariableAction.Actions.USE)); if (expression.isNameExpr() || expression.isFieldAccessExpr()) { expression.accept(this, action.or(VariableAction.Actions.DEFINITION)); } }); } @Override Loading
src/test/res/programs/sdg/Example1.java +11 −2 Original line number Diff line number Diff line Loading @@ -11,16 +11,25 @@ public class Example1 { */ int num; public static void main(String[] args) { int x = 1; int y = 2; int f = sum(x, y); Example1 example1 = new Example1(); Example1 example2 = new Example1(); int f = sum(example1.getNum(), example2.num); Logger.log(x); Logger.log(example1.num); Logger.log(f); } public int getNum() { return num; } private static int sum(int x, int y) { int res = x + y; return res; Loading