summaryrefslogtreecommitdiffstats
path: root/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CodanBuilder.java
blob: 6685b98f4daafc7f2436400d3f87d27f780b5129 (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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/*******************************************************************************
 * Copyright (c) 2009, 2010 Alena Laskavaia 
 * 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:
 *    Alena Laskavaia  - initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.codan.internal.core;

import java.util.Map;

import org.eclipse.cdt.codan.core.CodanCorePlugin;
import org.eclipse.cdt.codan.core.CodanRuntime;
import org.eclipse.cdt.codan.core.Messages;
import org.eclipse.cdt.codan.core.model.IChecker;
import org.eclipse.cdt.codan.core.model.ICodanBuilder;
import org.eclipse.cdt.codan.core.model.IProblemReporter;
import org.eclipse.cdt.codan.core.model.IProblemReporterPersistent;
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;

/**
 * Implementation of {@link ICodanBuilder}
 */
public class CodanBuilder extends IncrementalProjectBuilder implements
		ICodanBuilder {
	/**
	 * codan builder id
	 */
	public static final String BUILDER_ID = "org.eclipse.cdt.codan.core.codanBuilder"; //$NON-NLS-1$

	private class CodanDeltaVisitor implements IResourceDeltaVisitor {
		private IProgressMonitor monitor;

		/**
		 * @param monitor
		 */
		public CodanDeltaVisitor(IProgressMonitor monitor) {
			this.monitor = monitor;
		}

		public boolean visit(IResourceDelta delta) throws CoreException {
			IResource resource = delta.getResource();
			switch (delta.getKind()) {
				case IResourceDelta.ADDED:
					// handle added resource
					processResource(resource, monitor);
					break;
				case IResourceDelta.REMOVED:
					// handle removed resource
					break;
				case IResourceDelta.CHANGED:
					// handle changed resource
					processResource(resource, monitor);
					break;
			}
			// return true to continue visiting children.
			return true;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 * java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	@SuppressWarnings("rawtypes")
	@Override
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
			throws CoreException {
		if (kind == FULL_BUILD) {
			fullBuild(monitor);
		} else {
			IResourceDelta delta = getDelta(getProject());
			if (delta == null) {
				fullBuild(monitor);
			} else {
				incrementalBuild(delta, monitor);
			}
		}
		return null;
	}

	public void processResource(IResource resource, IProgressMonitor monitor) {
		processResource(resource, monitor, null, false);
	}

	protected void processResource(IResource resource,
			IProgressMonitor monitor, Object model, boolean inEditor) {
		CheckersRegistry chegistry = CheckersRegistry.getInstance();
		int checkers = chegistry.getCheckersSize();
		int memsize = 0;
		if (resource instanceof IContainer) {
			try {
				IResource[] members = ((IContainer) resource).members();
				memsize = members.length;
			} catch (CoreException e) {
				CodanCorePlugin.log(e);
			}
		}
		int tick = 1000;
		// System.err.println("processing " + resource);
		monitor.beginTask(Messages.CodanBuilder_Code_Analysis_On + resource,
				checkers + memsize * tick);
		try {
			IProblemReporter problemReporter = CodanRuntime.getInstance()
					.getProblemReporter();
			for (IChecker checker : chegistry) {
				try {
					if (monitor.isCanceled())
						return;
					if (checker.enabledInContext(resource)) {
						// delete markers if checker can possibly run on this
						// resource
						// this way if checker is not enabled markers would be
						// deleted too
						if (problemReporter instanceof IProblemReporterPersistent) {
							// delete general markers
							((IProblemReporterPersistent) problemReporter)
									.deleteProblems(resource, checker);
						}
						if (chegistry.isCheckerEnabled(checker, resource)) {
							if (inEditor) {
								if (checker.runInEditor()
										&& checker instanceof IRunnableInEditorChecker) {
									((IRunnableInEditorChecker) checker)
											.processModel(model);
								}
							} else {
								checker.processResource(resource);
							}
						}
					}
					monitor.worked(1);
				} catch (Throwable e) {
					CodanCorePlugin.log(e);
				}
			}
			if (resource instanceof IContainer) {
				try {
					IResource[] members = ((IContainer) resource).members();
					for (int i = 0; i < members.length; i++) {
						if (monitor.isCanceled())
							return;
						IResource member = members[i];
						processResource(member, new SubProgressMonitor(monitor,
								tick));
					}
				} catch (CoreException e) {
					CodanCorePlugin.log(e);
				}
			}
		} finally {
			monitor.done();
		}
	}

	protected void fullBuild(final IProgressMonitor monitor)
			throws CoreException {
		processResource(getProject(), monitor);
	}

	protected void incrementalBuild(IResourceDelta delta,
			IProgressMonitor monitor) throws CoreException {
		// the visitor does the work.
		delta.accept(new CodanDeltaVisitor(monitor));
	}

	/**
	 * Run all checkers that support "check as you type" mode
	 * 
	 * @param model - model of given resource such as ast
	 * @param resource - resource to process
	 * @param monitor - progress monitor
	 */
	public void runInEditor(Object model, IResource resource,
			IProgressMonitor monitor) {
		if (model == null)
			return;
		processResource(resource, monitor, model, true);
	}
}