Commit 2597482f authored by Carlos Galindo's avatar Carlos Galindo
Browse files

ClassGraph: unify keys and usage of vertexDeclarationMap

* Closes #52
* Simplify calls and remove unnecessary searches.
* Make dotexporter functional
parent c7a2eb70
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -217,7 +217,7 @@ public class CallGraph extends DirectedPseudograph<CallGraph.Vertex, CallGraph.E
                // Connect to each declaration
                AtomicInteger edgesCreated = new AtomicInteger();
                dynamicTypes.stream()
                        .map(t -> classGraph.findMethodByTypeAndSignature(t, decl.getSignature()))
                        .map(t -> classGraph.findMethodByTypeAndSignature(t, decl))
                        .collect(Collectors.toCollection(NodeHashSet::new))
                        .forEach(methodDecl -> {
                            edgesCreated.getAndIncrement();
+54 −89
Original line number Diff line number Diff line
package es.upv.mist.slicing.graphs;

import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
@@ -33,33 +32,11 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
    /** Locates the vertex that represents a given class or interface declaration.
     *  The vertex must exist, or an exception will be thrown. */
    protected Vertex findClassVertex(ClassOrInterfaceDeclaration declaration) {
        return vertexSet().stream()
                .filter(v -> v.declaration.isClassOrInterfaceDeclaration())
                .filter(v -> ASTUtils.equalsWithRangeInCU(v.declaration, declaration))
                .findFirst().orElseThrow();
    }

    /** Locates the vertex that represents a given class or interface declaration.
     *  The vertex must exist, or an exception will be thrown. */
    protected Vertex findClassVertex(ResolvedClassDeclaration declaration) {
        return vertexSet().stream()
                .filter(v -> v.declaration.isClassOrInterfaceDeclaration())
                .filter(v -> v.declaration.asClassOrInterfaceDeclaration().resolve().asClass().equals(declaration))
                .findFirst().orElseThrow();
    }

    protected Vertex findClassVertex(ResolvedReferenceType type) {
        return vertexSet().stream()
                .filter(v -> v.declaration.isClassOrInterfaceDeclaration())
                .filter(v -> ASTUtils.resolvedTypeDeclarationToResolvedType(v.declaration.asClassOrInterfaceDeclaration().resolve()).equals(type))
                .findFirst().orElseThrow();
        return vertexDeclarationMap.get(mapKey(declaration));
    }

    protected Vertex findMethodVertex(CallableDeclaration<?> declaration) {
        return vertexSet().stream()
                .filter(v -> v.declaration.isCallableDeclaration())
                .filter(v -> ASTUtils.equalsWithRangeInCU(v.declaration, declaration))
                .findFirst().orElseThrow();
        return vertexDeclarationMap.get(mapKey(declaration, ASTUtils.getClassNode(declaration)));
    }

    public Set<MethodDeclaration> overriddenSetOf(MethodDeclaration method) {
@@ -90,11 +67,11 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap

    /** Returns all child classes of the given class, including itself. */
    public Set<ClassOrInterfaceDeclaration> subclassesOf(ResolvedClassDeclaration clazz) {
        return subclassesOf(findClassVertex(clazz));
        return subclassesOf(vertexDeclarationMap.get(mapKey(clazz)));
    }

    public Set<ClassOrInterfaceDeclaration> subclassesOf(ResolvedReferenceType type) {
        return subclassesOf(findClassVertex(type));
        return subclassesOf(vertexDeclarationMap.get(mapKey(type)));
    }

    /** @see #subclassesOf(ClassOrInterfaceDeclaration) */
@@ -115,21 +92,14 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
    // 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.Signature signature) {
        Optional<MethodDeclaration> result = outgoingEdgesOf(findClassVertex(type)).stream()
                .filter(ClassArc.Member.class::isInstance)
                .map(this::getEdgeTarget)
                .map(Vertex::getDeclaration)
                .filter(BodyDeclaration::isMethodDeclaration)
                .map(BodyDeclaration::asMethodDeclaration)
                .filter(decl -> signature.equals(decl.getSignature()))
                .findFirst();
        if (result.isPresent())
            return result.get();
    public MethodDeclaration findMethodByTypeAndSignature(ClassOrInterfaceDeclaration type, CallableDeclaration<?> declaration) {
        Vertex v = vertexDeclarationMap.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 signature: " + signature);
        return findMethodByTypeAndSignature(parentType.get(), signature);
            throw new IllegalArgumentException("Cannot find the given declaration: " + declaration);
        return findMethodByTypeAndSignature(parentType.get(), declaration);
    }

    /** Find the parent class or interface of a given class. */
@@ -157,6 +127,26 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
        return built;
    }

    protected String mapKey(ClassOrInterfaceDeclaration n) {
        return n.getFullyQualifiedName().orElseThrow();
    }

    protected String mapKey(ResolvedClassDeclaration n) {
        return n.getQualifiedName();
    }

    protected String mapKey(ResolvedReferenceType n) {
        return n.getQualifiedName();
    }

    protected String mapKey(CallableDeclaration<?> declaration, ClassOrInterfaceDeclaration clazz) {
        return clazz.getFullyQualifiedName().orElseThrow() + "." + declaration.getSignature();
    }

    protected String mapKey(FieldDeclaration declaration, ClassOrInterfaceDeclaration clazz) {
        return clazz.getFullyQualifiedName().orElseThrow() + "." + declaration;
    }

    /** Find the class declarations, the field declaration, and method and constructor declarations (vertices)
     * in the given list of compilation units. */
    protected void buildVertices(NodeList<CompilationUnit> arg) {
@@ -177,16 +167,19 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap

            @Override
            public void visit(FieldDeclaration n, Void arg) {
                assert classStack.peek() != null;
                addFieldDeclaration(n, classStack.peek());
            }

            @Override
            public void visit(MethodDeclaration n, Void arg) {
                assert classStack.peek() != null;
                addCallableDeclaration(n, classStack.peek());
            }

            @Override
            public void visit(ConstructorDeclaration n, Void arg) {
                assert classStack.peek() != null;
                addCallableDeclaration(n, classStack.peek());
            }
        }, null);
@@ -196,14 +189,14 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
    protected void addClassDeclaration(ClassOrInterfaceDeclaration n) {
        ClassGraph.Vertex v = new ClassGraph.Vertex(n);
        // Required string to match ClassOrInterfaceType and ClassOrInterfaceDeclaration. QualifiedName Not Valid
        vertexDeclarationMap.put(n.getNameAsString(), v);
        vertexDeclarationMap.put(mapKey(n), v);
        addVertex(v);
    }

    /** Add a field declaration vertex to the class graph */
    protected void addFieldDeclaration(FieldDeclaration n, ClassOrInterfaceDeclaration c){
        ClassGraph.Vertex v = new ClassGraph.Vertex(n);
        vertexDeclarationMap.put(c.getFullyQualifiedName().get()+ "." + n.toString(), v);
        vertexDeclarationMap.put(mapKey(n, c), v);
        addVertex(v);
    }

@@ -211,7 +204,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
    protected void addCallableDeclaration(CallableDeclaration<?> n, ClassOrInterfaceDeclaration c){
        assert n instanceof ConstructorDeclaration || n instanceof MethodDeclaration;
        ClassGraph.Vertex v = new ClassGraph.Vertex(n);
        vertexDeclarationMap.put(c.getFullyQualifiedName().get()+ "." + n.getSignature().toString(), v);
        vertexDeclarationMap.put(mapKey(n, c), v);
        addVertex(v);
    }

@@ -224,7 +217,7 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
            @Override
            public void visit(ClassOrInterfaceDeclaration n, Void arg) {
                classStack.push(n);
                Vertex v = vertexDeclarationMap.get(n.getNameAsString());
                Vertex v = vertexDeclarationMap.get(mapKey(n));
                addClassEdges(v);
                super.visit(n, arg);
                classStack.pop();
@@ -233,24 +226,27 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
            @Override
            public void visit(FieldDeclaration n, Void arg) {
                ClassOrInterfaceDeclaration clazz = classStack.peek();
                Vertex c = vertexDeclarationMap.get(clazz.getNameAsString());
                Vertex v = vertexDeclarationMap.get(clazz.getFullyQualifiedName().get()+ "." + n.toString());
                assert clazz != null;
                Vertex c = vertexDeclarationMap.get(mapKey(clazz));
                Vertex v = vertexDeclarationMap.get(mapKey(n, clazz));
                addEdge(c, v, new ClassArc.Member());
            }

            @Override
            public void visit(MethodDeclaration n, Void arg) {
                ClassOrInterfaceDeclaration clazz = classStack.peek();
                Vertex c = vertexDeclarationMap.get(clazz.getNameAsString());
                Vertex v = vertexDeclarationMap.get(clazz.getFullyQualifiedName().get()+ "." + n.getSignature().toString());
                assert clazz != null;
                Vertex c = vertexDeclarationMap.get(mapKey(clazz));
                Vertex v = vertexDeclarationMap.get(mapKey(n, clazz));
                addEdge(c, v, new ClassArc.Member());
            }

            @Override
            public void visit(ConstructorDeclaration n, Void arg) {
                ClassOrInterfaceDeclaration clazz = classStack.peek();
                Vertex c = vertexDeclarationMap.get(clazz.getNameAsString());
                Vertex v = vertexDeclarationMap.get(clazz.getFullyQualifiedName().get()+ "." + n.getSignature().toString());
                assert clazz != null;
                Vertex c = vertexDeclarationMap.get(mapKey(clazz));
                Vertex v = vertexDeclarationMap.get(mapKey(n, clazz));
                addEdge(c, v, new ClassArc.Member());
            }
        }, null);
@@ -260,21 +256,22 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap
        assert v.declaration instanceof ClassOrInterfaceDeclaration;
        ClassOrInterfaceDeclaration dv = (ClassOrInterfaceDeclaration) v.declaration;
        dv.getExtendedTypes().forEach(p -> {
            Vertex source = vertexDeclarationMap.get(p.getNameAsString());
            Vertex source = vertexDeclarationMap.get(mapKey(p.resolve()));
            if (source != null && containsVertex(v))
                addEdge(source, v, new ClassArc.Extends());
        });
        dv.getImplementedTypes().forEach(p -> {
            Vertex source = vertexDeclarationMap.get(p.getNameAsString());
            Vertex source = vertexDeclarationMap.get(mapKey(p.resolve()));
            if (source != null && containsVertex(v))
                addEdge(source, v, new ClassArc.Implements());
        });
    }

    /** Creates a graph-appropriate DOT exporter. */
    public DOTExporter<CallableDeclaration<?>, CallGraph.Edge<?>> getDOTExporter() {
        DOTExporter<CallableDeclaration<?>, CallGraph.Edge<?>> dot = new DOTExporter<>();
        dot.setVertexAttributeProvider(decl -> Utils.dotLabel(decl.getDeclarationAsString(false, false, false)));
        dot.setEdgeAttributeProvider(edge -> Utils.dotLabel(edge.getCall().toString()));
    public DOTExporter<ClassGraph.Vertex, ClassGraph.ClassArc> getDOTExporter() {
        DOTExporter<ClassGraph.Vertex, ClassGraph.ClassArc> dot = new DOTExporter<>();
        dot.setVertexAttributeProvider(vertex -> Utils.dotLabel(vertex.declaration.toString().replaceAll("\\{.*}", "")));
        dot.setEdgeAttributeProvider(edge -> Utils.dotLabel(edge.getClass().getSimpleName()));
        return dot;
    }

@@ -306,40 +303,8 @@ public class ClassGraph extends DirectedPseudograph<ClassGraph.Vertex, ClassGrap

        @Override
        public String toString() {
            return super.toString();
        }
    }

    /** Returns a List with the static FieldDeclarations and InitializerDeclarations of the given class */
    public List<BodyDeclaration<?>> getStaticInit(String className){
        return getClassInit(className,true);
    }

    /** Returns a List with the dynamic FieldDeclarations and InitializerDeclarations of the given class */
    public List<BodyDeclaration<?>> getDynInit(String className){
        return getClassInit(className,false);
    }

    /** Returns a List with FieldDeclarations and InitializerDeclarations static/dynamic items of the given class */
    private List<BodyDeclaration<?>> getClassInit(String className, Boolean isStatic){
        Vertex classNode = vertexDeclarationMap.get(className);
        List<BodyDeclaration<?>> members = classNode.declaration.asClassOrInterfaceDeclaration().getMembers();
        List<BodyDeclaration<?>> classInit = new LinkedList<>();
        for (BodyDeclaration<?> member : members) {
            if (member instanceof CallableDeclaration<?>)
                continue;

            if (member.isFieldDeclaration()) {
                if (isStatic == member.asFieldDeclaration().hasModifier(Modifier.Keyword.STATIC))
                    classInit.add(member);
                continue;
            }

            if (member.isInitializerDeclaration())
                if (isStatic == member.asInitializerDeclaration().isStatic())
                    classInit.add(member);
            return declaration.toString();
        }
        return classInit;
    }

    protected static class ClassArc extends Arc {
+4 −10
Original line number Diff line number Diff line
@@ -3,13 +3,11 @@ package es.upv.mist.slicing.graphs.jsysdg;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.ThisExpr;
import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
import es.upv.mist.slicing.graphs.ClassGraph;
import es.upv.mist.slicing.graphs.cfg.CFGBuilder;
import es.upv.mist.slicing.graphs.exceptionsensitive.ESCFG;
import es.upv.mist.slicing.nodes.GraphNode;
@@ -30,9 +28,8 @@ public class JSysCFG extends ESCFG {
        throw new UnsupportedOperationException("Use build(CallableDeclaration, ClassGraph, Set<ConstructorDeclaration>)");
    }

    public void build(CallableDeclaration<?> declaration, ClassGraph classGraph, Set<ConstructorDeclaration> implicitConstructors) {
    public void build(CallableDeclaration<?> declaration, Set<ConstructorDeclaration> implicitConstructors) {
        Builder builder = (Builder) newCFGBuilder();
        builder.classGraph = classGraph;
        builder.implicitDeclaration = implicitConstructors.contains(declaration);
        declaration.accept(builder, null);
        // Verify that it has been built
@@ -47,8 +44,6 @@ public class JSysCFG extends ESCFG {
    }

    public class Builder extends ESCFG.Builder {
        /** ClassGraph associated to the Method represented by the CFG */
        protected ClassGraph classGraph;
        /** List of implicit instructions inserted explicitly in this CFG.
         *  They should be included in the graph as ImplicitNodes. */
        protected List<Node> methodInsertedInstructions = new LinkedList<>();
@@ -77,10 +72,9 @@ public class JSysCFG extends ESCFG {
            // 1. Connect to the following statements
            connectTo(n);
            // 2. Insert dynamic class code (only for super())
            if (!n.isThis()) {
                ClassOrInterfaceDeclaration containerClass = ASTUtils.getClassNode(rootNode.getAstNode());
                classGraph.getDynInit(containerClass.getNameAsString()).forEach(node -> node.accept(this, arg));
            }
            if (!n.isThis())
                ASTUtils.getClassInit(ASTUtils.getClassNode(rootNode.getAstNode()), false)
                        .forEach(node -> node.accept(this, arg));
            // 3. Handle exceptions
            super.visitCallForExceptions(n);
        }
+1 −1
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ public class JSysDG extends ESSDG {

        @Override
        protected void buildCFG(CallableDeclaration<?> declaration, CFG cfg) {
            ((JSysCFG) cfg).build(declaration, classGraph, newlyInsertedConstructors);
            ((JSysCFG) cfg).build(declaration, newlyInsertedConstructors);
        }

        @Override
+14 −0
Original line number Diff line number Diff line
@@ -200,4 +200,18 @@ public class ASTUtils {
        }
        throw new IllegalArgumentException("Invalid typing for a field");
    }

    /** Returns a List with FieldDeclarations and InitializerDeclarations static/dynamic items of the given class */
    public static List<BodyDeclaration<?>> getClassInit(ClassOrInterfaceDeclaration clazz, boolean isStatic) {
        List<BodyDeclaration<?>> classInit = new LinkedList<>();
        for (BodyDeclaration<?> member : clazz.getMembers()) {
            if (member.isFieldDeclaration() &&
                    member.asFieldDeclaration().isStatic() == isStatic)
                classInit.add(member);
            if (member.isInitializerDeclaration() &&
                    member.asInitializerDeclaration().isStatic() == isStatic)
                classInit.add(member);
        }
        return classInit;
    }
}