Skip to content
Snippets Groups Projects
Commit f8b7a13a authored by Carlos Galindo's avatar Carlos Galindo
Browse files

Add implicit constructors

* Small regression: only the last field declared in a constructor is included. This is expected, and will be solved with the new object dependencies.
* Integrate ImplicitNode as boolean in GraphNode.
* Updated tests
* Slice now allows the insertion of implicit instructions, but does not output them when generating the AST.
* Removed list of nodes from slice, as the map contains a superset of the information of the list.
parent a81337d6
No related branches found
No related tags found
1 merge request!52Dynamic initializerDeclaration in ConstructorDeclaration
Showing
with 95 additions and 40 deletions
package es.upv.mist.slicing.graphs.jsysdg;
import com.github.javaparser.ast.Node;
import es.upv.mist.slicing.nodes.SyntheticNode;
/**
* A graph node that does not exist in the original program, but represents
* implicit code constructs such as 'super()' at the start of a constructor.
* @param <T> The type of the AST node contained in this graph node.
*/
public class ImplicitNode<T extends Node> extends SyntheticNode<T> {
protected ImplicitNode(String instruction, T astNode) {
super(instruction, astNode);
}
}
......@@ -2,6 +2,7 @@ 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;
......@@ -12,10 +13,12 @@ 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;
import es.upv.mist.slicing.nodes.io.MethodExitNode;
import es.upv.mist.slicing.utils.ASTUtils;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* An SDG that is tailored for Java, including a class graph, inheritance,
......@@ -24,10 +27,20 @@ import java.util.List;
public class JSysCFG extends ESCFG {
/** ClassGraph associated to the Method represented by the CFG */
protected ClassGraph classGraph;
/** Set of constructors that must be built with implicit nodes. */
protected Set<ConstructorDeclaration> implicitConstructors;
public JSysCFG(ClassGraph classGraph){
public JSysCFG(ClassGraph classGraph, Set<ConstructorDeclaration> implicitConstructors) {
super();
this.classGraph = classGraph;
this.implicitConstructors = implicitConstructors;
}
@Override
public void buildRootNode(CallableDeclaration<?> rootNodeAst) {
super.buildRootNode(rootNodeAst);
if (implicitConstructors.contains(rootNodeAst))
rootNode.markAsImplicit();
}
@Override
......@@ -39,6 +52,8 @@ public class JSysCFG extends ESCFG {
/** List of implicit instructions inserted explicitly in this CFG.
* They should be included in the graph as ImplicitNodes. */
protected List<Node> methodInsertedInstructions = new LinkedList<>();
/** Whether we are building a CFG for an implicit method or not. */
protected boolean implicitDeclaration = false;
protected Builder(JSysCFG jSysCFG) {
super(JSysCFG.this);
......@@ -48,11 +63,10 @@ public class JSysCFG extends ESCFG {
@Override
protected <T extends Node> GraphNode<T> connectTo(T n, String text) {
GraphNode<T> dest;
if (methodInsertedInstructions.contains(n)) {
dest = new ImplicitNode<>(n.toString(), n);
} else {
dest = new GraphNode<>(text, n);
}
dest = new GraphNode<>(text, n);
if (methodInsertedInstructions.contains(n) ||
(implicitDeclaration && !(n instanceof FieldDeclaration)))
dest.markAsImplicit();
addVertex(dest);
connectTo(dest);
return dest;
......@@ -79,6 +93,8 @@ public class JSysCFG extends ESCFG {
@Override
public void visit(ConstructorDeclaration n, Void arg) {
if (implicitConstructors.contains(n))
implicitDeclaration = true;
// Insert call to super() if it is implicit.
if (!ASTUtils.constructorHasExplicitConstructorInvocation(n)){
var superCall = new ExplicitConstructorInvocationStmt(null, null, false, null, new NodeList<>());
......@@ -90,6 +106,11 @@ public class JSysCFG extends ESCFG {
}
// Perform the same task as previous graphs.
super.visit(n, arg);
// Convert the exit nodes to implicit if appropriate
if (implicitDeclaration)
vertexSet().stream()
.filter(MethodExitNode.class::isInstance)
.forEach(GraphNode::markAsImplicit);
}
}
}
package es.upv.mist.slicing.graphs.jsysdg;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.visitor.ModifierVisitor;
import com.github.javaparser.ast.visitor.Visitable;
import es.upv.mist.slicing.graphs.augmented.PSDG;
import es.upv.mist.slicing.graphs.cfg.CFG;
import es.upv.mist.slicing.graphs.exceptionsensitive.ESSDG;
import es.upv.mist.slicing.graphs.exceptionsensitive.ExceptionSensitiveCallConnector;
import es.upv.mist.slicing.graphs.pdg.PDG;
import es.upv.mist.slicing.utils.NodeHashSet;
public class JSysDG extends ESSDG {
......@@ -17,9 +25,29 @@ public class JSysDG extends ESSDG {
* @see PSDG.Builder
* @see ExceptionSensitiveCallConnector */
class Builder extends ESSDG.Builder {
protected NodeHashSet<ConstructorDeclaration> newlyInsertedConstructors = new NodeHashSet<>();
@Override
public void build(NodeList<CompilationUnit> nodeList) {
insertImplicitConstructors(nodeList);
super.build(nodeList);
}
/** Create implicit constructors, and store them in a set so that they may be built with implicit nodes. */
protected void insertImplicitConstructors(NodeList<CompilationUnit> nodeList) {
nodeList.accept(new ModifierVisitor<>() {
@Override
public Visitable visit(ClassOrInterfaceDeclaration n, Object arg) {
if (n.getConstructors().isEmpty())
newlyInsertedConstructors.add(n.addConstructor(Modifier.Keyword.PUBLIC));
return super.visit(n, arg);
}
}, null);
}
@Override
protected CFG createCFG() {
return new JSysCFG(classGraph);
return new JSysCFG(classGraph, newlyInsertedConstructors);
}
@Override
......
package es.upv.mist.slicing.graphs.jsysdg;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import es.upv.mist.slicing.graphs.ClassGraph;
import es.upv.mist.slicing.graphs.exceptionsensitive.ESPDG;
import java.util.Set;
public class JSysPDG extends ESPDG {
public JSysPDG(ClassGraph clg) {
this(new JSysCFG(clg));
public JSysPDG(ClassGraph classGraph, Set<ConstructorDeclaration> implicitConstructors) {
this(new JSysCFG(classGraph, implicitConstructors));
}
public JSysPDG(JSysCFG cfg) {
......
......@@ -122,6 +122,8 @@ public class PDG extends GraphWithRootNode<CallableDeclaration<?>> {
callNodeStack.pop();
} else {
CallNode callNode = CallNode.create(((VariableAction.CallMarker) action).getCall());
if (graphNode.isImplicitInstruction())
callNode.markAsImplicit();
addVertex(callNode);
addControlDependencyArc(graphNode, callNode);
callNodeStack.push(callNode);
......
......@@ -30,6 +30,9 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> {
/** The method calls contained */
protected final List<Resolvable<? extends ResolvedMethodLikeDeclaration>> methodCalls = new LinkedList<>();
/** @see #isImplicitInstruction() */
protected boolean isImplicit = false;
/** Create a graph node, with id and variable actions generated automatically. */
public GraphNode(String label, N astNode) {
this(IdHelper.getInstance().getNextId(), label, astNode);
......@@ -87,6 +90,22 @@ public class GraphNode<N extends Node> implements Comparable<GraphNode<?>> {
return label;
}
/** Marks the current node as implicit.
* @see #isImplicitInstruction() */
public void markAsImplicit() {
this.isImplicit = true;
variableActions.stream()
.filter(VariableAction.Movable.class::isInstance)
.map(VariableAction.Movable.class::cast)
.map(VariableAction.Movable::getRealNode)
.forEach(GraphNode::markAsImplicit);
}
/** Whether this graph node represents an AST node that didn't exist explicitly, such as 'super()'. */
public boolean isImplicitInstruction() {
return isImplicit;
}
// =============================================================
// =================== Variables and Calls ===================
// =============================================================
......
......@@ -4,7 +4,6 @@ import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.visitor.CloneVisitor;
import es.upv.mist.slicing.graphs.jsysdg.ImplicitNode;
import es.upv.mist.slicing.nodes.GraphNode;
import es.upv.mist.slicing.utils.ASTUtils;
import es.upv.mist.slicing.utils.NodeHashSet;
......@@ -17,16 +16,11 @@ import java.util.*;
public class Slice {
/** Nodes contained in this slice, mapped by id. */
private final Map<Long, GraphNode<?>> map = new HashMap<>();
/** The AST nodes contained in this slice. */
private final List<Node> nodes = new LinkedList<>();
/** Add a node to this slice. */
public void add(GraphNode<?> node) {
assert !map.containsKey(node.getId());
if (this.isASTOriginalNode(node)) {
map.put(node.getId(), node);
nodes.add(node.getAstNode());
}
map.put(node.getId(), node);
}
/** Add multiple nodes to this slice. */
......@@ -41,7 +35,7 @@ public class Slice {
/** Whether the slice contains the given AST node. */
public boolean contains(Node node) {
return nodes.stream().anyMatch(n -> n == node);
return map.values().stream().anyMatch(gn -> gn.getAstNode() == node);
}
@Override
......@@ -65,11 +59,13 @@ public class Slice {
Map<CompilationUnit, NodeHashSet<Node>> cuMap = ASTUtils.newIdentityHashMap();
// Add each node to the corresponding bucket of the map
// Nodes may not belong to a compilation unit (fictional nodes), and they are skipped for the slice.
for (Node node : nodes) {
Optional<CompilationUnit> cu = node.findCompilationUnit();
for (GraphNode<?> graphNode : map.values()) {
if (graphNode.isImplicitInstruction())
continue;
Optional<CompilationUnit> cu = graphNode.getAstNode().findCompilationUnit();
if (cu.isEmpty()) continue;
cuMap.computeIfAbsent(cu.get(), compilationUnit -> new NodeHashSet<>());
cuMap.get(cu.get()).add(node);
cuMap.get(cu.get()).add(graphNode.getAstNode());
}
// Traverse the AST of each compilation unit, creating a copy and
// removing any element not present in the slice.
......@@ -86,9 +82,4 @@ public class Slice {
}
return cus;
}
/** Returns whether a node was in the original AST or was added by instrumentation. */
private boolean isASTOriginalNode(GraphNode<?> node){
return !(node instanceof ImplicitNode);
}
}
......@@ -21,6 +21,8 @@ public class Josep2 {
class Numeros {
int noHaceFalta = 1;
int random() {
return haceFalta;
}
......
class A {
int xA = 0;
int getx() {
return xA;
}
......
......@@ -21,6 +21,8 @@ public class Josep2 {
class Numeros {
int noHaceFalta = 1;
int random() {
return haceFalta;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment