Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java +13 −6 Original line number Diff line number Diff line Loading @@ -133,14 +133,21 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E /** Find the calls to methods and constructors (edges) in the given list of compilation units. */ protected void buildEdges(NodeList<CompilationUnit> arg) { arg.accept(new VoidVisitorAdapter<Void>() { private final Deque<ClassOrInterfaceDeclaration> classStack = new LinkedList<>(); private final Deque<TypeDeclaration<?>> typeStack = new LinkedList<>(); private final Deque<CallableDeclaration<?>> declStack = new LinkedList<>(); @Override public void visit(ClassOrInterfaceDeclaration n, Void arg) { classStack.push(n); typeStack.push(n); super.visit(n, arg); classStack.pop(); typeStack.pop(); } @Override public void visit(EnumDeclaration n, Void arg) { typeStack.push(n); super.visit(n, arg); typeStack.pop(); } // ============ Method declarations =========== Loading Loading @@ -189,7 +196,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E } Optional<Expression> scope = call.getScope(); // Determine the type of the call's scope Set<ClassOrInterfaceDeclaration> dynamicTypes; Set<? extends TypeDeclaration<?>> dynamicTypes; if (scope.isEmpty()) { // a) No scope: any class the method is in, or any outer class if the class is not static. // Early exit: it is easier to find the methods that override the Loading @@ -199,7 +206,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E return; } else if (scope.get().isThisExpr() && scope.get().asThisExpr().getTypeName().isEmpty()) { // b) just 'this', the current class and any subclass dynamicTypes = classGraph.subclassesOf(classStack.peek()); dynamicTypes = classGraph.subclassesOf(typeStack.peek()); } else if (scope.get().isThisExpr()) { // c) 'ClassName.this', the given class and any subclass dynamicTypes = classGraph.subclassesOf(scope.get().asThisExpr().resolve().asClass()); Loading Loading @@ -229,7 +236,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E @Override public void visit(FieldDeclaration n, Void arg) { if (declStack.isEmpty() && !n.isStatic()) { for (ConstructorDeclaration cd : classStack.peek().getConstructors()) { for (ConstructorDeclaration cd : typeStack.peek().getConstructors()) { declStack.push(cd); super.visit(n, arg); declStack.pop(); Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/ClassGraph.java +45 −38 Original line number Diff line number Diff line Loading @@ -52,9 +52,8 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG /** Locates the vertex that represents a given class or interface declaration. * If the vertex is not contained in the graph, {@code null} will be returned. */ @SuppressWarnings("unchecked") protected Vertex<ClassOrInterfaceDeclaration> findClassVertex(ClassOrInterfaceDeclaration declaration) { return (Vertex<ClassOrInterfaceDeclaration>) classDeclarationMap.get(mapKey(declaration)); protected Vertex<? extends TypeDeclaration<?>> findClassVertex(TypeDeclaration<?> declaration) { return classDeclarationMap.get(mapKey(declaration)); } /** Whether this graph contains the given type as a vertex. */ Loading @@ -64,7 +63,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG /** Set of method declarations that override the given argument. */ public Set<MethodDeclaration> overriddenSetOf(MethodDeclaration method) { return subclassesStreamOf(findClassVertex(method.findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow())) return subclassesStreamOf(findClassVertex(method.findAncestor(TypeDeclaration.class).orElseThrow())) .flatMap(vertex -> outgoingEdgesOf(vertex).stream() .filter(ClassArc.Member.class::isInstance) .map(ClassGraph.this::getEdgeTarget) Loading Loading @@ -95,51 +94,52 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG } /** Returns all child classes of the given class, including itself. */ public Set<ClassOrInterfaceDeclaration> subclassesOf(ClassOrInterfaceDeclaration clazz) { public Set<? extends TypeDeclaration<?>> subclassesOf(TypeDeclaration<?> clazz) { return subclassesOf(findClassVertex(clazz)); } /** Returns all child classes of the given class, including itself. */ public Set<ClassOrInterfaceDeclaration> subclassesOf(ResolvedClassDeclaration clazz) { public Set<? extends TypeDeclaration<?>> subclassesOf(ResolvedClassDeclaration clazz) { return subclassesOf(classDeclarationMap.get(mapKey(clazz))); } public Set<ClassOrInterfaceDeclaration> subclassesOf(ResolvedReferenceType type) { public Set<? extends TypeDeclaration<?>> subclassesOf(ResolvedReferenceType type) { return subclassesOf(classDeclarationMap.get(mapKey(type))); } /** @see #subclassesOf(ClassOrInterfaceDeclaration) */ @SuppressWarnings("unchecked") protected Set<ClassOrInterfaceDeclaration> subclassesOf(Vertex<? extends TypeDeclaration<?>> v) { /** @see #subclassesOf(TypeDeclaration) */ protected Set<? extends TypeDeclaration<?>> subclassesOf(Vertex<? extends TypeDeclaration<?>> v) { if (v.getDeclaration() instanceof EnumDeclaration) return Collections.emptySet(); return subclassesStreamOf((Vertex<ClassOrInterfaceDeclaration>) v) return Set.of(v.getDeclaration()); return subclassesStreamOf(v) .map(Vertex::getDeclaration) .map(ClassOrInterfaceDeclaration.class::cast) .collect(Collectors.toSet()); } @SuppressWarnings("unchecked") protected Stream<Vertex<ClassOrInterfaceDeclaration>> subclassesStreamOf(Vertex<ClassOrInterfaceDeclaration> classVertex) { protected Stream<Vertex<? extends TypeDeclaration<?>>> subclassesStreamOf(Vertex<? extends TypeDeclaration<?>> classVertex) { return Stream.concat(Stream.of(classVertex), outgoingEdgesOf(classVertex).stream() .filter(ClassArc.Extends.class::isInstance) .map(this::getEdgeTarget) .map(v -> (Vertex<ClassOrInterfaceDeclaration>) v) .map(v -> (Vertex<? extends TypeDeclaration<?>>) v) .flatMap(this::subclassesStreamOf)); } // TODO: this method ignores default method implementations in interfaces, as can be overridden. /** Looks up a method in the graph, going up the class inheritance tree to locate a * matching method. If no match can be found, throws an {@link IllegalArgumentException}. */ public MethodDeclaration findMethodByTypeAndSignature(ClassOrInterfaceDeclaration type, CallableDeclaration<?> declaration) { public MethodDeclaration findMethodByTypeAndSignature(TypeDeclaration<?> type, CallableDeclaration<?> declaration) { Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(declaration, type)); if (v != null && v.declaration.isMethodDeclaration()) return v.declaration.asMethodDeclaration(); Optional<ClassOrInterfaceDeclaration> parentType = parentOf(type); if (parentType.isEmpty()) throw new IllegalArgumentException("Cannot find the given declaration: " + declaration); if (type.isClassOrInterfaceDeclaration()) { Optional<ClassOrInterfaceDeclaration> parentType = parentOf(type.asClassOrInterfaceDeclaration()); if (parentType.isPresent()) return findMethodByTypeAndSignature(parentType.get(), declaration); } throw new IllegalArgumentException("Cannot find the given declaration: " + declaration); } /** Find the parent class or interface of a given class. */ public Optional<ClassOrInterfaceDeclaration> parentOf(ClassOrInterfaceDeclaration declaration) { Loading @@ -164,7 +164,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG else return Optional.empty(); } else if (callableDeclaration.isConstructorDeclaration()) { return Optional.of(generateObjectTreeFor(ASTUtils.getClassNode(callableDeclaration))); return Optional.of(generateObjectTreeFor(callableDeclaration.findAncestor(TypeDeclaration.class).orElseThrow())); } else { throw new IllegalArgumentException("Invalid callable declaration type"); } Loading @@ -179,7 +179,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG return Optional.empty(); } public ObjectTree generateObjectTreeFor(ClassOrInterfaceDeclaration declaration) { public ObjectTree generateObjectTreeFor(TypeDeclaration<?> declaration) { return generateObjectTreeFor(classDeclarationMap.get(mapKey(declaration))); } Loading @@ -196,11 +196,11 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG protected ObjectTree generatePolyObjectTreeFor(Vertex<? extends TypeDeclaration<?>> classVertex, ObjectTree tree, String level, int depth) { if (depth >= StaticConfig.K_LIMIT) return tree; Set<ClassOrInterfaceDeclaration> types = subclassesOf(classVertex); Set<? extends TypeDeclaration<?>> types = subclassesOf(classVertex); if (types.isEmpty()) { generateObjectTreeFor(classVertex, tree, level, depth); } else { for (ClassOrInterfaceDeclaration type : types) { for (TypeDeclaration<?> type : types) { Vertex<? extends TypeDeclaration<?>> subclassVertex = classDeclarationMap.get(mapKey(type)); if (!findAllFieldsOf(subclassVertex).isEmpty()) { ObjectTree newType = tree.addType(ASTUtils.resolvedTypeDeclarationToResolvedType(type.resolve()), level); Loading Loading @@ -355,41 +355,48 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG * member/extends/implements relationships in the given list of compilation units. */ protected void buildEdges(NodeList<CompilationUnit> arg) { arg.accept(new VoidVisitorAdapter<Void>() { private final Deque<ClassOrInterfaceDeclaration> classStack = new LinkedList<>(); private final Deque<TypeDeclaration<?>> typeStack = new LinkedList<>(); @Override public void visit(ClassOrInterfaceDeclaration n, Void arg) { classStack.push(n); typeStack.push(n); var v = classDeclarationMap.get(mapKey(n)); addClassEdges(v); super.visit(n, arg); classStack.pop(); typeStack.pop(); } @Override public void visit(EnumDeclaration n, Void arg) { typeStack.push(n); super.visit(n, arg); typeStack.pop(); } @Override public void visit(FieldDeclaration n, Void arg) { ClassOrInterfaceDeclaration clazz = classStack.peek(); assert clazz != null; var c = classDeclarationMap.get(mapKey(clazz)); Vertex<FieldDeclaration> v = fieldDeclarationMap.get(mapKey(n, clazz)); assert !typeStack.isEmpty(); TypeDeclaration<?> type = typeStack.peek(); var c = classDeclarationMap.get(mapKey(type)); Vertex<FieldDeclaration> v = fieldDeclarationMap.get(mapKey(n, type)); addEdge(c, v, new ClassArc.Member()); } @Override public void visit(MethodDeclaration n, Void arg) { ClassOrInterfaceDeclaration clazz = classStack.peek(); assert clazz != null; var c = classDeclarationMap.get(mapKey(clazz)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, clazz)); assert !typeStack.isEmpty(); TypeDeclaration<?> type = typeStack.peek(); var c = classDeclarationMap.get(mapKey(type)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, type)); addEdge(c, v, new ClassArc.Member()); } @Override public void visit(ConstructorDeclaration n, Void arg) { ClassOrInterfaceDeclaration clazz = classStack.peek(); assert clazz != null; var c = classDeclarationMap.get(mapKey(clazz)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, clazz)); assert !typeStack.isEmpty(); TypeDeclaration<?> type = typeStack.peek(); var c = classDeclarationMap.get(mapKey(type)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, type)); addEdge(c, v, new ClassArc.Member()); } }, null); Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/jsysdg/JSysCFG.java +19 −2 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.ThisExpr; import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; Loading Loading @@ -197,7 +198,7 @@ public class JSysCFG extends ESCFG { connectTo(n); // 2. Insert dynamic class code (only for super()) if (!n.isThis()) ASTUtils.getClassInit(ASTUtils.getClassNode(rootNode.getAstNode()), false) ASTUtils.getTypeInit(n.findAncestor(TypeDeclaration.class).orElseThrow(), false) .forEach(node -> node.accept(this, arg)); // 3. Handle exceptions super.visitCallForExceptions(n); Loading @@ -213,7 +214,7 @@ public class JSysCFG extends ESCFG { @Override public void visit(ConstructorDeclaration n, Void arg) { // Insert call to super() if it is implicit. if (!ASTUtils.constructorHasExplicitConstructorInvocation(n)){ if (ASTUtils.shouldInsertExplicitConstructorInvocation(n)) { var superCall = new ExplicitConstructorInvocationStmt(null, null, false, null, new NodeList<>()); methodInsertedInstructions.add(superCall); n.getBody().addStatement(0, superCall); Loading @@ -237,6 +238,22 @@ public class JSysCFG extends ESCFG { } } @Override protected void buildEnter(CallableDeclaration<?> callableDeclaration) { super.buildEnter(callableDeclaration); // enums have no super(), so the implicitly inserted instructions // must be placed after the root node if (callableDeclaration.isConstructorDeclaration()) { ConstructorDeclaration cd = callableDeclaration.asConstructorDeclaration(); TypeDeclaration<?> type = cd.findAncestor(TypeDeclaration.class).orElseThrow(); if (!ASTUtils.shouldInsertExplicitConstructorInvocation(cd) && type.isEnumDeclaration() && ASTUtils.shouldInsertDynamicInitInEnum(cd)) { ASTUtils.getTypeInit(type, false).forEach(n -> n.accept(this, null)); } } } /** * Sets the expression for all return statements contained in its argument. * @param node The AST to search for return statements. Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/jsysdg/JSysDG.java +7 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,13 @@ public class JSysDG extends ESSDG { newlyInsertedConstructors.add(n.addConstructor(Modifier.Keyword.PUBLIC)); return super.visit(n, arg); } @Override public Visitable visit(EnumDeclaration n, Object arg) { if (n.getConstructors().isEmpty()) newlyInsertedConstructors.add(n.addConstructor()); return super.visit(n, arg); } }, null); } Loading sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java +2 −2 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ package es.upv.mist.slicing.graphs.oo; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.MethodCallExpr; Loading Loading @@ -151,7 +151,7 @@ public class DynamicTypeResolver { ResolvedClassDeclaration type = expression.calculateResolvedType().asReferenceType() .getTypeDeclaration().orElseThrow().asClass(); return classGraph.subclassesOf(type).stream() .map(ClassOrInterfaceDeclaration::resolve) .map(TypeDeclaration::resolve) .map(ASTUtils::resolvedTypeDeclarationToResolvedType); } } Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java +13 −6 Original line number Diff line number Diff line Loading @@ -133,14 +133,21 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E /** Find the calls to methods and constructors (edges) in the given list of compilation units. */ protected void buildEdges(NodeList<CompilationUnit> arg) { arg.accept(new VoidVisitorAdapter<Void>() { private final Deque<ClassOrInterfaceDeclaration> classStack = new LinkedList<>(); private final Deque<TypeDeclaration<?>> typeStack = new LinkedList<>(); private final Deque<CallableDeclaration<?>> declStack = new LinkedList<>(); @Override public void visit(ClassOrInterfaceDeclaration n, Void arg) { classStack.push(n); typeStack.push(n); super.visit(n, arg); classStack.pop(); typeStack.pop(); } @Override public void visit(EnumDeclaration n, Void arg) { typeStack.push(n); super.visit(n, arg); typeStack.pop(); } // ============ Method declarations =========== Loading Loading @@ -189,7 +196,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E } Optional<Expression> scope = call.getScope(); // Determine the type of the call's scope Set<ClassOrInterfaceDeclaration> dynamicTypes; Set<? extends TypeDeclaration<?>> dynamicTypes; if (scope.isEmpty()) { // a) No scope: any class the method is in, or any outer class if the class is not static. // Early exit: it is easier to find the methods that override the Loading @@ -199,7 +206,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E return; } else if (scope.get().isThisExpr() && scope.get().asThisExpr().getTypeName().isEmpty()) { // b) just 'this', the current class and any subclass dynamicTypes = classGraph.subclassesOf(classStack.peek()); dynamicTypes = classGraph.subclassesOf(typeStack.peek()); } else if (scope.get().isThisExpr()) { // c) 'ClassName.this', the given class and any subclass dynamicTypes = classGraph.subclassesOf(scope.get().asThisExpr().resolve().asClass()); Loading Loading @@ -229,7 +236,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E @Override public void visit(FieldDeclaration n, Void arg) { if (declStack.isEmpty() && !n.isStatic()) { for (ConstructorDeclaration cd : classStack.peek().getConstructors()) { for (ConstructorDeclaration cd : typeStack.peek().getConstructors()) { declStack.push(cd); super.visit(n, arg); declStack.pop(); Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/ClassGraph.java +45 −38 Original line number Diff line number Diff line Loading @@ -52,9 +52,8 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG /** Locates the vertex that represents a given class or interface declaration. * If the vertex is not contained in the graph, {@code null} will be returned. */ @SuppressWarnings("unchecked") protected Vertex<ClassOrInterfaceDeclaration> findClassVertex(ClassOrInterfaceDeclaration declaration) { return (Vertex<ClassOrInterfaceDeclaration>) classDeclarationMap.get(mapKey(declaration)); protected Vertex<? extends TypeDeclaration<?>> findClassVertex(TypeDeclaration<?> declaration) { return classDeclarationMap.get(mapKey(declaration)); } /** Whether this graph contains the given type as a vertex. */ Loading @@ -64,7 +63,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG /** Set of method declarations that override the given argument. */ public Set<MethodDeclaration> overriddenSetOf(MethodDeclaration method) { return subclassesStreamOf(findClassVertex(method.findAncestor(ClassOrInterfaceDeclaration.class).orElseThrow())) return subclassesStreamOf(findClassVertex(method.findAncestor(TypeDeclaration.class).orElseThrow())) .flatMap(vertex -> outgoingEdgesOf(vertex).stream() .filter(ClassArc.Member.class::isInstance) .map(ClassGraph.this::getEdgeTarget) Loading Loading @@ -95,51 +94,52 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG } /** Returns all child classes of the given class, including itself. */ public Set<ClassOrInterfaceDeclaration> subclassesOf(ClassOrInterfaceDeclaration clazz) { public Set<? extends TypeDeclaration<?>> subclassesOf(TypeDeclaration<?> clazz) { return subclassesOf(findClassVertex(clazz)); } /** Returns all child classes of the given class, including itself. */ public Set<ClassOrInterfaceDeclaration> subclassesOf(ResolvedClassDeclaration clazz) { public Set<? extends TypeDeclaration<?>> subclassesOf(ResolvedClassDeclaration clazz) { return subclassesOf(classDeclarationMap.get(mapKey(clazz))); } public Set<ClassOrInterfaceDeclaration> subclassesOf(ResolvedReferenceType type) { public Set<? extends TypeDeclaration<?>> subclassesOf(ResolvedReferenceType type) { return subclassesOf(classDeclarationMap.get(mapKey(type))); } /** @see #subclassesOf(ClassOrInterfaceDeclaration) */ @SuppressWarnings("unchecked") protected Set<ClassOrInterfaceDeclaration> subclassesOf(Vertex<? extends TypeDeclaration<?>> v) { /** @see #subclassesOf(TypeDeclaration) */ protected Set<? extends TypeDeclaration<?>> subclassesOf(Vertex<? extends TypeDeclaration<?>> v) { if (v.getDeclaration() instanceof EnumDeclaration) return Collections.emptySet(); return subclassesStreamOf((Vertex<ClassOrInterfaceDeclaration>) v) return Set.of(v.getDeclaration()); return subclassesStreamOf(v) .map(Vertex::getDeclaration) .map(ClassOrInterfaceDeclaration.class::cast) .collect(Collectors.toSet()); } @SuppressWarnings("unchecked") protected Stream<Vertex<ClassOrInterfaceDeclaration>> subclassesStreamOf(Vertex<ClassOrInterfaceDeclaration> classVertex) { protected Stream<Vertex<? extends TypeDeclaration<?>>> subclassesStreamOf(Vertex<? extends TypeDeclaration<?>> classVertex) { return Stream.concat(Stream.of(classVertex), outgoingEdgesOf(classVertex).stream() .filter(ClassArc.Extends.class::isInstance) .map(this::getEdgeTarget) .map(v -> (Vertex<ClassOrInterfaceDeclaration>) v) .map(v -> (Vertex<? extends TypeDeclaration<?>>) v) .flatMap(this::subclassesStreamOf)); } // TODO: this method ignores default method implementations in interfaces, as can be overridden. /** Looks up a method in the graph, going up the class inheritance tree to locate a * matching method. If no match can be found, throws an {@link IllegalArgumentException}. */ public MethodDeclaration findMethodByTypeAndSignature(ClassOrInterfaceDeclaration type, CallableDeclaration<?> declaration) { public MethodDeclaration findMethodByTypeAndSignature(TypeDeclaration<?> type, CallableDeclaration<?> declaration) { Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(declaration, type)); if (v != null && v.declaration.isMethodDeclaration()) return v.declaration.asMethodDeclaration(); Optional<ClassOrInterfaceDeclaration> parentType = parentOf(type); if (parentType.isEmpty()) throw new IllegalArgumentException("Cannot find the given declaration: " + declaration); if (type.isClassOrInterfaceDeclaration()) { Optional<ClassOrInterfaceDeclaration> parentType = parentOf(type.asClassOrInterfaceDeclaration()); if (parentType.isPresent()) return findMethodByTypeAndSignature(parentType.get(), declaration); } throw new IllegalArgumentException("Cannot find the given declaration: " + declaration); } /** Find the parent class or interface of a given class. */ public Optional<ClassOrInterfaceDeclaration> parentOf(ClassOrInterfaceDeclaration declaration) { Loading @@ -164,7 +164,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG else return Optional.empty(); } else if (callableDeclaration.isConstructorDeclaration()) { return Optional.of(generateObjectTreeFor(ASTUtils.getClassNode(callableDeclaration))); return Optional.of(generateObjectTreeFor(callableDeclaration.findAncestor(TypeDeclaration.class).orElseThrow())); } else { throw new IllegalArgumentException("Invalid callable declaration type"); } Loading @@ -179,7 +179,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG return Optional.empty(); } public ObjectTree generateObjectTreeFor(ClassOrInterfaceDeclaration declaration) { public ObjectTree generateObjectTreeFor(TypeDeclaration<?> declaration) { return generateObjectTreeFor(classDeclarationMap.get(mapKey(declaration))); } Loading @@ -196,11 +196,11 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG protected ObjectTree generatePolyObjectTreeFor(Vertex<? extends TypeDeclaration<?>> classVertex, ObjectTree tree, String level, int depth) { if (depth >= StaticConfig.K_LIMIT) return tree; Set<ClassOrInterfaceDeclaration> types = subclassesOf(classVertex); Set<? extends TypeDeclaration<?>> types = subclassesOf(classVertex); if (types.isEmpty()) { generateObjectTreeFor(classVertex, tree, level, depth); } else { for (ClassOrInterfaceDeclaration type : types) { for (TypeDeclaration<?> type : types) { Vertex<? extends TypeDeclaration<?>> subclassVertex = classDeclarationMap.get(mapKey(type)); if (!findAllFieldsOf(subclassVertex).isEmpty()) { ObjectTree newType = tree.addType(ASTUtils.resolvedTypeDeclarationToResolvedType(type.resolve()), level); Loading Loading @@ -355,41 +355,48 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex<?>, ClassG * member/extends/implements relationships in the given list of compilation units. */ protected void buildEdges(NodeList<CompilationUnit> arg) { arg.accept(new VoidVisitorAdapter<Void>() { private final Deque<ClassOrInterfaceDeclaration> classStack = new LinkedList<>(); private final Deque<TypeDeclaration<?>> typeStack = new LinkedList<>(); @Override public void visit(ClassOrInterfaceDeclaration n, Void arg) { classStack.push(n); typeStack.push(n); var v = classDeclarationMap.get(mapKey(n)); addClassEdges(v); super.visit(n, arg); classStack.pop(); typeStack.pop(); } @Override public void visit(EnumDeclaration n, Void arg) { typeStack.push(n); super.visit(n, arg); typeStack.pop(); } @Override public void visit(FieldDeclaration n, Void arg) { ClassOrInterfaceDeclaration clazz = classStack.peek(); assert clazz != null; var c = classDeclarationMap.get(mapKey(clazz)); Vertex<FieldDeclaration> v = fieldDeclarationMap.get(mapKey(n, clazz)); assert !typeStack.isEmpty(); TypeDeclaration<?> type = typeStack.peek(); var c = classDeclarationMap.get(mapKey(type)); Vertex<FieldDeclaration> v = fieldDeclarationMap.get(mapKey(n, type)); addEdge(c, v, new ClassArc.Member()); } @Override public void visit(MethodDeclaration n, Void arg) { ClassOrInterfaceDeclaration clazz = classStack.peek(); assert clazz != null; var c = classDeclarationMap.get(mapKey(clazz)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, clazz)); assert !typeStack.isEmpty(); TypeDeclaration<?> type = typeStack.peek(); var c = classDeclarationMap.get(mapKey(type)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, type)); addEdge(c, v, new ClassArc.Member()); } @Override public void visit(ConstructorDeclaration n, Void arg) { ClassOrInterfaceDeclaration clazz = classStack.peek(); assert clazz != null; var c = classDeclarationMap.get(mapKey(clazz)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, clazz)); assert !typeStack.isEmpty(); TypeDeclaration<?> type = typeStack.peek(); var c = classDeclarationMap.get(mapKey(type)); Vertex<CallableDeclaration<?>> v = methodDeclarationMap.get(mapKey(n, type)); addEdge(c, v, new ClassArc.Member()); } }, null); Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/jsysdg/JSysCFG.java +19 −2 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.ThisExpr; import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; Loading Loading @@ -197,7 +198,7 @@ public class JSysCFG extends ESCFG { connectTo(n); // 2. Insert dynamic class code (only for super()) if (!n.isThis()) ASTUtils.getClassInit(ASTUtils.getClassNode(rootNode.getAstNode()), false) ASTUtils.getTypeInit(n.findAncestor(TypeDeclaration.class).orElseThrow(), false) .forEach(node -> node.accept(this, arg)); // 3. Handle exceptions super.visitCallForExceptions(n); Loading @@ -213,7 +214,7 @@ public class JSysCFG extends ESCFG { @Override public void visit(ConstructorDeclaration n, Void arg) { // Insert call to super() if it is implicit. if (!ASTUtils.constructorHasExplicitConstructorInvocation(n)){ if (ASTUtils.shouldInsertExplicitConstructorInvocation(n)) { var superCall = new ExplicitConstructorInvocationStmt(null, null, false, null, new NodeList<>()); methodInsertedInstructions.add(superCall); n.getBody().addStatement(0, superCall); Loading @@ -237,6 +238,22 @@ public class JSysCFG extends ESCFG { } } @Override protected void buildEnter(CallableDeclaration<?> callableDeclaration) { super.buildEnter(callableDeclaration); // enums have no super(), so the implicitly inserted instructions // must be placed after the root node if (callableDeclaration.isConstructorDeclaration()) { ConstructorDeclaration cd = callableDeclaration.asConstructorDeclaration(); TypeDeclaration<?> type = cd.findAncestor(TypeDeclaration.class).orElseThrow(); if (!ASTUtils.shouldInsertExplicitConstructorInvocation(cd) && type.isEnumDeclaration() && ASTUtils.shouldInsertDynamicInitInEnum(cd)) { ASTUtils.getTypeInit(type, false).forEach(n -> n.accept(this, null)); } } } /** * Sets the expression for all return statements contained in its argument. * @param node The AST to search for return statements. Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/jsysdg/JSysDG.java +7 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,13 @@ public class JSysDG extends ESSDG { newlyInsertedConstructors.add(n.addConstructor(Modifier.Keyword.PUBLIC)); return super.visit(n, arg); } @Override public Visitable visit(EnumDeclaration n, Object arg) { if (n.getConstructors().isEmpty()) newlyInsertedConstructors.add(n.addConstructor()); return super.visit(n, arg); } }, null); } Loading
sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java +2 −2 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ package es.upv.mist.slicing.graphs.oo; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.CallableDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.MethodCallExpr; Loading Loading @@ -151,7 +151,7 @@ public class DynamicTypeResolver { ResolvedClassDeclaration type = expression.calculateResolvedType().asReferenceType() .getTypeDeclaration().orElseThrow().asClass(); return classGraph.subclassesOf(type).stream() .map(ClassOrInterfaceDeclaration::resolve) .map(TypeDeclaration::resolve) .map(ASTUtils::resolvedTypeDeclarationToResolvedType); } }