Unverified Commit 3b669889 authored by Carlos Galindo's avatar Carlos Galindo Committed by GitHub
Browse files

Merge pull request #21 from jacosro/14-switch-library

Switch from edg.graphlib to  JGraphT
parents 1a40875c 2b465f8d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2,3 +2,4 @@
.idea/
target/
out/
.settings
 No newline at end of file

lib/graphlib.jar

deleted100644 → 0
−21.9 KiB

File deleted.

+12 −1
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@
    </build>

    <dependencies>

        <dependency>
            <groupId>com.github.javaparser</groupId>
            <artifactId>javaparser-symbol-solver-core</artifactId>
@@ -41,5 +40,17 @@
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.jgrapht</groupId>
            <artifactId>jgrapht-io</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.5.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
 No newline at end of file
+35 −19
Original line number Diff line number Diff line
@@ -34,9 +34,9 @@ Find `Slice` class (`tfm/slicing`), set the program path and execute. The sliced

## Structure

Graphs are built using a library called `graphlib`, located in `lib/graphlib.jar`. This library is old and has some issues I had to fix...
Graphs are built using a library called `JGraphT`.

The main class is the `Graph` class, which extends from `graphlib`'s `Graph` class. This class includes some behaviour fixes, and some general interest methods (like `toString`, `toGraphvizRepresentation`, etc.)
The main class is the `Graph` class, which extends from `JGraphT`'s `DefaultDirectedGraph` class. This class includes some general interest methods (like `toString`, etc.)

Every graph has a set of nodes and arrows. `GraphNode` and `Arc` classes are used to represent them respectively.

@@ -104,7 +104,7 @@ Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has

### General

- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization
- Switch to a (much) better graph library like [JGraphT](https://jgrapht.org/). It also supports graph visualization (done).
- Performance review
- Make a test suite (test graph building, slicing, etc.)
- Add support to more Java language features (lambdas, etc.)
@@ -114,28 +114,44 @@ Forget about the `tfm/scopes` folder, it was an idea I had to discard and it has
### Build a CFG from a program

```java
public CFGGraph buildCFG(File programFile) {
    JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case
public class Example {
    public CFG buildCFG(File programFile) {
        // Always disable attribution of comments, just in case
        JavaParser.getStaticConfiguration().setAttributeComments(false);
        
        Node astRoot = JavaParser.parse(programFile);

    return Graphs.CFG.fromASTNode(astRoot); // Creates a new graph representing the program
        Optional<MethodDeclaration> optMethod = astRoot.findFirst(MethodDeclaration.class);
        if (!optMethod.isPresent)
            throw new RuntimeException("No method could be found");
        
        // Creates a new graph representing the program
        CFG cfg = new CFG();
        cfg.build(optMethod.get());
        return cfg;
    }
}
```

### Get a slice of the PDG of a program

```java
public class Example {
    public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) {
    JavaParser.getStaticConfiguration().setAttributeComments(false); // Always disable comments, just in case
        // Always disable attribution of comments, just in case
        JavaParser.getStaticConfiguration().setAttributeComments(false);
        
        Node astRoot = JavaParser.parse(programFile);

    PDGGraph pdgGraph = Graphs.PDG.fromASTNode(astRoot);

    return pdgGraph.slice(slicingCriterion);
        Optional<MethodDeclaration> optMethod = astRoot.findFirst(MethodDeclaration.class);
        if (!optMethod.isPresent)
            throw new RuntimeException("No method could be found");
        
        // Creates a new graph representing the program
        PDG pdg = new PDG();
        pdg.build(optMethod.get());
        // Slice PDG
        return pdg.slice(slicingCriterion);
    }
}

```

## Workflow
@@ -143,7 +159,7 @@ public PDGGraph getSlice(File program, SlicingCriterion slicingCriterion) {
- Branches:
  - `master` (only for stable versions)
  - `develop` (main branch)
  - `<issue number>`
  - `<issue number>-name`

1. Discover a new feature/fix
2. Open an issue describing it and assign it
+48 −41
Original line number Diff line number Diff line
package tfm.arcs;

import tfm.arcs.data.ArcData;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.io.Attribute;
import tfm.arcs.cfg.ControlFlowArc;
import tfm.arcs.pdg.ControlDependencyArc;
import tfm.arcs.pdg.DataDependencyArc;
import tfm.nodes.GraphNode;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public abstract class Arc<D extends ArcData> extends edg.graphlib.Arrow<String, D> {
public abstract class Arc extends DefaultEdge {
    public Arc() {

    @SuppressWarnings("unchecked")
    public Arc(GraphNode<?> from, GraphNode<?> to) {
        super((edg.graphlib.Vertex<String, D>) from, (edg.graphlib.Vertex<String, D>) to);
    }

    public abstract boolean isControlFlowArrow();
    public final boolean isControlFlowArc() {
        return this instanceof ControlFlowArc;
    }

    public abstract boolean isControlDependencyArrow();
    public final ControlFlowArc asControlFlowArc() {
        if (isControlFlowArc())
            return (ControlFlowArc) this;
        throw new UnsupportedOperationException("Not a ControlFlowArc");
    }

    public abstract boolean isDataDependencyArrow();
    public final boolean isControlDependencyArc() {
        return this instanceof ControlDependencyArc;
    }

    @Override
    public String toString() {
        return String.format("Arc{data: %s, %s -> %s}",
                getData(),
                getFrom(),
                getTo()
        );
    public final ControlDependencyArc asControlDependencyArc() {
        if (isControlDependencyArc())
            return (ControlDependencyArc) this;
        throw new UnsupportedOperationException("Not a ControlDependencyArc");
    }

    public String toGraphvizRepresentation() {
        GraphNode from = (GraphNode) getFrom();
        GraphNode to = (GraphNode) getTo();
    public final boolean isDataDependencyArc() {
        return this instanceof DataDependencyArc;
    }

        return String.format("%s -> %s",
                from.getId(),
                to.getId()
        );
    public final DataDependencyArc asDataDependencyArc() {
        if (isDataDependencyArc())
            return (DataDependencyArc) this;
        throw new UnsupportedOperationException("Not a DataDependencyArc");
    }

    public GraphNode<?> getFromNode() {
        return (GraphNode<?>) super.getFrom();
    @Override
    public String toString() {
        return String.format("%s{%d -> %d}", getClass().getName(),
                ((GraphNode<?>) getSource()).getId(), ((GraphNode<?>) getTarget()).getId());
    }

    public GraphNode<?> getToNode() {
        return (GraphNode<?>) super.getTo();
    public String getLabel() {
        return "";
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getData()) + getFrom().hashCode() + getTo().hashCode();
    public Map<String, Attribute> getDotAttributes() {
        return new HashMap<>();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;

        if (!(o instanceof Arc))
        if (o == null)
            return false;
        if (!o.getClass().equals(this.getClass()))
            return false;
        return Objects.equals(getSource(), ((Arc) o).getSource()) &&
                Objects.equals(getTarget(), ((Arc) o).getTarget());
    }

        Arc arc = (Arc) o;

        GraphNode from = (GraphNode) arc.getFrom();
        GraphNode from2 = (GraphNode) getFrom();
        GraphNode to = (GraphNode) getTo();
        GraphNode to2 = (GraphNode) arc.getTo();

        return Objects.equals(arc.getData(), getData()) &&
                Objects.equals(from.getId(), from2.getId()) &&
                Objects.equals(to.getId(), to2.getId());
    @Override
    public int hashCode() {
        return Objects.hash(getClass(), getSource(), getTarget());
    }
}
Loading