summaryrefslogtreecommitdiffstats
path: root/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/AbstractOpenCloseChecker.java
blob: f457364206ca7df6acb7ce6ea3f8b17f2bc1bdc2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*******************************************************************************
 * Copyright (c) 2009 Elliott Baron
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Elliott Baron - initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.codan.extension.checkers;

import java.io.File;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.cdt.codan.core.model.AbstractIndexAstChecker;
import org.eclipse.cdt.codan.extension.ExecutionState;
import org.eclipse.cdt.codan.extension.IPropertyFSM;
import org.eclipse.cdt.codan.extension.PropertySimulator;
import org.eclipse.cdt.codan.extension.PropertyState;
import org.eclipse.cdt.codan.extension.SymbolicState;
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.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.GraphCreator;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.ICallGraph;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.ICallGraphNode;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.IControlFlowGraph;
import org.eclipse.ptp.pldt.mpi.analysis.cdt.graphs.impl.ControlFlowGraph;

public abstract class AbstractOpenCloseChecker extends AbstractIndexAstChecker {	
	private IPropertyFSM fsm;
	
	// Property FSM states
	private PropertyState uninit;
	private PropertyState error;
	private PropertyState opened;

	public AbstractOpenCloseChecker() {
		fsm = initFSM();
	}

	public void processAst(IASTTranslationUnit ast) {
		GraphCreator creator = new GraphCreator();

		// Retrieve resource corresponding to this translation unit
		String path = ast.getFilePath();
		URI fileURI = new File(path).toURI();
		IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
		IResource[] resources = wsRoot.findFilesForLocationURI(fileURI);
		if (resources != null && resources.length > 0) {
			IProject proj = resources[0].getProject();

			// Create call graph for project
			ICallGraph cg = creator.createCallGraph(proj);
			creator.computeCallGraph(cg);

			// Create control flow graph for each function
			for (ICallGraphNode node : cg.getAllNodes()) {
				IASTStatement fnBody = node.getFuncDef().getBody();
				IControlFlowGraph cfg = new ControlFlowGraph(fnBody);
				cfg.buildCFG();

				// Search for error states using property simulation algorithm
				PropertySimulator sim = new PropertySimulator(cfg, fsm);

				// Check if the exit edge of the CFG contains an error state
				for (SymbolicState s : sim.getEndStates()) {
					if (s.getPropertyStates().contains(error)) {
						// Report problems
						for (IASTNode errorNode : s.getErrorCauses()) {
							reportProblem(errorNode, s.getExecutionState());
						}
					}
				}
			}
		}		
	}
	
	private IPropertyFSM initFSM() {
		uninit = new PropertyState("$u") {			
			@Override
			public PropertyState transition(IASTNode node) {
				PropertyState dest = uninit;
				if (containsOpen(node)) {
					dest = opened;
				}
				else if (containsClose(node)) {
					dest = error;
				}
				return dest;
			}
		};
		
		opened = new PropertyState("o") {			
			@Override
			public PropertyState transition(IASTNode node) {
				PropertyState dest = opened;
				if (containsOpen(node)) {
					dest = error;
				}
				if (containsClose(node)) {
					dest = uninit;
				}
				return dest;
			}
		};
		
		error = new PropertyState("$e") {
			
			@Override
			public PropertyState transition(IASTNode node) {
				return error;
			}
		};
		
		return new IPropertyFSM() {
			
			@Override
			public PropertyState getUninitState() {
				return uninit;
			}
			
			@Override
			public Set<PropertyState> getPropertyStates() {
				Set<PropertyState> states = new HashSet<PropertyState>();
				states.add(uninit);
				states.add(opened);
				states.add(error);
				return states;
			}
			
			@Override
			public PropertyState getErrorState() {
				return error;
			}
		};
	}
	
	protected abstract boolean containsOpen(IASTNode node);

	protected abstract boolean containsClose(IASTNode node);
	
	protected abstract void reportProblem(IASTNode node, ExecutionState condition);
}