summaryrefslogtreecommitdiffstats
path: root/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/CloseOpenedFilesChecker.java
blob: 8acdc8115fbdb754868e5294789d11836a276d5d (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
152
153
154
155
156
157
/*******************************************************************************
 * 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;

import java.io.File;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.cdt.codan.core.model.AbstractIndexAstChecker;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression;
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.IBinding;
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.IBlock;
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 class CloseOpenedFilesChecker extends AbstractIndexAstChecker {
	private static final String ERR_ID = Activator.PLUGIN_ID + ".CloseOpenedFilesProblem";

	public void processAst(IASTTranslationUnit ast) {
		// traverse the AST using the visitor pattern
		CloseOpenedFilesVisitor visitor = new CloseOpenedFilesVisitor();
		
		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
			ICallGraphNode cgRoot = cg.topEntry();
			IASTStatement fnBody = cgRoot.getFuncDef().getBody();
			IControlFlowGraph cfg = new ControlFlowGraph(fnBody);
			cfg.buildCFG();
			cfg.print();
			
			ast.accept(visitor);			
		}		
	}


	private void reportProblem(IASTName closeFD) {
		String message = MessageFormat.format("File descriptor \"{0}\" has not been opened", closeFD.toString());
		reportProblem(ERR_ID, closeFD, message);
	}

	
	class CloseOpenedFilesVisitor extends ASTVisitor {
		
		public static final String OPEN = "open";
		public static final String CLOSE = "close";
		
		private List<IASTName> openedFDs;

		public CloseOpenedFilesVisitor() {
			openedFDs = new ArrayList<IASTName>();
			shouldVisitExpressions = true;
		}
		
		@Override
		public int visit(IASTExpression expression) {
			if (expression instanceof IASTFunctionCallExpression) {
				IASTFunctionCallExpression callExpression = (IASTFunctionCallExpression) expression;
				IASTExpression funcName = callExpression.getFunctionNameExpression();
				if (funcName instanceof IASTIdExpression) {
					IASTName name = ((IASTIdExpression) funcName).getName();
					String simpleName = String.valueOf(name.getSimpleID());
					if (simpleName.equals(OPEN)) {
						IASTNode parent = callExpression.getParent();
						// Handle initialization in declaration
						if (parent instanceof IASTInitializerExpression) {
							parent = parent.getParent();
							if (parent instanceof IASTDeclarator) {
								openedFDs.add(((IASTDeclarator) parent).getName());
							}
						}
						// Assignment after declaration
						else if (parent instanceof IASTBinaryExpression) {
							IASTExpression op2 = ((IASTBinaryExpression) parent).getOperand2();
							int operator = ((IASTBinaryExpression) parent).getOperator();
							if (callExpression.equals(op2) && operator == IASTBinaryExpression.op_assign) { 
								IASTExpression op1 = ((IASTBinaryExpression) parent).getOperand1();
								if (op1 instanceof IASTIdExpression) {
									openedFDs.add(((IASTIdExpression) op1).getName());
								}
							}
						}
					}
					else if (simpleName.equals(CLOSE)) {
						IASTExpression paramExpression = callExpression.getParameterExpression();
						if (paramExpression instanceof IASTIdExpression) {
							IASTName fd = ((IASTIdExpression) paramExpression).getName();
							// Add only if no matching opened FD
							boolean match = false;
							for (int i = 0; !match && i < openedFDs.size(); i++) {
								IASTName opened = openedFDs.get(i);
								match = matchingFileDescriptors(fd, opened);
							}
							
							if (!match) {
								reportProblem(fd);
							}
						}
					}
				}
				
				return PROCESS_SKIP;
			}
			else {
				return PROCESS_CONTINUE;
			}
		}
		
		private boolean matchingFileDescriptors(IASTName closeFD, IASTName openFD) {
			// FIXME elaborate
			IBinding closeBinding = closeFD.getBinding();
			IBinding openBinding = openFD.getBinding();
			
			return openBinding != null && closeBinding != null && openBinding.equals(closeBinding);
		}
	}

}