Loading src/main/java/tfm/exec/Main.java +2 −2 Original line number Diff line number Diff line Loading @@ -13,8 +13,8 @@ import java.util.Optional; public class Main { public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "pdg/Test.java"; public static final String GRAPH = GraphLog.PDG; public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; public static final String GRAPH = GraphLog.SDG; public static final String METHOD = "main"; public static void main(String[] args) throws IOException { Loading src/main/java/tfm/programs/sdg/Example1.java +12 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,10 @@ import tfm.utils.Logger; public class Example1 { public Example1() { } public static void main(String[] args) { int x = 1; int y = 2; Loading @@ -17,4 +21,12 @@ public class Example1 { int res = x + y; return res; } public int m1() { return 1; } public int m2() { return m1(); } } src/main/java/tfm/utils/Context.java 0 → 100644 +91 −0 Original line number Diff line number Diff line package tfm.utils; 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.MethodDeclaration; import java.util.Objects; import java.util.Optional; public class Context { private CompilationUnit currentCU; private ClassOrInterfaceDeclaration currentClass; private MethodDeclaration currentMethod; public Context() { } public Context(CompilationUnit cu) { this(cu, null, null); } public Context(CompilationUnit cu, ClassOrInterfaceDeclaration clazz) { this(cu, clazz, null); } public Context(CompilationUnit cu, ClassOrInterfaceDeclaration clazz, MethodDeclaration method) { this.currentCU = cu; this.currentClass = clazz; this.currentMethod = method; } public Optional<CompilationUnit> getCurrentCU() { return Optional.ofNullable(currentCU); } public Optional<ClassOrInterfaceDeclaration> getCurrentClass() { return Optional.ofNullable(currentClass); } public Optional<MethodDeclaration> getCurrentMethod() { return Optional.ofNullable(currentMethod); } public void setCurrentCU(CompilationUnit currentCU) { this.currentCU = currentCU; } public void setCurrentClass(ClassOrInterfaceDeclaration currentClass) { this.currentClass = currentClass; } public void setCurrentMethod(MethodDeclaration currentMethod) { this.currentMethod = currentMethod; } @Override public int hashCode() { return getCurrentCU().map(Node::hashCode).orElse(0) + getCurrentClass().map(Node::hashCode).orElse(0) + getCurrentMethod().map(Node::hashCode).orElse(0); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Context)) { return false; } Context other = (Context) obj; return Objects.equals(currentCU, other.currentCU) && Objects.equals(currentClass, other.currentClass) && Objects.equals(currentMethod, other.currentMethod); } @Override public String toString() { return String.format("Context{compilationUnit: %s, class: %s, method: %s}", getCurrentCU().map(Node::toString), getCurrentClass().map(Node::toString), getCurrentMethod().map(Node::toString) ); } } src/main/java/tfm/visitors/MethodCallVisitor.java 0 → 100644 +141 −0 Original line number Diff line number Diff line package tfm.visitors; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.SDGGraph; import tfm.nodes.GraphNode; import tfm.utils.Context; import java.lang.reflect.Method; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; public class MethodCallVisitor extends VoidVisitorAdapter<Context> { SDGGraph sdgGraph; public MethodCallVisitor(SDGGraph sdgGraph) { this.sdgGraph = sdgGraph; } @Override public void visit(MethodCallExpr methodCallExpr, Context context) { Optional<MethodDeclaration> optionalCallingMethod = methodCallExpr.getScope().isPresent() ? shouldMakeCallWithScope(methodCallExpr, context) : shouldMakeCallWithNoScope(methodCallExpr, context); if (!optionalCallingMethod.isPresent()) { return; } // todo make call } private Optional<MethodDeclaration> shouldMakeCallWithScope(MethodCallExpr methodCallExpr, Context context) { assert methodCallExpr.getScope().isPresent(); String scopeName = methodCallExpr.getScope().get().toString(); if (!context.getCurrentClass().isPresent()) { return Optional.empty(); } ClassOrInterfaceDeclaration currentClass = context.getCurrentClass().get(); // Check if it's a static method call of current class if (!Objects.equals(scopeName, currentClass.getNameAsString())) { // Check if 'scopeName' is a variable List<GraphNode<?>> declarations = sdgGraph.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We do nothing return Optional.empty(); } /* It's a variable since it has declarations. We now have to check if the class name is the same as the current class (the object is an instance of our class) */ GraphNode<?> declarationNode = declarations.get(declarations.size() - 1); ExpressionStmt declarationExpr = (ExpressionStmt) declarationNode.getAstNode(); VariableDeclarationExpr variableDeclarationExpr = declarationExpr.getExpression().asVariableDeclarationExpr(); Optional<VariableDeclarator> optionalVariableDeclarator = variableDeclarationExpr.getVariables().stream() .filter(variableDeclarator -> Objects.equals(variableDeclarator.getNameAsString(), scopeName)) .findFirst(); if (!optionalVariableDeclarator.isPresent()) { // should not happen return Optional.empty(); } Type variableType = optionalVariableDeclarator.get().getType(); if (!variableType.isClassOrInterfaceType()) { // Not class type return Optional.empty(); } if (!Objects.equals(variableType.asClassOrInterfaceType().getNameAsString(), currentClass.getNameAsString())) { // object is not instance of our class return Optional.empty(); } // if we got here, the object is instance of our class } // It's a static method call to a method of the current class return findMethodInClass(methodCallExpr, currentClass); } private Optional<MethodDeclaration> shouldMakeCallWithNoScope(MethodCallExpr methodCallExpr, Context context) { assert !methodCallExpr.getScope().isPresent(); /* May be a call to a method of the current class or a call to an imported static method. In the first case, we make the call. Otherwise, not. */ if (!context.getCurrentClass().isPresent()) { return Optional.empty(); } // We get the current class and search along their methods to find the one we're looking for... ClassOrInterfaceDeclaration currentClass = context.getCurrentClass().get(); return findMethodInClass(methodCallExpr, currentClass); } private Optional<MethodDeclaration> findMethodInClass(MethodCallExpr methodCallExpr, ClassOrInterfaceDeclaration klass) { String[] typeParameters = methodCallExpr.getTypeArguments() .map(types -> types.stream() .map(Node::toString) .collect(Collectors.toList()) .toArray(new String[types.size()]) ).orElse(new String[]{}); List<MethodDeclaration> classMethods = klass.getMethodsBySignature(methodCallExpr.getNameAsString(), typeParameters); if (classMethods.isEmpty()) { return Optional.empty(); // The method called is not inside the current class } // The current method is inside the current class, so we make the call return Optional.of(classMethods.get(0)); } } src/main/java/tfm/visitors/NewSDGVisitor.java 0 → 100644 +68 −0 Original line number Diff line number Diff line package tfm.visitors; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.PDGGraph; import tfm.graphs.SDGGraph; import tfm.utils.Context; import java.util.ArrayList; import java.util.List; public class NewSDGVisitor extends VoidVisitorAdapter<Context> { SDGGraph sdgGraph; List<PDGGraph> pdgGraphs; public NewSDGVisitor(SDGGraph sdgGraph) { this.sdgGraph = sdgGraph; this.pdgGraphs = new ArrayList<>(); } @Override public void visit(MethodDeclaration methodDeclaration, Context context) { if (!methodDeclaration.getBody().isPresent()) { return; } context.setCurrentMethod(methodDeclaration); // 1. Build PDG PDGGraph pdgGraph = new PDGGraph(); PDGCFGVisitor pdgcfgVisitor = new PDGCFGVisitor(pdgGraph); methodDeclaration.accept(pdgcfgVisitor, pdgGraph.getRootNode()); // 2. Expand method call nodes (build input and output variable nodes) // 2.1 Visit called methods with this visitor // 3. Build summary arcs } @Override public void visit(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, Context context) { // if (sdgGraph.getRootNode() != null) { // throw new IllegalStateException("¡Solo podemos procesar una clase por el momento!"); // } if (classOrInterfaceDeclaration.isInterface()) { throw new IllegalArgumentException("¡Las interfaces no estan permitidas!"); } context.setCurrentClass(classOrInterfaceDeclaration); classOrInterfaceDeclaration.accept(this, context); } @Override public void visit(CompilationUnit compilationUnit, Context context) { context.setCurrentCU(compilationUnit); super.visit(compilationUnit, context); } } Loading
src/main/java/tfm/exec/Main.java +2 −2 Original line number Diff line number Diff line Loading @@ -13,8 +13,8 @@ import java.util.Optional; public class Main { public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "pdg/Test.java"; public static final String GRAPH = GraphLog.PDG; public static final String PROGRAM = Utils.PROGRAMS_FOLDER + "sdg/Example1.java"; public static final String GRAPH = GraphLog.SDG; public static final String METHOD = "main"; public static void main(String[] args) throws IOException { Loading
src/main/java/tfm/programs/sdg/Example1.java +12 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,10 @@ import tfm.utils.Logger; public class Example1 { public Example1() { } public static void main(String[] args) { int x = 1; int y = 2; Loading @@ -17,4 +21,12 @@ public class Example1 { int res = x + y; return res; } public int m1() { return 1; } public int m2() { return m1(); } }
src/main/java/tfm/utils/Context.java 0 → 100644 +91 −0 Original line number Diff line number Diff line package tfm.utils; 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.MethodDeclaration; import java.util.Objects; import java.util.Optional; public class Context { private CompilationUnit currentCU; private ClassOrInterfaceDeclaration currentClass; private MethodDeclaration currentMethod; public Context() { } public Context(CompilationUnit cu) { this(cu, null, null); } public Context(CompilationUnit cu, ClassOrInterfaceDeclaration clazz) { this(cu, clazz, null); } public Context(CompilationUnit cu, ClassOrInterfaceDeclaration clazz, MethodDeclaration method) { this.currentCU = cu; this.currentClass = clazz; this.currentMethod = method; } public Optional<CompilationUnit> getCurrentCU() { return Optional.ofNullable(currentCU); } public Optional<ClassOrInterfaceDeclaration> getCurrentClass() { return Optional.ofNullable(currentClass); } public Optional<MethodDeclaration> getCurrentMethod() { return Optional.ofNullable(currentMethod); } public void setCurrentCU(CompilationUnit currentCU) { this.currentCU = currentCU; } public void setCurrentClass(ClassOrInterfaceDeclaration currentClass) { this.currentClass = currentClass; } public void setCurrentMethod(MethodDeclaration currentMethod) { this.currentMethod = currentMethod; } @Override public int hashCode() { return getCurrentCU().map(Node::hashCode).orElse(0) + getCurrentClass().map(Node::hashCode).orElse(0) + getCurrentMethod().map(Node::hashCode).orElse(0); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Context)) { return false; } Context other = (Context) obj; return Objects.equals(currentCU, other.currentCU) && Objects.equals(currentClass, other.currentClass) && Objects.equals(currentMethod, other.currentMethod); } @Override public String toString() { return String.format("Context{compilationUnit: %s, class: %s, method: %s}", getCurrentCU().map(Node::toString), getCurrentClass().map(Node::toString), getCurrentMethod().map(Node::toString) ); } }
src/main/java/tfm/visitors/MethodCallVisitor.java 0 → 100644 +141 −0 Original line number Diff line number Diff line package tfm.visitors; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.VariableDeclarationExpr; import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.SDGGraph; import tfm.nodes.GraphNode; import tfm.utils.Context; import java.lang.reflect.Method; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; public class MethodCallVisitor extends VoidVisitorAdapter<Context> { SDGGraph sdgGraph; public MethodCallVisitor(SDGGraph sdgGraph) { this.sdgGraph = sdgGraph; } @Override public void visit(MethodCallExpr methodCallExpr, Context context) { Optional<MethodDeclaration> optionalCallingMethod = methodCallExpr.getScope().isPresent() ? shouldMakeCallWithScope(methodCallExpr, context) : shouldMakeCallWithNoScope(methodCallExpr, context); if (!optionalCallingMethod.isPresent()) { return; } // todo make call } private Optional<MethodDeclaration> shouldMakeCallWithScope(MethodCallExpr methodCallExpr, Context context) { assert methodCallExpr.getScope().isPresent(); String scopeName = methodCallExpr.getScope().get().toString(); if (!context.getCurrentClass().isPresent()) { return Optional.empty(); } ClassOrInterfaceDeclaration currentClass = context.getCurrentClass().get(); // Check if it's a static method call of current class if (!Objects.equals(scopeName, currentClass.getNameAsString())) { // Check if 'scopeName' is a variable List<GraphNode<?>> declarations = sdgGraph.findDeclarationsOfVariable(scopeName); if (declarations.isEmpty()) { // It is a static method call of another class. We do nothing return Optional.empty(); } /* It's a variable since it has declarations. We now have to check if the class name is the same as the current class (the object is an instance of our class) */ GraphNode<?> declarationNode = declarations.get(declarations.size() - 1); ExpressionStmt declarationExpr = (ExpressionStmt) declarationNode.getAstNode(); VariableDeclarationExpr variableDeclarationExpr = declarationExpr.getExpression().asVariableDeclarationExpr(); Optional<VariableDeclarator> optionalVariableDeclarator = variableDeclarationExpr.getVariables().stream() .filter(variableDeclarator -> Objects.equals(variableDeclarator.getNameAsString(), scopeName)) .findFirst(); if (!optionalVariableDeclarator.isPresent()) { // should not happen return Optional.empty(); } Type variableType = optionalVariableDeclarator.get().getType(); if (!variableType.isClassOrInterfaceType()) { // Not class type return Optional.empty(); } if (!Objects.equals(variableType.asClassOrInterfaceType().getNameAsString(), currentClass.getNameAsString())) { // object is not instance of our class return Optional.empty(); } // if we got here, the object is instance of our class } // It's a static method call to a method of the current class return findMethodInClass(methodCallExpr, currentClass); } private Optional<MethodDeclaration> shouldMakeCallWithNoScope(MethodCallExpr methodCallExpr, Context context) { assert !methodCallExpr.getScope().isPresent(); /* May be a call to a method of the current class or a call to an imported static method. In the first case, we make the call. Otherwise, not. */ if (!context.getCurrentClass().isPresent()) { return Optional.empty(); } // We get the current class and search along their methods to find the one we're looking for... ClassOrInterfaceDeclaration currentClass = context.getCurrentClass().get(); return findMethodInClass(methodCallExpr, currentClass); } private Optional<MethodDeclaration> findMethodInClass(MethodCallExpr methodCallExpr, ClassOrInterfaceDeclaration klass) { String[] typeParameters = methodCallExpr.getTypeArguments() .map(types -> types.stream() .map(Node::toString) .collect(Collectors.toList()) .toArray(new String[types.size()]) ).orElse(new String[]{}); List<MethodDeclaration> classMethods = klass.getMethodsBySignature(methodCallExpr.getNameAsString(), typeParameters); if (classMethods.isEmpty()) { return Optional.empty(); // The method called is not inside the current class } // The current method is inside the current class, so we make the call return Optional.of(classMethods.get(0)); } }
src/main/java/tfm/visitors/NewSDGVisitor.java 0 → 100644 +68 −0 Original line number Diff line number Diff line package tfm.visitors; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; import tfm.graphs.PDGGraph; import tfm.graphs.SDGGraph; import tfm.utils.Context; import java.util.ArrayList; import java.util.List; public class NewSDGVisitor extends VoidVisitorAdapter<Context> { SDGGraph sdgGraph; List<PDGGraph> pdgGraphs; public NewSDGVisitor(SDGGraph sdgGraph) { this.sdgGraph = sdgGraph; this.pdgGraphs = new ArrayList<>(); } @Override public void visit(MethodDeclaration methodDeclaration, Context context) { if (!methodDeclaration.getBody().isPresent()) { return; } context.setCurrentMethod(methodDeclaration); // 1. Build PDG PDGGraph pdgGraph = new PDGGraph(); PDGCFGVisitor pdgcfgVisitor = new PDGCFGVisitor(pdgGraph); methodDeclaration.accept(pdgcfgVisitor, pdgGraph.getRootNode()); // 2. Expand method call nodes (build input and output variable nodes) // 2.1 Visit called methods with this visitor // 3. Build summary arcs } @Override public void visit(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, Context context) { // if (sdgGraph.getRootNode() != null) { // throw new IllegalStateException("¡Solo podemos procesar una clase por el momento!"); // } if (classOrInterfaceDeclaration.isInterface()) { throw new IllegalArgumentException("¡Las interfaces no estan permitidas!"); } context.setCurrentClass(classOrInterfaceDeclaration); classOrInterfaceDeclaration.accept(this, context); } @Override public void visit(CompilationUnit compilationUnit, Context context) { context.setCurrentCU(compilationUnit); super.visit(compilationUnit, context); } }