View | Details | Raw Unified | Return to bug 233643 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/pde/api/tools/internal/builder/BaseApiAnalyzer.java (-4 / +4 lines)
Lines 301-307 Link Here
301
					}
301
					}
302
				}
302
				}
303
				if (changedTypes != null) {
303
				if (changedTypes != null) {
304
					// check the ones not already checked as part of typenames check
304
					// check the ones not already checked as part of type names check
305
					for (int i = 0; i < changedTypes.length; i++) {
305
					for (int i = 0; i < changedTypes.length; i++) {
306
						String typeName = changedTypes[i];
306
						String typeName = changedTypes[i];
307
						if (typeNamesSet == null || !typeNamesSet.remove(typeName)) {
307
						if (typeNamesSet == null || !typeNamesSet.remove(typeName)) {
Lines 1550-1556 Link Here
1550
							Util.EMPTY_STRING);
1550
							Util.EMPTY_STRING);
1551
				}
1551
				}
1552
			}
1552
			}
1553
			// analyse version of required components
1553
			// analyze version of required components
1554
			ReexportedBundleVersionInfo info = null;
1554
			ReexportedBundleVersionInfo info = null;
1555
			if (problem != null) {
1555
			if (problem != null) {
1556
				switch (problem.getKind()) {
1556
				switch (problem.getKind()) {
Lines 1580-1586 Link Here
1580
						}
1580
						}
1581
						break;
1581
						break;
1582
					case IApiProblem.MINOR_VERSION_CHANGE :
1582
					case IApiProblem.MINOR_VERSION_CHANGE :
1583
						// check if there is a version change required due to reexported bundles
1583
						// check if there is a version change required due to re-exported bundles
1584
						info = checkBundleVersionsOfReexportedBundles(reference, component);
1584
						info = checkBundleVersionsOfReexportedBundles(reference, component);
1585
						if (info != null) {
1585
						if (info != null) {
1586
							switch(info.kind) {
1586
							switch(info.kind) {
Lines 1602-1608 Link Here
1602
						}
1602
						}
1603
						break;
1603
						break;
1604
					case IApiProblem.MINOR_VERSION_CHANGE_NO_NEW_API :
1604
					case IApiProblem.MINOR_VERSION_CHANGE_NO_NEW_API :
1605
						// check if there is a version change required due to reexported bundles
1605
						// check if there is a version change required due to re-exported bundles
1606
						info = checkBundleVersionsOfReexportedBundles(reference, component);
1606
						info = checkBundleVersionsOfReexportedBundles(reference, component);
1607
						if (info != null) {
1607
						if (info != null) {
1608
							switch(info.kind) {
1608
							switch(info.kind) {
(-)src/org/eclipse/pde/api/tools/internal/builder/BuilderMessages.java (+1 lines)
Lines 20-25 Link Here
20
	public static String checking_api_usage;
20
	public static String checking_api_usage;
21
21
22
	public static String AbstractTypeLeakDetector_vis_type_has_no_api_description;
22
	public static String AbstractTypeLeakDetector_vis_type_has_no_api_description;
23
	public static String ApiAnalysisBuilder_builder_for_project;
23
	public static String ApiAnalysisBuilder_finding_affected_source_files;
24
	public static String ApiAnalysisBuilder_finding_affected_source_files;
24
	public static String ApiAnalysisBuilder_initializing_analyzer;
25
	public static String ApiAnalysisBuilder_initializing_analyzer;
25
	public static String ApiProblemFactory_problem_message_not_found;
26
	public static String ApiProblemFactory_problem_message_not_found;
(-)src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java (-550 / +120 lines)
Lines 22-39 Link Here
22
import java.util.Date;
22
import java.util.Date;
23
import java.util.HashMap;
23
import java.util.HashMap;
24
import java.util.HashSet;
24
import java.util.HashSet;
25
import java.util.Iterator;
26
import java.util.List;
25
import java.util.List;
27
import java.util.Map;
26
import java.util.Map;
28
import java.util.Set;
29
import java.util.jar.JarFile;
27
import java.util.jar.JarFile;
30
28
31
import org.eclipse.core.resources.IFile;
32
import org.eclipse.core.resources.IMarker;
29
import org.eclipse.core.resources.IMarker;
33
import org.eclipse.core.resources.IProject;
30
import org.eclipse.core.resources.IProject;
34
import org.eclipse.core.resources.IResource;
31
import org.eclipse.core.resources.IResource;
35
import org.eclipse.core.resources.IResourceDelta;
32
import org.eclipse.core.resources.IResourceDelta;
36
import org.eclipse.core.resources.IResourceDeltaVisitor;
37
import org.eclipse.core.resources.IWorkspaceRoot;
33
import org.eclipse.core.resources.IWorkspaceRoot;
38
import org.eclipse.core.resources.IncrementalProjectBuilder;
34
import org.eclipse.core.resources.IncrementalProjectBuilder;
39
import org.eclipse.core.resources.ResourcesPlugin;
35
import org.eclipse.core.resources.ResourcesPlugin;
Lines 41-47 Link Here
41
import org.eclipse.core.runtime.IPath;
37
import org.eclipse.core.runtime.IPath;
42
import org.eclipse.core.runtime.IProgressMonitor;
38
import org.eclipse.core.runtime.IProgressMonitor;
43
import org.eclipse.core.runtime.IStatus;
39
import org.eclipse.core.runtime.IStatus;
44
import org.eclipse.core.runtime.NullProgressMonitor;
45
import org.eclipse.core.runtime.OperationCanceledException;
40
import org.eclipse.core.runtime.OperationCanceledException;
46
import org.eclipse.core.runtime.Path;
41
import org.eclipse.core.runtime.Path;
47
import org.eclipse.core.runtime.Platform;
42
import org.eclipse.core.runtime.Platform;
Lines 49-64 Link Here
49
import org.eclipse.core.runtime.SubMonitor;
44
import org.eclipse.core.runtime.SubMonitor;
50
import org.eclipse.jdt.core.IClasspathAttribute;
45
import org.eclipse.jdt.core.IClasspathAttribute;
51
import org.eclipse.jdt.core.IClasspathEntry;
46
import org.eclipse.jdt.core.IClasspathEntry;
52
import org.eclipse.jdt.core.ICompilationUnit;
53
import org.eclipse.jdt.core.IJavaElement;
54
import org.eclipse.jdt.core.IJavaProject;
47
import org.eclipse.jdt.core.IJavaProject;
55
import org.eclipse.jdt.core.IType;
56
import org.eclipse.jdt.core.JavaCore;
48
import org.eclipse.jdt.core.JavaCore;
57
import org.eclipse.jdt.core.JavaModelException;
49
import org.eclipse.jdt.core.JavaModelException;
58
import org.eclipse.jdt.internal.core.JavaModelManager;
59
import org.eclipse.jdt.internal.core.builder.ReferenceCollection;
60
import org.eclipse.jdt.internal.core.builder.State;
61
import org.eclipse.jdt.internal.core.builder.StringSet;
62
import org.eclipse.osgi.service.resolver.BundleDescription;
50
import org.eclipse.osgi.service.resolver.BundleDescription;
63
import org.eclipse.osgi.util.NLS;
51
import org.eclipse.osgi.util.NLS;
64
import org.eclipse.pde.api.tools.internal.ApiDescriptionManager;
52
import org.eclipse.pde.api.tools.internal.ApiDescriptionManager;
Lines 82-174 Link Here
82
 */
70
 */
83
public class ApiAnalysisBuilder extends IncrementalProjectBuilder {
71
public class ApiAnalysisBuilder extends IncrementalProjectBuilder {
84
	/**
72
	/**
85
	 * Visits a resource delta to determine if the changes have been made that might required a rebuild:
86
	 * - modification to the manifest file
87
	 * - removal of the .api_filter file
88
	 */
89
	class ResourceDeltaVisitor implements IResourceDeltaVisitor {
90
		IProject[] projects;
91
		public ResourceDeltaVisitor(IProject[] projects) {
92
			this.projects = projects;
93
		}
94
		private boolean fRequireFullBuild = false;
95
96
		/**
97
		 * Returns whether a full build should be run.
98
		 * 
99
		 * @return whether a full build should be run
100
		 */
101
		boolean shouldRunFullBuild() {
102
			return fRequireFullBuild;
103
		}
104
105
		/* (non-Javadoc)
106
		 * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
107
		 */
108
		public boolean visit(IResourceDelta delta) throws CoreException {
109
			switch (delta.getResource().getType()) {
110
				case IResource.ROOT:
111
				case IResource.PROJECT:
112
					return !fRequireFullBuild;
113
				case IResource.FOLDER:
114
					return !fRequireFullBuild; 
115
				case IResource.FILE:
116
					if (delta.getResource().getProjectRelativePath().equals(MANIFEST_PATH)) {
117
						fRequireFullBuild = true;
118
						break;
119
					}
120
					IResource resource = delta.getResource();
121
					String fileName = resource.getName();
122
					if (Util.isClassFile(fileName)) {
123
						findAffectedSourceFiles(delta);
124
					} else if (Util.isJavaFileName(fileName)) {
125
						IProject project = resource.getProject();
126
						if (fCurrentProject.equals(project)) {
127
							if (delta.getKind() == IResourceDelta.ADDED) {
128
								fAddedRemovedDeltas.add(delta);
129
							}
130
							fTypesToCheck.add(resource);
131
						} else if (this.projects != null) {
132
							loop: for (int i = 0, max = this.projects.length; i < max; i++) {
133
								if (this.projects[i].equals(project)) {
134
									fTypesToCheck.add(resource);
135
									break loop;
136
								}
137
							}
138
						}
139
					} else if (!fRequireFullBuild && IApiCoreConstants.API_FILTERS_XML_NAME.equals(fileName)) {
140
						switch(delta.getKind()) {
141
							case IResourceDelta.REMOVED :
142
							case IResourceDelta.REPLACED :
143
							case IResourceDelta.CHANGED :
144
							case IResourceDelta.ADDED :
145
								fRequireFullBuild = true;
146
						}
147
					}
148
			}
149
			return false;
150
		}
151
	}
152
	/**
153
	 * Constant used for controlling tracing in the API tool builder
73
	 * Constant used for controlling tracing in the API tool builder
154
	 */
74
	 */
155
	private static boolean DEBUG = Util.DEBUG;
75
	static boolean DEBUG = Util.DEBUG;
156
	
76
	
157
	/**
77
	/**
158
	 * Project relative path to the manifest file.
78
	 * Project relative path to the manifest file.
159
	 */
79
	 */
160
	private static final IPath MANIFEST_PATH = new Path(JarFile.MANIFEST_NAME);
80
	static final IPath MANIFEST_PATH = new Path(JarFile.MANIFEST_NAME);
161
	
81
	
162
	/**
82
	/**
163
	 * Internal flag used to determine what created the marker, as there is overlap for reference kinds and deltas
83
	 * Project relative path to the .api_filters file
164
	 */
84
	 */
165
	public static final int REF_TYPE_FLAG = 0;
85
	static final IPath FILTER_PATH = new Path(".settings").append(IApiCoreConstants.API_FILTERS_XML_NAME); //$NON-NLS-1$
86
	
87
	/**
88
	 * Empty listing of projects to be returned by the builder if there is nothing to do
89
	 */
90
	static final IProject[] NO_PROJECTS = new IProject[0];
166
91
167
	/**
92
	/**
168
	 * Constant representing the name of the 'source' attribute on API tooling markers.
93
	 * Constant representing the name of the 'source' attribute on API tooling markers.
169
	 * Value is <code>Api Tooling</code>
94
	 * Value is <code>Api Tooling</code>
170
	 */
95
	 */
171
	public static final String SOURCE = "Api Tooling"; //$NON-NLS-1$
96
	static final String SOURCE = "Api Tooling"; //$NON-NLS-1$
172
	
97
	
173
	/**
98
	/**
174
	 * Method used for initializing tracing in the API tool builder
99
	 * Method used for initializing tracing in the API tool builder
Lines 176-226 Link Here
176
	public static void setDebug(boolean debugValue) {
101
	public static void setDebug(boolean debugValue) {
177
		DEBUG = debugValue || Util.DEBUG;
102
		DEBUG = debugValue || Util.DEBUG;
178
	}
103
	}
104
	
179
	/**
105
	/**
180
	 * The current project for which this builder was defined
106
	 * The current project for which this builder was defined
181
	 */
107
	 */
182
	private IProject fCurrentProject = null;
108
	private IProject currentproject = null;
183
	
109
	
184
	/**
110
	/**
185
	 * The API analyzer for this builder
111
	 * The API analyzer for this builder
186
	 */
112
	 */
187
	private IApiAnalyzer fAnalyzer = null;
113
	private IApiAnalyzer analyzer = null;
188
	
114
	
189
	/**
115
	/**
190
	 * Maps prerequisite projects to their output location(s)
116
	 * Maps prerequisite projects to their output location(s)
191
	 */
117
	 */
192
	private HashMap fProjectToOutputLocations = new HashMap();
118
	private HashMap projecttooutputlocations = new HashMap();
193
	
194
	/**
195
	 * List of type names to lookup for each project context to find dependents of
196
	 */
197
	private StringSet fTypes = new StringSet(3);
198
	
199
	/**
200
	 * List of package names to qualify type names
201
	 */
202
	private StringSet fPackages = new StringSet(3);
203
	
204
	/**
205
	 * The type that we want to check for API problems
206
	 */
207
	private HashSet fTypesToCheck = new HashSet();
208
	/**
209
	 * The set of added/removed deltas that come directly from the builder resource delta 
210
	 */
211
	private HashSet fAddedRemovedDeltas = new HashSet(5);
212
	
119
	
213
	/**
120
	/**
214
	 * Current build state
121
	 * Current build state
215
	 */
122
	 */
216
	private BuildState fBuildState;
123
	private BuildState buildstate = null;
217
	
124
	
218
	/**
125
	/**
219
	 * Cleans up markers associated with API tooling on the given resource.
126
	 * Cleans up markers associated with API tooling on the given resource.
220
	 * 
127
	 * 
221
	 * @param resource
128
	 * @param resource
222
	 */
129
	 */
223
	public static void cleanupMarkers(IResource resource) {
130
	void cleanupMarkers(IResource resource) {
224
		cleanupUsageMarkers(resource);
131
		cleanupUsageMarkers(resource);
225
		cleanupCompatibilityMarkers(resource);
132
		cleanupCompatibilityMarkers(resource);
226
		cleanupUnsupportedTagMarkers(resource);
133
		cleanupUnsupportedTagMarkers(resource);
Lines 230-236 Link Here
230
	 * Cleans up unsupported Javadoc tag markers on the specified resource
137
	 * Cleans up unsupported Javadoc tag markers on the specified resource
231
	 * @param resource
138
	 * @param resource
232
	 */
139
	 */
233
	private static void cleanupUnsupportedTagMarkers(IResource resource) {
140
	void cleanupUnsupportedTagMarkers(IResource resource) {
234
		try {
141
		try {
235
			if(DEBUG) {
142
			if(DEBUG) {
236
				System.out.println("cleaning unsupported tag problems"); //$NON-NLS-1$
143
				System.out.println("cleaning unsupported tag problems"); //$NON-NLS-1$
Lines 245-251 Link Here
245
	 * Cleans up only API compatibility markers on the given {@link IResource}
152
	 * Cleans up only API compatibility markers on the given {@link IResource}
246
	 * @param resource the given resource
153
	 * @param resource the given resource
247
	 */
154
	 */
248
	private static void cleanupCompatibilityMarkers(IResource resource) {
155
	void cleanupCompatibilityMarkers(IResource resource) {
249
		try {
156
		try {
250
			if (resource != null && resource.isAccessible()) {
157
			if (resource != null && resource.isAccessible()) {
251
				resource.deleteMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
158
				resource.deleteMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
Lines 266-272 Link Here
266
	 * cleans up only API usage markers from the given {@link IResource}
173
	 * cleans up only API usage markers from the given {@link IResource}
267
	 * @param resource
174
	 * @param resource
268
	 */
175
	 */
269
	private static void cleanupUsageMarkers(IResource resource) {
176
	void cleanupUsageMarkers(IResource resource) {
270
		try {
177
		try {
271
			if (resource != null && resource.isAccessible()) {
178
			if (resource != null && resource.isAccessible()) {
272
				resource.deleteMarkers(IApiMarkerConstants.API_USAGE_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
179
				resource.deleteMarkers(IApiMarkerConstants.API_USAGE_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
Lines 276-314 Link Here
276
		}
183
		}
277
	}
184
	}
278
	
185
	
279
	/**
280
	 * Adds a type to search for dependents of in considered projects for an incremental build
281
	 * 
282
	 * @param path
283
	 */
284
	private void addDependentsOf(IPath path) {
285
		// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
286
		path = path.setDevice(null);
287
		String packageName = path.removeLastSegments(1).toString();
288
		String typeName = path.lastSegment();
289
		int memberIndex = typeName.indexOf('$');
290
		if (memberIndex > 0) {
291
			typeName = typeName.substring(0, memberIndex);
292
		}
293
		if (fTypes.add(typeName) && fPackages.add(packageName) && DEBUG) {
294
			System.out.println("  will look for dependents of " + typeName + " in " + packageName); //$NON-NLS-1$ //$NON-NLS-2$
295
		}
296
	}
297
	
298
	/* (non-Javadoc)
186
	/* (non-Javadoc)
299
	 * @see org.eclipse.core.resources.IncrementalProjectBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
187
	 * @see org.eclipse.core.resources.IncrementalProjectBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
300
	 */
188
	 */
301
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
189
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
302
		fCurrentProject = getProject();
190
		this.currentproject = getProject();
303
		fAnalyzer = getAnalyzer();
191
		this.analyzer = getAnalyzer();
304
		if (fCurrentProject == null || 
192
		if (!this.currentproject.isAccessible() || !this.currentproject.hasNature(ApiPlugin.NATURE_ID) || hasBeenBuilt(this.currentproject)) {
305
				!fCurrentProject.isAccessible() || 
193
			return NO_PROJECTS;
306
				!fCurrentProject.hasNature(ApiPlugin.NATURE_ID) ||
307
				hasBeenBuilt(fCurrentProject)) {
308
			return new IProject[0];
309
		}
194
		}
310
		if (DEBUG) {
195
		if (DEBUG) {
311
			System.out.println("\nStarting build of " + fCurrentProject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
196
			System.out.println("\nStarting build of " + this.currentproject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
312
		}
197
		}
313
		updateMonitor(monitor, 0);
198
		updateMonitor(monitor, 0);
314
		SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_builder, 2);
199
		SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_builder, 2);
Lines 326-388 Link Here
326
				case AUTO_BUILD :
211
				case AUTO_BUILD :
327
				case INCREMENTAL_BUILD : {
212
				case INCREMENTAL_BUILD : {
328
					IResourceDelta[] deltas = getDeltas(projects);
213
					IResourceDelta[] deltas = getDeltas(projects);
329
					boolean shouldRunFullBuild = false;
214
					if(deltas.length == 0) {
330
					fBuildState = getLastBuiltState(fCurrentProject);
331
					if (fBuildState == null) {
332
						buildAll(baseline, localMonitor.newChild(1));
215
						buildAll(baseline, localMonitor.newChild(1));
333
					} else {
216
						break;
334
						IProject[] reexportedProjects = null;
217
					}
335
						String[] projectNames = this.fBuildState.getReexportedComponents();
218
					this.buildstate = getLastBuiltState(currentproject);
336
						int length = projectNames.length;
219
					if (this.buildstate == null) {
337
						if (length != 0) {
220
						buildAll(baseline, localMonitor.newChild(1));
338
							List allProjects = new ArrayList();
221
						break;
339
							IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
222
					}
340
							for (int i = 0, max = projectNames.length; i < max; i++) {
223
					IResourceDelta manifest = null;
341
								String projectName = projectNames[i];
224
					IResourceDelta filters = null;
342
								IProject project = root.getProject(projectName);
225
					for (int i = 0; i < deltas.length; i++) {
343
								if (project.isAccessible()) {
226
						manifest = deltas[i].findMember(MANIFEST_PATH);
344
									// select only projects that don't exist in the reference baseline
227
						if(manifest != null) {
345
									if (baseline != null && baseline.getApiComponent(projectName) == null) {
228
							break;
346
										allProjects.add(project);
229
						}
347
									}
230
						filters = deltas[i].findMember(FILTER_PATH);
348
								}
231
						if(filters != null){
349
							}
232
							break;
350
							if (allProjects.size() != 0) {
351
								reexportedProjects = new IProject[allProjects.size()];
352
								allProjects.toArray(reexportedProjects);
353
							}
354
						}
233
						}
355
						ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(reexportedProjects);
234
					}
356
						for (int i = 0; i < deltas.length; i++) {
235
					if (manifest != null || filters != null) {
357
							deltas[i].accept(visitor);
236
						if (DEBUG) {
358
							if (visitor.shouldRunFullBuild()) {
237
							System.out.println("Performing full build since MANIFEST.MF or .api_filters was modified"); //$NON-NLS-1$
359
								shouldRunFullBuild = true;
360
								break;
361
							}
362
						}
238
						}
363
						if (shouldRunFullBuild) {
239
						buildAll(baseline, localMonitor.newChild(1));
364
							if (DEBUG) {
240
					}
365
								System.out.println("Performing full build since MANIFEST.MF was modified"); //$NON-NLS-1$
241
					IProject[] reexportedProjects = null;
366
							}
242
					String[] projectNames = this.buildstate.getReexportedComponents();
367
							buildAll(baseline, localMonitor.newChild(1));
243
					int length = projectNames.length;
368
						} else if (deltas.length == 0) {
244
					if (length != 0) {
369
							if (DEBUG) {
245
						List allProjects = new ArrayList();
370
								System.out.println("Performing full build since deltas are missing after incremental request"); //$NON-NLS-1$
246
						IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
371
							}
247
						for (int i = 0, max = projectNames.length; i < max; i++) {
372
							buildAll(baseline, localMonitor.newChild(1));
248
							String projectName = projectNames[i];
373
						} else {
249
							IProject project = root.getProject(projectName);
374
							State state = (State)JavaModelManager.getJavaModelManager().getLastBuiltState(fCurrentProject, new NullProgressMonitor());
250
							if (project.isAccessible()) {
375
							if (state == null) {
251
								// select only projects that don't exist in the reference baseline
376
								buildAll(baseline, localMonitor.newChild(1));
252
								if (baseline != null && baseline.getApiComponent(projectName) == null) {
377
							} else {
253
									allProjects.add(project);
378
								build(state, baseline, localMonitor.newChild(1));
254
								}
379
							}
255
							}
380
						}
256
						}
257
						if (allProjects.size() != 0) {
258
							reexportedProjects = new IProject[allProjects.size()];
259
							allProjects.toArray(reexportedProjects);
260
						}
261
					}
262
					IncrementalApiBuilder incbuilder = new IncrementalApiBuilder(this);
263
					incbuilder.build(baseline, deltas, localMonitor.newChild(1));
381
					}
264
					}
382
					break;
265
					break;
383
				}
266
				}
384
			}
267
				updateMonitor(monitor, 0);
385
			updateMonitor(monitor, 0);
386
		} catch(CoreException e) {
268
		} catch(CoreException e) {
387
			IStatus status = e.getStatus();
269
			IStatus status = e.getStatus();
388
			if (status == null || status.getCode() != ApiPlugin.REPORT_BASELINE_IS_DISPOSED) {
270
			if (status == null || status.getCode() != ApiPlugin.REPORT_BASELINE_IS_DISPOSED) {
Lines 390-415 Link Here
390
			}
272
			}
391
			ApiPlugin.log(e);
273
			ApiPlugin.log(e);
392
		} finally {
274
		} finally {
393
			fTypes.clear();
275
			this.projecttooutputlocations.clear();
394
			fPackages.clear();
395
			fTypesToCheck.clear();
396
			fAddedRemovedDeltas.clear();
397
			fProjectToOutputLocations.clear();
398
			updateMonitor(monitor, 0);
276
			updateMonitor(monitor, 0);
399
			fAnalyzer.dispose();
277
			this.analyzer.dispose();
400
			if(baseline != null) {
278
			if(baseline != null) {
401
				baseline.close();
279
				baseline.close();
402
			}
280
			}
403
			if(monitor != null) {
281
			if(monitor != null) {
404
				monitor.done();
282
				monitor.done();
405
			}
283
			}
406
			if (fBuildState != null) {
284
			if (this.buildstate != null) {
407
				saveBuiltState(fCurrentProject, fBuildState);
285
				saveBuiltState(this.currentproject, this.buildstate);
408
				fBuildState = null;
286
				this.buildstate = null;
409
			}
287
			}
410
		}
288
		}
411
		if (DEBUG) {
289
		if (DEBUG) {
412
			System.out.println("Finished build of " + fCurrentProject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
290
			System.out.println("Finished build of " + currentproject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
413
		}
291
		}
414
		return projects;
292
		return projects;
415
	}
293
	}
Lines 418-431 Link Here
418
	 * Performs a full build for the project
296
	 * Performs a full build for the project
419
	 * @param monitor
297
	 * @param monitor
420
	 */
298
	 */
421
	private void buildAll(IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
299
	void buildAll(IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
422
		IApiBaseline wsprofile = null;
300
		IApiBaseline wsprofile = null;
423
		try {
301
		try {
424
			clearLastState();
302
			clearLastState();
425
			fBuildState = new BuildState();
303
			this.buildstate = new BuildState();
426
			SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 4);
304
			SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 4);
427
			localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_initializing_analyzer, fCurrentProject.getName()));
305
			localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_initializing_analyzer, currentproject.getName()));
428
			cleanupMarkers(fCurrentProject);
306
			cleanupMarkers(this.currentproject);
429
			IPluginModelBase currentModel = getCurrentModel();
307
			IPluginModelBase currentModel = getCurrentModel();
430
			if (currentModel != null) {
308
			if (currentModel != null) {
431
				localMonitor.subTask(BuilderMessages.building_workspace_profile);
309
				localMonitor.subTask(BuilderMessages.building_workspace_profile);
Lines 441-447 Link Here
441
				// Compatibility checks
319
				// Compatibility checks
442
				IApiComponent apiComponent = wsprofile.getApiComponent(id);
320
				IApiComponent apiComponent = wsprofile.getApiComponent(id);
443
				if(apiComponent != null) {
321
				if(apiComponent != null) {
444
					fAnalyzer.analyzeComponent(fBuildState, null, null, baseline, apiComponent, null, null, localMonitor.newChild(1));
322
					this.analyzer.analyzeComponent(this.buildstate, null, null, baseline, apiComponent, null, null, localMonitor.newChild(1));
445
					updateMonitor(localMonitor, 1);
323
					updateMonitor(localMonitor, 1);
446
					createMarkers();
324
					createMarkers();
447
					updateMonitor(localMonitor, 1);
325
					updateMonitor(localMonitor, 1);
Lines 465-477 Link Here
465
	 */
343
	 */
466
	protected void createMarkers() {
344
	protected void createMarkers() {
467
		try {
345
		try {
468
			fCurrentProject.deleteMarkers(IApiMarkerConstants.VERSION_NUMBERING_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
346
			this.currentproject.deleteMarkers(IApiMarkerConstants.VERSION_NUMBERING_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
469
			fCurrentProject.deleteMarkers(IApiMarkerConstants.DEFAULT_API_BASELINE_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
347
			this.currentproject.deleteMarkers(IApiMarkerConstants.DEFAULT_API_BASELINE_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
470
			fCurrentProject.deleteMarkers(IApiMarkerConstants.API_COMPONENT_RESOLUTION_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
348
			this.currentproject.deleteMarkers(IApiMarkerConstants.API_COMPONENT_RESOLUTION_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
471
		} catch (CoreException e) {
349
		} catch (CoreException e) {
472
			ApiPlugin.log(e);
350
			ApiPlugin.log(e);
473
		}
351
		}
474
		IApiProblem[] problems = fAnalyzer.getProblems();
352
		IApiProblem[] problems = this.analyzer.getProblems();
475
		String type = null;
353
		String type = null;
476
		for(int i = 0; i < problems.length; i++) {
354
		for(int i = 0; i < problems.length; i++) {
477
			int category = problems[i].getCategory();
355
			int category = problems[i].getCategory();
Lines 555-561 Link Here
555
							IApiMarkerConstants.MARKER_ATTR_PROBLEM_ID},
433
							IApiMarkerConstants.MARKER_ATTR_PROBLEM_ID},
556
					new Object[] {
434
					new Object[] {
557
							problem.getMessage(),
435
							problem.getMessage(),
558
							new Integer(ApiPlugin.getDefault().getSeverityLevel(ApiProblemFactory.getProblemSeverityId(problem), this.fCurrentProject)),
436
							new Integer(ApiPlugin.getDefault().getSeverityLevel(ApiProblemFactory.getProblemSeverityId(problem), this.currentproject)),
559
							new Integer(line),
437
							new Integer(line),
560
							new Integer(problem.getCharStart()),
438
							new Integer(problem.getCharStart()),
561
							new Integer(problem.getCharEnd()),
439
							new Integer(problem.getCharEnd()),
Lines 597-603 Link Here
597
		if (resourcePath == null) {
475
		if (resourcePath == null) {
598
			return null;
476
			return null;
599
		}
477
		}
600
		IResource resource = fCurrentProject.findMember(new Path(resourcePath));
478
		IResource resource = currentproject.findMember(new Path(resourcePath));
601
		if(resource == null) {
479
		if(resource == null) {
602
			return null;
480
			return null;
603
		}
481
		}
Lines 631-637 Link Here
631
	 * @param ticks
509
	 * @param ticks
632
	 * @throws OperationCanceledException
510
	 * @throws OperationCanceledException
633
	 */
511
	 */
634
	private void updateMonitor(IProgressMonitor monitor, int ticks) throws OperationCanceledException {
512
	void updateMonitor(IProgressMonitor monitor, int ticks) throws OperationCanceledException {
635
		if(monitor != null) {
513
		if(monitor != null) {
636
			monitor.worked(ticks);
514
			monitor.worked(ticks);
637
			if (monitor.isCanceled()) {
515
			if (monitor.isCanceled()) {
Lines 640-871 Link Here
640
		}
518
		}
641
	}
519
	}
642
	
520
	
643
	/**
644
	 * Builds an API delta using the default profile (from the workspace settings and the current
645
	 * workspace profile
646
	 * @param state
647
	 * @param monitor
648
	 */
649
	private void build(final State state, IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
650
		IApiBaseline wsprofile = null;
651
		try {
652
			clearLastState(); // so if the build fails, a full build will be triggered
653
			int typesToCheckSize = fTypesToCheck.size();
654
			SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 2 + (typesToCheckSize != 0 ? 3 : 0));
655
			localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_finding_affected_source_files, fCurrentProject.getName()));
656
			updateMonitor(localMonitor, 0);
657
			collectAffectedSourceFiles(state, fTypesToCheck);
658
			updateMonitor(localMonitor, 1);
659
			if (typesToCheckSize != 0) {
660
				IPluginModelBase currentModel = getCurrentModel();
661
				if (currentModel != null) {
662
					wsprofile = getWorkspaceProfile();
663
					if (wsprofile == null) {
664
						if (DEBUG) {
665
							System.err.println("Could not retrieve a workspace profile"); //$NON-NLS-1$
666
						}
667
						return;
668
					}
669
					String id = currentModel.getBundleDescription().getSymbolicName();
670
					IApiComponent apiComponent = wsprofile.getApiComponent(id);
671
					if(apiComponent == null) {
672
						return;
673
					}
674
					List tnames = new ArrayList(typesToCheckSize),
675
						 cnames = new ArrayList(typesToCheckSize);
676
					collectAllQualifiedNames(fTypesToCheck, tnames, cnames, localMonitor.newChild(1));
677
					updateMonitor(localMonitor, 1);
678
					fAnalyzer.analyzeComponent(fBuildState, 
679
							null, 
680
							null, 
681
							baseline, 
682
							apiComponent, 
683
							(String[])tnames.toArray(new String[tnames.size()]), 
684
							(String[])cnames.toArray(new String[cnames.size()]), 
685
							localMonitor.newChild(1));
686
					updateMonitor(localMonitor, 1);
687
					createMarkers();
688
					updateMonitor(localMonitor, 1);
689
				}
690
			}
691
		}
692
		finally {
693
			if(wsprofile != null) {
694
				wsprofile.close();
695
			}
696
			if(monitor != null) {
697
				monitor.done();
698
			}
699
		}
700
	}
701
	
702
	/**
703
	 * Returns an array of type names, and cleans up markers for the specified resource
704
	 * @param alltypes the listing of {@link IFile}s to get qualified names from
705
	 * @param changedtypes the listing of {@link IFile}s that have actually changed (from the {@link IResourceDelta}
706
	 * @param tnames the list to collect all type names into (including inner member names)
707
	 * @param cnames the list to collect the changed type names into
708
	 * @param monitor
709
	 */
710
	private void collectAllQualifiedNames(final HashSet alltypes, List tnames, List cnames, final IProgressMonitor monitor) {
711
		IType[] types = null;
712
		IFile file = null;
713
		for (Iterator iterator = alltypes.iterator(); iterator.hasNext(); ) {
714
			file = (IFile) iterator.next();
715
			ICompilationUnit unit = (ICompilationUnit) JavaCore.create(file);
716
			if(!unit.exists()) {
717
				continue;
718
			}
719
			IType type = unit.findPrimaryType();
720
			if(type == null) {
721
				continue;
722
			}
723
			updateMonitor(monitor, 0);
724
			cleanupUnsupportedTagMarkers(file);
725
			updateMonitor(monitor, 0);
726
			cleanupCompatibilityMarkers(file);
727
			updateMonitor(monitor, 0);
728
			cnames.add(type.getFullyQualifiedName());
729
			try {
730
				cleanupUsageMarkers(file);
731
				updateMonitor(monitor, 0);
732
				types = unit.getAllTypes();
733
				String tname = null;
734
				for (int i = 0; i < types.length; i++) {
735
					IType type2 = types[i];
736
					if (type2.isMember()) {
737
						tname = type2.getFullyQualifiedName('$');
738
					} else {
739
						tname = type2.getFullyQualifiedName();
740
					}
741
					tnames.add(tname);
742
				}
743
			} catch (JavaModelException e) {
744
				ApiPlugin.log(e.getStatus());
745
			}
746
			updateMonitor(monitor, 0);
747
		}
748
		// inject removed types inside changed type names so that we can properly detect type removal
749
		for (Iterator iterator = this.fAddedRemovedDeltas.iterator(); iterator.hasNext(); ) {
750
			IResourceDelta delta = (IResourceDelta) iterator.next();
751
			if (delta.getKind() != IResourceDelta.REMOVED) continue;
752
			IResource resource = delta.getResource();
753
			IPath typePath = resolveJavaPathFromResource(resource);
754
			if(typePath == null) {
755
				continue;
756
			}
757
			// record removed type names (package + type)
758
			StringBuffer buffer = new StringBuffer();
759
			String[] segments = typePath.segments();
760
			for (int i = 0, max = segments.length; i < max; i++) {
761
				if (i > 0) {
762
					buffer.append('.');
763
				}
764
				buffer.append(segments[i]);
765
			}
766
			cnames.add(String.valueOf(buffer));
767
		}
768
		// clean up markers on added deltas
769
		if (!this.fAddedRemovedDeltas.isEmpty()) {
770
			IResource manifestFile = Util.getManifestFile(this.fCurrentProject);
771
			if (manifestFile != null) {
772
				try {
773
					IMarker[] markers = manifestFile.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
774
					for (int i = 0, max = markers.length; i < max; i++) {
775
						IMarker marker = markers[i];
776
						String typeName = marker.getAttribute(IApiMarkerConstants.MARKER_ATTR_PROBLEM_TYPE_NAME, null);
777
						if (typeName != null) {
778
							for (Iterator iterator = this.fAddedRemovedDeltas.iterator(); iterator.hasNext(); ) {
779
								IResourceDelta delta = (IResourceDelta) iterator.next();
780
								if (delta.getKind() != IResourceDelta.ADDED) continue;
781
								ICompilationUnit unit = (ICompilationUnit) JavaCore.create(delta.getResource());
782
								if(!unit.exists()) {
783
									continue;
784
								}
785
								IType type = unit.findPrimaryType();
786
								if(type == null) {
787
									continue;
788
								}
789
								if (typeName.equals(type.getFullyQualifiedName())) {
790
									marker.delete();
791
									return;
792
								} else {
793
									// check secondary types
794
									try {
795
										types = unit.getAllTypes();
796
										for (int j = 0; j < types.length; j++) {
797
											IType type2 = types[i];
798
											String fullyQualifiedName = null;
799
											if (type2.isMember()) {
800
												fullyQualifiedName = type2.getFullyQualifiedName('$');
801
											} else {
802
												fullyQualifiedName = type2.getFullyQualifiedName();
803
											}
804
											if (typeName.equals(fullyQualifiedName)) {
805
												marker.delete();
806
												return;
807
											}
808
										}
809
									} catch (JavaModelException e) {
810
										ApiPlugin.log(e.getStatus());
811
									}
812
								}
813
							}
814
						}
815
					}
816
				} catch (CoreException e) {
817
					ApiPlugin.log(e.getStatus());
818
				}
819
			}
820
		}
821
		IResource resource = fCurrentProject.findMember(MANIFEST_PATH);
822
		if (resource != null) {
823
			try {
824
				IMarker[] markers = resource.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
825
				loop: for (int i = 0, max = markers.length; i < max; i++) {
826
					IMarker marker = markers[i];
827
					String typeNameFromMarker = Util.getTypeNameFromMarker(marker);
828
					for (Iterator iterator = tnames.iterator(); iterator.hasNext(); ) {
829
						String typeName = (String) iterator.next();
830
						if (typeName.equals(typeNameFromMarker)) {
831
							marker.delete();
832
							continue loop;
833
						}
834
					}
835
				}
836
				markers = resource.findMarkers(IApiMarkerConstants.SINCE_TAGS_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
837
				loop: for (int i = 0, max = markers.length; i < max; i++) {
838
					IMarker marker = markers[i];
839
					String typeNameFromMarker = Util.getTypeNameFromMarker(marker);
840
					for (Iterator iterator = tnames.iterator(); iterator.hasNext(); ) {
841
						String typeName = (String) iterator.next();
842
						if (typeName.equals(typeNameFromMarker)) {
843
							marker.delete();
844
							continue loop;
845
						}
846
					}
847
				}
848
			} catch (CoreException e) {
849
				ApiPlugin.log(e);
850
			}
851
		}
852
	}
853
	
854
	/* (non-Javadoc)
521
	/* (non-Javadoc)
855
	 * @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor)
522
	 * @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor)
856
	 */
523
	 */
857
	protected void clean(IProgressMonitor monitor) throws CoreException {
524
	protected void clean(IProgressMonitor monitor) throws CoreException {
858
		fCurrentProject = getProject();
525
		this.currentproject = getProject();
859
		SubMonitor localmonitor = SubMonitor.convert(monitor, MessageFormat.format(BuilderMessages.CleaningAPIDescription, new String[] {fCurrentProject.getName()}), 2);
526
		SubMonitor localmonitor = SubMonitor.convert(monitor, MessageFormat.format(BuilderMessages.CleaningAPIDescription, new String[] {currentproject.getName()}), 2);
860
		try {
527
		try {
861
			// clean up all existing markers
528
			// clean up all existing markers
862
			cleanupUsageMarkers(fCurrentProject);
529
			cleanupUsageMarkers(this.currentproject);
863
			cleanupCompatibilityMarkers(fCurrentProject);
530
			cleanupCompatibilityMarkers(this.currentproject);
864
			cleanupUnsupportedTagMarkers(fCurrentProject);
531
			cleanupUnsupportedTagMarkers(this.currentproject);
865
			fCurrentProject.deleteMarkers(IApiMarkerConstants.UNUSED_FILTER_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
532
			this.currentproject.deleteMarkers(IApiMarkerConstants.UNUSED_FILTER_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
866
			updateMonitor(localmonitor, 1);
533
			updateMonitor(localmonitor, 1);
867
			//clean up the .api_settings
534
			//clean up the .api_settings
868
			cleanupApiDescription(fCurrentProject);
535
			cleanupApiDescription(this.currentproject);
869
			updateMonitor(localmonitor, 1);
536
			updateMonitor(localmonitor, 1);
870
		}
537
		}
871
		finally {
538
		finally {
Lines 882-974 Link Here
882
			ApiDescriptionManager.getDefault().clean(JavaCore.create(project), true, false);
549
			ApiDescriptionManager.getDefault().clean(JavaCore.create(project), true, false);
883
		}
550
		}
884
	}
551
	}
885
	/**
886
	 * Collects the complete set of affected source files from the current project context based on the current JDT build state.
887
	 * 
888
	 * @param state
889
	 */
890
	private void collectAffectedSourceFiles(State state, Set typesToCheck) {
891
		// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
892
		char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(fPackages);
893
		// if a well known qualified name was found then we can skip over these
894
		if (internedQualifiedNames.length < fPackages.elementSize) {
895
			internedQualifiedNames = null;
896
		}
897
		char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(fTypes, true);
898
		// if a well known name was found then we can skip over these
899
		if (internedSimpleNames.length < fTypes.elementSize) {
900
			internedSimpleNames = null;
901
		}
902
		Object[] keyTable = state.getReferences().keyTable;
903
		Object[] valueTable = state.getReferences().valueTable;
904
		next : for (int i = 0, l = valueTable.length; i < l; i++) {
905
			String typeLocator = (String) keyTable[i];
906
			if (typeLocator != null) {
907
				ReferenceCollection refs = (ReferenceCollection) valueTable[i];
908
				if (refs.includes(internedQualifiedNames, internedSimpleNames, null)) {
909
					IFile file = fCurrentProject.getFile(typeLocator);
910
					if (file == null) {
911
						continue next;
912
					}
913
					if (DEBUG) {
914
						System.out.println("  adding affected source file " + typeLocator); //$NON-NLS-1$
915
					}
916
					typesToCheck.add(file);
917
				}
918
			}
919
		}
920
	}
921
	
922
	
552
	
923
924
	/**
925
	 * Finds affected source files for a resource that has changed that either contains class files or is itself a class file
926
	 * @param binaryDelta
927
	 */
928
	private void findAffectedSourceFiles(IResourceDelta binaryDelta) {
929
		IResource resource = binaryDelta.getResource();
930
		if(resource.getType() == IResource.FILE) {
931
			if (Util.isClassFile(resource.getName())) {
932
				switch (binaryDelta.getKind()) {
933
					case IResourceDelta.REMOVED :
934
						fAddedRemovedDeltas.add(binaryDelta);
935
						//$FALL-THROUGH$
936
					case IResourceDelta.ADDED : {
937
						IPath typePath = resolveJavaPathFromResource(resource);
938
						if(typePath == null) {
939
							return;
940
						}
941
						if (DEBUG) {
942
							System.out.println("Found added/removed class file " + typePath); //$NON-NLS-1$
943
						}
944
						addDependentsOf(typePath);
945
						return;
946
					}
947
					case IResourceDelta.CHANGED : {
948
						if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) {
949
							return; // skip it since it really isn't changed
950
						}
951
						IPath typePath = resolveJavaPathFromResource(resource);
952
						if(typePath == null) {
953
							return;
954
						}
955
						if (DEBUG) {
956
							System.out.println("Found changed class file " + typePath); //$NON-NLS-1$
957
						}
958
						addDependentsOf(typePath);
959
					}
960
				}
961
				return;
962
			}
963
		}
964
	}
965
966
	/**
553
	/**
967
	 * @return the current {@link IPluginModelBase} based on the current project for this builder
554
	 * @return the current {@link IPluginModelBase} based on the current project for this builder
968
	 */
555
	 */
969
	private IPluginModelBase getCurrentModel() {
556
	IPluginModelBase getCurrentModel() {
970
		IPluginModelBase[] workspaceModels = PluginRegistry.getWorkspaceModels();
557
		IPluginModelBase[] workspaceModels = PluginRegistry.getWorkspaceModels();
971
		IPath location = fCurrentProject.getLocation();
558
		IPath location = this.currentproject.getLocation();
972
		IPluginModelBase currentModel = null;
559
		IPluginModelBase currentModel = null;
973
		BundleDescription desc = null;
560
		BundleDescription desc = null;
974
		loop: for (int i = 0, max = workspaceModels.length; i < max; i++) {
561
		loop: for (int i = 0, max = workspaceModels.length; i < max; i++) {
Lines 994-1003 Link Here
994
	 */
581
	 */
995
	private IResourceDelta[] getDeltas(IProject[] projects) {
582
	private IResourceDelta[] getDeltas(IProject[] projects) {
996
		if(DEBUG) {
583
		if(DEBUG) {
997
			System.out.println("Searching for deltas for build of project: "+fCurrentProject.getName()); //$NON-NLS-1$
584
			System.out.println("Searching for deltas for build of project: "+this.currentproject.getName()); //$NON-NLS-1$
998
		}
585
		}
999
		ArrayList deltas = new ArrayList();
586
		ArrayList deltas = new ArrayList();
1000
		IResourceDelta delta = getDelta(fCurrentProject);
587
		IResourceDelta delta = getDelta(this.currentproject);
1001
		if(delta != null) {
588
		if(delta != null) {
1002
			if (DEBUG) {
589
			if (DEBUG) {
1003
				System.out.println("Found a delta: " + delta); //$NON-NLS-1$
590
				System.out.println("Found a delta: " + delta); //$NON-NLS-1$
Lines 1032-1046 Link Here
1032
	 */
619
	 */
1033
	private IProject[] getRequiredProjects(boolean includebinaries) throws CoreException {
620
	private IProject[] getRequiredProjects(boolean includebinaries) throws CoreException {
1034
		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
621
		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
1035
		if (fCurrentProject == null || workspaceRoot == null) { 
622
		if (this.currentproject == null || workspaceRoot == null) { 
1036
			return new IProject[0];
623
			return new IProject[0];
1037
		}
624
		}
1038
		ArrayList projects = new ArrayList();
625
		ArrayList projects = new ArrayList();
1039
		try {
626
		try {
1040
			IJavaProject javaProject = JavaCore.create(fCurrentProject);
627
			IJavaProject javaProject = JavaCore.create(this.currentproject);
1041
			HashSet blocations = new HashSet();
628
			HashSet blocations = new HashSet();
1042
			blocations.add(javaProject.getOutputLocation());
629
			blocations.add(javaProject.getOutputLocation());
1043
			fProjectToOutputLocations.put(fCurrentProject, blocations);
630
			projecttooutputlocations.put(this.currentproject, blocations);
1044
			IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
631
			IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
1045
			for (int i = 0, l = entries.length; i < l; i++) {
632
			for (int i = 0, l = entries.length; i < l; i++) {
1046
				IClasspathEntry entry = entries[i];
633
				IClasspathEntry entry = entries[i];
Lines 1088-1094 Link Here
1088
								}
675
								}
1089
							}
676
							}
1090
						}
677
						}
1091
						fProjectToOutputLocations.put(p, bins);
678
						this.projecttooutputlocations.put(p, bins);
1092
					}
679
					}
1093
				}
680
				}
1094
			}
681
			}
Lines 1104-1112 Link Here
1104
	/**
691
	/**
1105
	 * @return the workspace {@link IApiProfile}
692
	 * @return the workspace {@link IApiProfile}
1106
	 */
693
	 */
1107
	private IApiBaseline getWorkspaceProfile() throws CoreException {
694
	IApiBaseline getWorkspaceProfile() throws CoreException {
1108
		return ApiPlugin.getDefault().getApiBaselineManager().getWorkspaceBaseline();
695
		return ApiPlugin.getDefault().getApiBaselineManager().getWorkspaceBaseline();
1109
	}
696
	}
697
	
698
	/**
699
	 * Returns the output paths of the given project or <code>null</code> if none have been computed
700
	 * @param project
701
	 * @return the output paths for the given project or <code>null</code>
702
	 */
703
	HashSet getProjectOutputPaths(IProject project) {
704
		return (HashSet) this.projecttooutputlocations.get(project);
705
	}
706
	
1110
	/**
707
	/**
1111
	 * Returns is the given classpath entry is optional or not
708
	 * Returns is the given classpath entry is optional or not
1112
	 * @param entry
709
	 * @param entry
Lines 1121-1159 Link Here
1121
		}
718
		}
1122
		return false;
719
		return false;
1123
	}
720
	}
1124
1125
	/**
1126
	 * Resolves the java path from the given resource
1127
	 * @param resource
1128
	 * @return the resolved path or <code>null</code> if the resource is not part of the java model
1129
	 */
1130
	private IPath resolveJavaPathFromResource(IResource resource) {
1131
		IJavaElement element = JavaCore.create(resource);
1132
		if(element != null) {
1133
			switch(element.getElementType()) {
1134
				case IJavaElement.CLASS_FILE: {
1135
					org.eclipse.jdt.core.IClassFile classfile = (org.eclipse.jdt.core.IClassFile) element;
1136
					IType type = classfile.getType();
1137
					HashSet paths = (HashSet) fProjectToOutputLocations.get(resource.getProject());
1138
					IPath prefix = null;
1139
					for(Iterator iter = paths.iterator(); iter.hasNext();) {
1140
						prefix = (IPath) iter.next();
1141
						if(prefix.isPrefixOf(type.getPath())) {
1142
							return type.getPath().removeFirstSegments(prefix.segmentCount()).removeFileExtension();
1143
						}
1144
					}
1145
					break;
1146
				}
1147
			}
1148
		}
1149
		return null;
1150
	}
1151
	
721
	
1152
	/* (non-Javadoc)
722
	/* (non-Javadoc)
1153
	 * @see java.lang.Object#toString()
723
	 * @see java.lang.Object#toString()
1154
	 */
724
	 */
1155
	public String toString() {
725
	public String toString() {
1156
		return "Builder for project: ["+fCurrentProject.getName()+"]"; //$NON-NLS-1$ //$NON-NLS-2$
726
		return NLS.bind(BuilderMessages.ApiAnalysisBuilder_builder_for_project, this.currentproject.getName());
1157
	}
727
	}
1158
	
728
	
1159
	/**
729
	/**
Lines 1170-1176 Link Here
1170
	/**
740
	/**
1171
	 * Reads the build state for the relevant project.
741
	 * Reads the build state for the relevant project.
1172
	 */
742
	 */
1173
	protected static BuildState readState(IProject project) throws CoreException {
743
	static BuildState readState(IProject project) throws CoreException {
1174
		File file = getSerializationFile(project);
744
		File file = getSerializationFile(project);
1175
		if (file != null && file.exists()) {
745
		if (file != null && file.exists()) {
1176
			try {
746
			try {
Lines 1221-1227 Link Here
1221
	/**
791
	/**
1222
	 * Returns the File to use for saving and restoring the last built state for the given project.
792
	 * Returns the File to use for saving and restoring the last built state for the given project.
1223
	 */
793
	 */
1224
	private static File getSerializationFile(IProject project) {
794
	static File getSerializationFile(IProject project) {
1225
		if (!project.exists()) {
795
		if (!project.exists()) {
1226
			return null;
796
			return null;
1227
		}
797
		}
Lines 1235-1241 Link Here
1235
	 * @param state
805
	 * @param state
1236
	 * @throws CoreException
806
	 * @throws CoreException
1237
	 */
807
	 */
1238
	private static void saveBuiltState(IProject project, BuildState state) throws CoreException {
808
	static void saveBuiltState(IProject project, BuildState state) throws CoreException {
1239
		if (DEBUG) {
809
		if (DEBUG) {
1240
			System.out.println("Saving build state for project: "+project.getName()); //$NON-NLS-1$
810
			System.out.println("Saving build state for project: "+project.getName()); //$NON-NLS-1$
1241
		}
811
		}
Lines 1281-1287 Link Here
1281
	 * Clears the last build state by setting it to <code>null</code>
851
	 * Clears the last build state by setting it to <code>null</code>
1282
	 * @throws CoreException
852
	 * @throws CoreException
1283
	 */
853
	 */
1284
	private void clearLastState() throws CoreException {
854
	void clearLastState() throws CoreException {
1285
		setLastBuiltState(fCurrentProject, null);
855
		setLastBuiltState(this.currentproject, null);
1286
	}
856
	}
1287
}
857
}
(-)src/org/eclipse/pde/api/tools/internal/builder/buildermessages.properties (+1 lines)
Lines 13-18 Link Here
13
building_workspace_profile=Building workspace API profile
13
building_workspace_profile=Building workspace API profile
14
checking_api_usage=Checking API use of ''{0}''
14
checking_api_usage=Checking API use of ''{0}''
15
AbstractTypeLeakDetector_vis_type_has_no_api_description=Visible type {0} has no API description
15
AbstractTypeLeakDetector_vis_type_has_no_api_description=Visible type {0} has no API description
16
ApiAnalysisBuilder_builder_for_project=Builder for project: [{0}]
16
ApiAnalysisBuilder_finding_affected_source_files=Finding affected source in ''{0}''
17
ApiAnalysisBuilder_finding_affected_source_files=Finding affected source in ''{0}''
17
ApiAnalysisBuilder_initializing_analyzer=Initializing analyzer for ''{0}''
18
ApiAnalysisBuilder_initializing_analyzer=Initializing analyzer for ''{0}''
18
ApiProblemFactory_problem_message_not_found=Message not found for id: {0}
19
ApiProblemFactory_problem_message_not_found=Message not found for id: {0}
(-)src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java (-2 lines)
Lines 56-62 Link Here
56
import org.eclipse.jdt.core.IPackageFragment;
56
import org.eclipse.jdt.core.IPackageFragment;
57
import org.eclipse.jdt.core.IPackageFragmentRoot;
57
import org.eclipse.jdt.core.IPackageFragmentRoot;
58
import org.eclipse.jdt.core.JavaCore;
58
import org.eclipse.jdt.core.JavaCore;
59
import org.eclipse.pde.api.tools.internal.builder.ApiAnalysisBuilder;
60
import org.eclipse.pde.api.tools.internal.model.ApiBaseline;
59
import org.eclipse.pde.api.tools.internal.model.ApiBaseline;
61
import org.eclipse.pde.api.tools.internal.model.ApiModelFactory;
60
import org.eclipse.pde.api.tools.internal.model.ApiModelFactory;
62
import org.eclipse.pde.api.tools.internal.model.StubApiComponent;
61
import org.eclipse.pde.api.tools.internal.model.StubApiComponent;
Lines 880-886 Link Here
880
									IJavaProject jp = JavaCore.create(project);
879
									IJavaProject jp = JavaCore.create(project);
881
									if (jp.exists()) {
880
									if (jp.exists()) {
882
										ApiDescriptionManager.getDefault().clean(jp, true, true);
881
										ApiDescriptionManager.getDefault().clean(jp, true, true);
883
										ApiAnalysisBuilder.cleanupMarkers(resource);
884
									}
882
									}
885
								}
883
								}
886
							} catch (CoreException e) {
884
							} catch (CoreException e) {
(-)src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java (-2 / +2 lines)
Lines 139-146 Link Here
139
	 * Cleans the API description for the given project.
139
	 * Cleans the API description for the given project.
140
	 * 
140
	 * 
141
	 * @param project
141
	 * @param project
142
	 * @param whether to delete the file on disk
142
	 * @param delete whether to delete the file on disk
143
	 * @param whether to remove the cached API description
143
	 * @param remove whether to remove the cached API description
144
	 */
144
	 */
145
	public synchronized void clean(IJavaProject project, boolean delete, boolean remove) {
145
	public synchronized void clean(IJavaProject project, boolean delete, boolean remove) {
146
		ProjectApiDescription desc = null;
146
		ProjectApiDescription desc = null;
(-)src/org/eclipse/pde/api/tools/internal/builder/IncrementalApiBuilder.java (+507 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2009 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.pde.api.tools.internal.builder;
12
13
import java.util.ArrayList;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.Set;
18
19
import org.eclipse.core.resources.IFile;
20
import org.eclipse.core.resources.IMarker;
21
import org.eclipse.core.resources.IProject;
22
import org.eclipse.core.resources.IResource;
23
import org.eclipse.core.resources.IResourceDelta;
24
import org.eclipse.core.resources.IResourceDeltaVisitor;
25
import org.eclipse.core.runtime.CoreException;
26
import org.eclipse.core.runtime.IPath;
27
import org.eclipse.core.runtime.IProgressMonitor;
28
import org.eclipse.core.runtime.SubMonitor;
29
import org.eclipse.jdt.core.ICompilationUnit;
30
import org.eclipse.jdt.core.IJavaElement;
31
import org.eclipse.jdt.core.IType;
32
import org.eclipse.jdt.core.JavaCore;
33
import org.eclipse.jdt.core.JavaModelException;
34
import org.eclipse.jdt.internal.core.JavaModelManager;
35
import org.eclipse.jdt.internal.core.builder.ReferenceCollection;
36
import org.eclipse.jdt.internal.core.builder.State;
37
import org.eclipse.jdt.internal.core.builder.StringSet;
38
import org.eclipse.osgi.util.NLS;
39
import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
40
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
41
import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
42
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
43
import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
44
import org.eclipse.pde.api.tools.internal.util.Util;
45
import org.eclipse.pde.core.plugin.IPluginModelBase;
46
47
/**
48
 * Used to incrementally build changed Java types
49
 * 
50
 * @since 3.5
51
 */
52
public class IncrementalApiBuilder {
53
54
	/**
55
	 * Visits a resource delta to determine if the changes have been made that might required a rebuild:
56
	 * - modification to the manifest file
57
	 * - removal of the .api_filter file
58
	 */
59
	class ResourceDeltaVisitor implements IResourceDeltaVisitor {
60
		IProject[] projects;
61
		public ResourceDeltaVisitor(IProject[] projects) {
62
			this.projects = projects;
63
		}
64
		private boolean fRequireFullBuild = false;
65
66
		/**
67
		 * Returns whether a full build should be run.
68
		 * 
69
		 * @return whether a full build should be run
70
		 */
71
		boolean shouldRunFullBuild() {
72
			return fRequireFullBuild;
73
		}
74
75
		/* (non-Javadoc)
76
		 * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
77
		 */
78
		public boolean visit(IResourceDelta delta) throws CoreException {
79
			switch (delta.getResource().getType()) {
80
				case IResource.ROOT:
81
				case IResource.PROJECT:
82
					return !fRequireFullBuild;
83
				case IResource.FOLDER:
84
					return !fRequireFullBuild; 
85
				case IResource.FILE:
86
					IResource resource = delta.getResource();
87
					String fileName = resource.getName();
88
					if (Util.isClassFile(fileName)) {
89
						findAffectedSourceFiles(delta);
90
					} else if (Util.isJavaFileName(fileName)) {
91
						IProject project = resource.getProject();
92
						if (IncrementalApiBuilder.this.project.equals(project)) {
93
							if (delta.getKind() == IResourceDelta.ADDED) {
94
								IncrementalApiBuilder.this.addremovedeltas.add(delta);
95
							}
96
							IncrementalApiBuilder.this.changedtypes.add(resource);
97
						} else if (this.projects != null) {
98
							loop: for (int i = 0, max = this.projects.length; i < max; i++) {
99
								if (this.projects[i].equals(project)) {
100
									IncrementalApiBuilder.this.changedtypes.add(resource);
101
									break loop;
102
								}
103
							}
104
						}
105
					} else if (!fRequireFullBuild && IApiCoreConstants.API_FILTERS_XML_NAME.equals(fileName)) {
106
						switch(delta.getKind()) {
107
							case IResourceDelta.REMOVED :
108
							case IResourceDelta.REPLACED :
109
							case IResourceDelta.CHANGED :
110
							case IResourceDelta.ADDED :
111
								fRequireFullBuild = true;
112
						}
113
					}
114
			}
115
			return false;
116
		}
117
	}
118
	
119
	State state = null;
120
	ApiAnalysisBuilder builder = null;
121
	IProject project = null;
122
	HashSet changedtypes = new HashSet(16);
123
	HashSet addremovedeltas = new HashSet(8);
124
	StringSet typenames = new StringSet(16);
125
	StringSet packages = new StringSet(16);
126
	
127
	
128
	/**
129
	 * Constructor
130
	 * @param project the current project context being built
131
	 * @param delta the {@link IResourceDelta} from the build framework
132
	 * @param buildstate the current build state from the {@link org.eclipse.jdt.internal.core.builder.JavaBuilder}
133
	 */
134
	public IncrementalApiBuilder(ApiAnalysisBuilder builder) {
135
		this.builder = builder;
136
		this.state = null;
137
	}
138
	
139
	/**
140
	 * Incrementally builds using the {@link org.eclipse.pde.api.tools.internal.provisional.builder.IApiAnalyzer}
141
	 * from the given {@link ApiAnalysisBuilder}
142
	 * 
143
	 * @param baseline
144
	 * @param deltas
145
	 * @param monitor
146
	 * @throws CoreException
147
	 */
148
	public void build(IApiBaseline baseline, IResourceDelta[] deltas, IProgressMonitor monitor) throws CoreException {
149
		this.project = this.builder.getProject();
150
		SubMonitor localmonitor = SubMonitor.convert(monitor, NLS.bind("API analysis: Incrementally building... {0}", this.project), 10);
151
		try {
152
			this.state = (State)JavaModelManager.getJavaModelManager().getLastBuiltState(this.project, localmonitor.newChild(1));
153
			if(this.state == null) {
154
				this.builder.buildAll(baseline, localmonitor);
155
			}
156
			this.builder.clearLastState();
157
			//start incremental preparing
158
			build(this.state, baseline, localmonitor.newChild(1));
159
		}
160
		finally {
161
			if(!localmonitor.isCanceled()) {
162
				localmonitor.done();
163
			}
164
			this.changedtypes.clear();
165
		}
166
	}
167
	
168
	/**
169
	 * Collects the complete set of affected source files from the current project context based on the current JDT build state.
170
	 * 
171
	 * @param state
172
	 */
173
	private void collectAffectedSourceFiles(State state, Set typesToCheck) {
174
		// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
175
		char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(this.packages);
176
		// if a well known qualified name was found then we can skip over these
177
		if (internedQualifiedNames.length < this.packages.elementSize) {
178
			internedQualifiedNames = null;
179
		}
180
		char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(this.typenames, true);
181
		// if a well known name was found then we can skip over these
182
		if (internedSimpleNames.length < this.typenames.elementSize) {
183
			internedSimpleNames = null;
184
		}
185
		Object[] keyTable = state.getReferences().keyTable;
186
		Object[] valueTable = state.getReferences().valueTable;
187
		next : for (int i = 0, l = valueTable.length; i < l; i++) {
188
			String typeLocator = (String) keyTable[i];
189
			if (typeLocator != null) {
190
				ReferenceCollection refs = (ReferenceCollection) valueTable[i];
191
				if (refs.includes(internedQualifiedNames, internedSimpleNames, null)) {
192
					IFile file = this.project.getFile(typeLocator);
193
					if (file == null) {
194
						continue next;
195
					}
196
					if (ApiAnalysisBuilder.DEBUG) {
197
						System.out.println("  adding affected source file " + typeLocator); //$NON-NLS-1$
198
					}
199
					typesToCheck.add(file);
200
				}
201
			}
202
		}
203
	}
204
	
205
	/**
206
	 * Finds affected source files for a resource that has changed that either contains class files or is itself a class file
207
	 * @param binaryDelta
208
	 */
209
	private void findAffectedSourceFiles(IResourceDelta binaryDelta) {
210
		IResource resource = binaryDelta.getResource();
211
		if(resource.getType() == IResource.FILE) {
212
			if (Util.isClassFile(resource.getName())) {
213
				switch (binaryDelta.getKind()) {
214
					case IResourceDelta.REMOVED :
215
						//fAddedRemovedDeltas.add(binaryDelta);
216
						//$FALL-THROUGH$
217
					case IResourceDelta.ADDED : {
218
						IPath typePath = resolveJavaPathFromResource(resource);
219
						if(typePath == null) {
220
							return;
221
						}
222
						if (ApiAnalysisBuilder.DEBUG) {
223
							System.out.println("Found added/removed class file " + typePath); //$NON-NLS-1$
224
						}
225
						addDependentsOf(typePath);
226
						return;
227
					}
228
					case IResourceDelta.CHANGED : {
229
						if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) {
230
							return; // skip it since it really isn't changed
231
						}
232
						IPath typePath = resolveJavaPathFromResource(resource);
233
						if(typePath == null) {
234
							return;
235
						}
236
						if (ApiAnalysisBuilder.DEBUG) {
237
							System.out.println("Found changed class file " + typePath); //$NON-NLS-1$
238
						}
239
						addDependentsOf(typePath);
240
					}
241
				}
242
				return;
243
			}
244
		}
245
	}
246
	
247
	/**
248
	 * Adds a type to search for dependents of in considered projects for an incremental build
249
	 * 
250
	 * @param path
251
	 */
252
	void addDependentsOf(IPath path) {
253
		// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
254
		path = path.setDevice(null);
255
		String packageName = path.removeLastSegments(1).toString();
256
		String typeName = path.lastSegment();
257
		int memberIndex = typeName.indexOf('$');
258
		if (memberIndex > 0) {
259
			typeName = typeName.substring(0, memberIndex);
260
		}
261
		if (this.typenames.add(typeName) && this.packages.add(packageName) && ApiAnalysisBuilder.DEBUG) {
262
			System.out.println("  will look for dependents of " + typeName + " in " + packageName); //$NON-NLS-1$ //$NON-NLS-2$
263
		}
264
	}
265
	
266
	/**
267
	 * Builds an API delta using the default profile (from the workspace settings and the current
268
	 * workspace profile
269
	 * @param state
270
	 * @param monitor
271
	 */
272
	private void build(final State state, IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
273
		IApiBaseline wsprofile = null;
274
		try {
275
			int typesToCheckSize = this.changedtypes.size();
276
			SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 2 + (typesToCheckSize != 0 ? 3 : 0));
277
			localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_finding_affected_source_files, this.project.getName()));
278
			this.builder.updateMonitor(localMonitor, 0);
279
			collectAffectedSourceFiles(state, this.changedtypes);
280
			this.builder.updateMonitor(localMonitor, 1);
281
			if (typesToCheckSize != 0) {
282
				IPluginModelBase currentModel = this.builder.getCurrentModel();
283
				if (currentModel != null) {
284
					wsprofile = this.builder.getWorkspaceProfile();
285
					if (wsprofile == null) {
286
						if (ApiAnalysisBuilder.DEBUG) {
287
							System.err.println("Could not retrieve a workspace profile"); //$NON-NLS-1$
288
						}
289
						return;
290
					}
291
					String id = currentModel.getBundleDescription().getSymbolicName();
292
					IApiComponent apiComponent = wsprofile.getApiComponent(id);
293
					if(apiComponent == null) {
294
						return;
295
					}
296
					List tnames = new ArrayList(typesToCheckSize),
297
						 cnames = new ArrayList(typesToCheckSize);
298
					collectAllQualifiedNames(this.changedtypes, tnames, cnames, localMonitor.newChild(1));
299
					this.builder.updateMonitor(localMonitor, 1);
300
					this.builder.getAnalyzer().analyzeComponent(null, 
301
							null, 
302
							null, 
303
							baseline, 
304
							apiComponent, 
305
							(String[])tnames.toArray(new String[tnames.size()]), 
306
							(String[])cnames.toArray(new String[cnames.size()]), 
307
							localMonitor.newChild(1));
308
					this.builder.updateMonitor(localMonitor, 1);
309
					this.builder.createMarkers();
310
					this.builder.updateMonitor(localMonitor, 1);
311
				}
312
			}
313
		}
314
		finally {
315
			if(wsprofile != null) {
316
				wsprofile.close();
317
			}
318
			if(monitor != null) {
319
				monitor.done();
320
			}
321
		}
322
	}
323
	
324
	/**
325
	 * Returns an array of type names, and cleans up markers for the specified resource
326
	 * @param alltypes the listing of {@link IFile}s to get qualified names from
327
	 * @param changedtypes the listing of {@link IFile}s that have actually changed (from the {@link IResourceDelta}
328
	 * @param tnames the list to collect all type names into (including inner member names)
329
	 * @param cnames the list to collect the changed type names into
330
	 * @param monitor
331
	 */
332
	private void collectAllQualifiedNames(final HashSet alltypes, List tnames, List cnames, final IProgressMonitor monitor) {
333
		IType[] types = null;
334
		IFile file = null;
335
		for (Iterator iterator = alltypes.iterator(); iterator.hasNext(); ) {
336
			file = (IFile) iterator.next();
337
			ICompilationUnit unit = (ICompilationUnit) JavaCore.create(file);
338
			if(!unit.exists()) {
339
				continue;
340
			}
341
			IType type = unit.findPrimaryType();
342
			if(type == null) {
343
				continue;
344
			}
345
			this.builder.updateMonitor(monitor, 0);
346
			this.builder.cleanupUnsupportedTagMarkers(file);
347
			this.builder.updateMonitor(monitor, 0);
348
			this.builder.cleanupCompatibilityMarkers(file);
349
			this.builder.updateMonitor(monitor, 0);
350
			cnames.add(type.getFullyQualifiedName());
351
			try {
352
				this.builder.cleanupUsageMarkers(file);
353
				this.builder.updateMonitor(monitor, 0);
354
				types = unit.getAllTypes();
355
				String tname = null;
356
				for (int i = 0; i < types.length; i++) {
357
					IType type2 = types[i];
358
					if (type2.isMember()) {
359
						tname = type2.getFullyQualifiedName('$');
360
					} else {
361
						tname = type2.getFullyQualifiedName();
362
					}
363
					tnames.add(tname);
364
				}
365
			} catch (JavaModelException e) {
366
				ApiPlugin.log(e.getStatus());
367
			}
368
			this.builder.updateMonitor(monitor, 0);
369
		}
370
		// inject removed types inside changed type names so that we can properly detect type removal
371
		for (Iterator iterator = this.addremovedeltas.iterator(); iterator.hasNext(); ) {
372
			IResourceDelta delta = (IResourceDelta) iterator.next();
373
			if (delta.getKind() != IResourceDelta.REMOVED) continue;
374
			IResource resource = delta.getResource();
375
			IPath typePath = resolveJavaPathFromResource(resource);
376
			if(typePath == null) {
377
				continue;
378
			}
379
			// record removed type names (package + type)
380
			StringBuffer buffer = new StringBuffer();
381
			String[] segments = typePath.segments();
382
			for (int i = 0, max = segments.length; i < max; i++) {
383
				if (i > 0) {
384
					buffer.append('.');
385
				}
386
				buffer.append(segments[i]);
387
			}
388
			cnames.add(String.valueOf(buffer));
389
		}
390
		// clean up markers on added deltas
391
		if (!this.addremovedeltas.isEmpty()) {
392
			IResource manifestFile = Util.getManifestFile(this.project);
393
			if (manifestFile != null) {
394
				try {
395
					IMarker[] markers = manifestFile.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
396
					for (int i = 0, max = markers.length; i < max; i++) {
397
						IMarker marker = markers[i];
398
						String typeName = marker.getAttribute(IApiMarkerConstants.MARKER_ATTR_PROBLEM_TYPE_NAME, null);
399
						if (typeName != null) {
400
							for (Iterator iterator = this.addremovedeltas.iterator(); iterator.hasNext(); ) {
401
								IResourceDelta delta = (IResourceDelta) iterator.next();
402
								if (delta.getKind() != IResourceDelta.ADDED) {
403
									continue;
404
								}
405
								ICompilationUnit unit = (ICompilationUnit) JavaCore.create(delta.getResource());
406
								if(!unit.exists()) {
407
									continue;
408
								}
409
								IType type = unit.findPrimaryType();
410
								if(type == null) {
411
									continue;
412
								}
413
								if (typeName.equals(type.getFullyQualifiedName())) {
414
									marker.delete();
415
									return;
416
								} else {
417
									// check secondary types
418
									try {
419
										types = unit.getAllTypes();
420
										for (int j = 0; j < types.length; j++) {
421
											IType type2 = types[i];
422
											String fullyQualifiedName = null;
423
											if (type2.isMember()) {
424
												fullyQualifiedName = type2.getFullyQualifiedName('$');
425
											} else {
426
												fullyQualifiedName = type2.getFullyQualifiedName();
427
											}
428
											if (typeName.equals(fullyQualifiedName)) {
429
												marker.delete();
430
												return;
431
											}
432
										}
433
									} catch (JavaModelException e) {
434
										ApiPlugin.log(e.getStatus());
435
									}
436
								}
437
							}
438
						}
439
					}
440
				} catch (CoreException e) {
441
					ApiPlugin.log(e.getStatus());
442
				}
443
			}
444
		}
445
		IResource resource = this.project.findMember(ApiAnalysisBuilder.MANIFEST_PATH);
446
		if (resource != null) {
447
			try {
448
				IMarker[] markers = resource.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
449
				loop: for (int i = 0, max = markers.length; i < max; i++) {
450
					IMarker marker = markers[i];
451
					String typeNameFromMarker = Util.getTypeNameFromMarker(marker);
452
					for (Iterator iterator = tnames.iterator(); iterator.hasNext(); ) {
453
						String typeName = (String) iterator.next();
454
						if (typeName.equals(typeNameFromMarker)) {
455
							marker.delete();
456
							continue loop;
457
						}
458
					}
459
				}
460
				markers = resource.findMarkers(IApiMarkerConstants.SINCE_TAGS_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
461
				loop: for (int i = 0, max = markers.length; i < max; i++) {
462
					IMarker marker = markers[i];
463
					String typeNameFromMarker = Util.getTypeNameFromMarker(marker);
464
					for (Iterator iterator = tnames.iterator(); iterator.hasNext(); ) {
465
						String typeName = (String) iterator.next();
466
						if (typeName.equals(typeNameFromMarker)) {
467
							marker.delete();
468
							continue loop;
469
						}
470
					}
471
				}
472
			} catch (CoreException e) {
473
				ApiPlugin.log(e);
474
			}
475
		}
476
	}
477
	
478
	/**
479
	 * Resolves the java path from the given resource
480
	 * @param resource
481
	 * @return the resolved path or <code>null</code> if the resource is not part of the java model
482
	 */
483
	IPath resolveJavaPathFromResource(IResource resource) {
484
		IJavaElement element = JavaCore.create(resource);
485
		if(element != null) {
486
			switch(element.getElementType()) {
487
				case IJavaElement.CLASS_FILE: {
488
					org.eclipse.jdt.core.IClassFile classfile = (org.eclipse.jdt.core.IClassFile) element;
489
					IType type = classfile.getType();
490
					HashSet paths = this.builder.getProjectOutputPaths(resource.getProject());
491
					if(paths == null) {
492
						return null;
493
					}
494
					IPath prefix = null;
495
					for(Iterator iter = paths.iterator(); iter.hasNext();) {
496
						prefix = (IPath) iter.next();
497
						if(prefix.isPrefixOf(type.getPath())) {
498
							return type.getPath().removeFirstSegments(prefix.segmentCount()).removeFileExtension();
499
						}
500
					}
501
					break;
502
				}
503
			}
504
		}
505
		return null;
506
	}
507
}

Return to bug 233643