summaryrefslogtreecommitdiffstats
path: root/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java')
-rw-r--r--org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java166
1 files changed, 146 insertions, 20 deletions
diff --git a/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java b/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java
index 04348ab..a38ef13 100644
--- a/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java
+++ b/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java
@@ -27,9 +27,17 @@ import org.eclipse.cdt.codan.extension.ExecutionStateClause;
import org.eclipse.cdt.codan.extension.PropertyState;
import org.eclipse.cdt.codan.extension.SymbolicState;
import org.eclipse.cdt.codan.extension.VariableAssignmentVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
+import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
@@ -81,19 +89,22 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker {
ICallGraph cg = creator.createCallGraph(proj);
creator.computeCallGraph(cg);
- // Create control flow graph
- ICallGraphNode cgRoot = cg.topEntry();
- IASTStatement fnBody = cgRoot.getFuncDef().getBody();
- IControlFlowGraph cfg = new ControlFlowGraph(fnBody);
- cfg.buildCFG();
+ // Create control flow graph for each function
+ for (ICallGraphNode node : cg.getAllNodes()) {
+ IASTStatement fnBody = node.getFuncDef().getBody();
+ IControlFlowGraph cfg = new ControlFlowGraph(fnBody);
+ cfg.buildCFG();
- solve(cfg);
-
- IControlFlowEdge exitEdge = cfg.getExit().getInEdges()[0];
- for (SymbolicState s : edgeInfo.get(exitEdge)) {
- if (s.getPropertyStates().contains(error)) {
- // Report problem
- reportProblem(errorNode, s.getExecutionState());
+ // Search for error states using property simulation algorithm
+ solve(cfg);
+
+ // Check if the exit edge of the CFG contains an error state
+ IControlFlowEdge exitEdge = cfg.getExit().getInEdges()[0];
+ for (SymbolicState s : edgeInfo.get(exitEdge)) {
+ if (s.getPropertyStates().contains(error)) {
+ // Report problem
+ reportProblem(errorNode, s.getExecutionState());
+ }
}
}
}
@@ -112,9 +123,7 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker {
Set<SymbolicState> symStates = edgeInfo.get(entryEdge);
Set<PropertyState> propStates = new HashSet<PropertyState>();
propStates.add(uninit);
- ExecutionState es = new ExecutionState();
- es.setTop(true);
- symStates.add(new SymbolicState(propStates, es));
+ symStates.add(new SymbolicState(propStates, new ExecutionState()));
worklist.add(entryEdge.getTo());
// XXX Debug
@@ -199,20 +208,99 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker {
}
private Set<SymbolicState> group(Set<SymbolicState> ss) {
- // FIXME Fully Path Sensitive
+ return groupPSA(ss);
+ }
+
+ private Set<SymbolicState> groupPSA(Set<SymbolicState> ss) {
return ss;
}
+
+ private Set<SymbolicState> groupPropSim(Set<SymbolicState> ss) {
+ Set<SymbolicState> ret = new HashSet<SymbolicState>();
+
+ // Group SymbolicStates by PropertyState
+ Map<PropertyState, Set<ExecutionState>> statesPerProperty = new HashMap<PropertyState, Set<ExecutionState>>();
+ for (SymbolicState s : ss) {
+ for (PropertyState ps : s.getPropertyStates()) {
+ if (!statesPerProperty.containsKey(ps)) {
+ statesPerProperty.put(ps, new HashSet<ExecutionState>());
+ }
+ Set<ExecutionState> states = statesPerProperty.get(ps);
+ states.add(s.getExecutionState());
+ }
+ }
+
+ // Iterate through result and create SymbolicStates per PropertyState with ExecutionStates joined
+ for (PropertyState p : statesPerProperty.keySet()) {
+ Set<PropertyState> ps = new HashSet<PropertyState>();
+ ps.add(p);
+ ExecutionState es = new ExecutionState();
+ for (ExecutionState e : statesPerProperty.get(p)) {
+ es.join(e);
+ }
+ SymbolicState s = new SymbolicState(ps, es);
+ ret.add(s);
+ }
+
+ return ret;
+ }
private SymbolicState transferBranch(IBlock blk, SymbolicState s, boolean value) {
IASTNode node = blk.getContent();
SymbolicState ret = s.copy();
- if (node != null) {
- // TODO Theorem Prover goes here! / Determine if branch is feasible
-
+ if (node != null) {
// Modify execution state according to branch condition
+ ExecutionStateClause clause = null;
// *N.B.* content for condition IBlock is condition expression itself
- ret.getExecutionState().addClause(new ExecutionStateClause(node, value));
+ if (node instanceof IASTBinaryExpression) {
+ // FIXME compound conditionals
+ IASTBinaryExpression binExpr = (IASTBinaryExpression) node;
+ int op = binExpr.getOperator();
+
+ // FIXME other ops
+ // Check operator is an equality operator
+ if (op == IASTBinaryExpression.op_equals) { // if (x == 0)
+ IASTExpression o1 = binExpr.getOperand1();
+ if (o1 instanceof IASTIdExpression) {
+ IASTName name = ((IASTIdExpression) o1).getName();
+ clause = parseConditional(clause, name, binExpr.getOperand2(), value);
+ }
+ }
+ else if (op == IASTBinaryExpression.op_notequals) { // if (x != 0)
+ IASTExpression o1 = binExpr.getOperand1();
+ if (o1 instanceof IASTIdExpression) {
+ IASTName name = ((IASTIdExpression) o1).getName();
+ clause = parseConditional(clause, name, binExpr.getOperand2(), !value); // Negation
+ }
+ }
+ }
+ else if (node instanceof IASTUnaryExpression) { // if (!x)
+ IASTUnaryExpression uExpr = (IASTUnaryExpression) node;
+ int op = uExpr.getOperator();
+
+ // Check operator is a negation operator
+ if (op == IASTUnaryExpression.op_not) {
+ IASTExpression operand = uExpr.getOperand();
+ if (operand instanceof IASTIdExpression) {
+ IASTName name = ((IASTIdExpression) operand).getName();
+ clause = parseConditional(clause, name, !value); // Negation
+ }
+ }
+ }
+ else if (node instanceof IASTIdExpression) { // if (x)
+ IASTName name = ((IASTIdExpression) node).getName();
+ clause = parseConditional(clause, name, value);
+ }
+
+ if (clause != null) {
+ ret.getExecutionState().addClause(clause);
+ // TODO Theorem Prover goes here! / Determine if branch is feasible
+ ret.getExecutionState().bindTruthAssignments();
+ }
+ else {
+ // FIXME Handle unresolvable case
+ }
}
return ret;
@@ -313,4 +401,42 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker {
String message = MessageFormat.format("Improper use of open/close given {0}.", condition);
reportProblem(ERR_ID, node, message);
}
+
+ // FIXME REFACTOR
+ private ExecutionStateClause parseConditional(ExecutionStateClause clause, IASTName name, IASTExpression valueExpr, boolean branchTruth) {
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof IVariable) {
+ IVariable var = (IVariable) binding;
+ Boolean truth = getTruthValue(valueExpr);
+ if (truth != null) {
+ clause = new ExecutionStateClause(var, truth == branchTruth);
+ }
+ }
+ return clause;
+ }
+
+ private ExecutionStateClause parseConditional(ExecutionStateClause clause, IASTName name, boolean branchTruth) {
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof IVariable) {
+ IVariable var = (IVariable) binding;
+ clause = new ExecutionStateClause(var, branchTruth);
+ }
+ return clause;
+ }
+
+ private Boolean getTruthValue(IASTExpression valueExpr) {
+ Boolean result = null;
+ // Handle assignment from literals
+ if (valueExpr instanceof IASTLiteralExpression) {
+ int kind = ((IASTLiteralExpression) valueExpr).getKind();
+ String value = String.valueOf(((IASTLiteralExpression) valueExpr).getValue());
+ switch (kind) {
+ case IASTLiteralExpression.lk_integer_constant:
+ // 0 = False, > 0 = True
+ result = !value.equals("0");
+ }
+ }
+ // TODO other variable assignments
+ return result;
+ }
}