### Eclipse Workspace Patch 1.0 #P org.eclipse.pde.api.tools.tests Index: src/org/eclipse/pde/api/tools/builder/tests/usage/UnusedApiProblemFilterTests.java =================================================================== RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/builder/tests/usage/UnusedApiProblemFilterTests.java,v retrieving revision 1.9 diff -u -r1.9 UnusedApiProblemFilterTests.java --- src/org/eclipse/pde/api/tools/builder/tests/usage/UnusedApiProblemFilterTests.java 20 Feb 2009 19:27:40 -0000 1.9 +++ src/org/eclipse/pde/api/tools/builder/tests/usage/UnusedApiProblemFilterTests.java 26 Feb 2009 20:37:20 -0000 @@ -161,11 +161,11 @@ } public void testUnusedFilter2F() { -// x2(false); + x2(false); } public void testUnusedFilter2I() { -// x2(true); + x2(true); } /** @@ -173,19 +173,22 @@ * problem filter * @param inc */ -// private void x2(boolean inc) { -// String testname = "test2"; -// String sourcename = "testUF2"; -// setExpectedProblemIds(getDefaultProblemIdSet(1)); -// setExpectedMessageArgs(new String[][] {{"testUF2.m1() has non-API return type internal"}}); -// deployReplacementTest( -// getBeforePath(testname), -// null, -// getFilterFilePath(testname), -// sourcename, -// inc); -// } + private void x2(boolean inc) { + String testname = "test2"; + String sourcename = "testUF2"; + setExpectedProblemIds(getDefaultProblemIdSet(1)); + setExpectedMessageArgs(new String[][] {{"testUF2.m1() has non-API return type internal"}}); + deployReplacementTest( + getBeforePath(testname), + null, + getFilterFilePath(testname), + sourcename, + inc); + } + /** + * + */ public void testUnusedFilter3F() { x3(false); } #P org.eclipse.pde.api.tools Index: src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java =================================================================== RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java,v retrieving revision 1.92 diff -u -r1.92 ApiAnalysisBuilder.java --- src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java 24 Feb 2009 21:26:13 -0000 1.92 +++ src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java 26 Feb 2009 20:37:21 -0000 @@ -19,11 +19,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarFile; @@ -87,12 +87,18 @@ * - removal of the .api_filter file */ class ResourceDeltaVisitor implements IResourceDeltaVisitor { - IProject[] projects; - public ResourceDeltaVisitor(IProject[] projects) { + + private boolean fRequireFullBuild = false; + private Set projects; + + /** + * Constructor + * @param projects + */ + public ResourceDeltaVisitor(Set/**/ projects) { this.projects = projects; } - private boolean fRequireFullBuild = false; - + /** * Returns whether a full build should be run. * @@ -125,16 +131,11 @@ IProject project = resource.getProject(); if (fCurrentProject.equals(project)) { if (delta.getKind() == IResourceDelta.ADDED) { - fAddedRemovedDeltas.add(delta); - } - fTypesToCheck.add(resource); - } else if (this.projects != null) { - loop: for (int i = 0, max = this.projects.length; i < max; i++) { - if (this.projects[i].equals(project)) { - fTypesToCheck.add(resource); - break loop; - } + fAddedDeltas.add(delta); } + fChangedTypesToCheck.add(resource); + } else if (this.projects.contains(project)) { + fChangedTypesToCheck.add(resource); } } else if (!fRequireFullBuild && IApiCoreConstants.API_FILTERS_XML_NAME.equals(fileName)) { switch(delta.getKind()) { @@ -202,13 +203,22 @@ private StringSet fPackages = new StringSet(3); /** - * The type that we want to check for API problems + * The changed types that we want to check for API problems + */ + private HashSet fChangedTypesToCheck = new HashSet(); + /** + * The computed dependent types we also want to check for API problems + */ + private HashSet fDependentTypesToCheck = new HashSet(); + /** + * The set of added deltas that come directly from the builder resource delta */ - private HashSet fTypesToCheck = new HashSet(); + private HashSet fAddedDeltas = new HashSet(4); + /** - * The set of added/removed deltas that come directly from the builder resource delta + * The set of removed deltas that come directly from the builder {@link IResourceDelta} */ - private HashSet fAddedRemovedDeltas = new HashSet(5); + private HashSet fRemovedDeltas = new HashSet(4); /** * Current build state @@ -331,11 +341,10 @@ if (fBuildState == null) { buildAll(baseline, localMonitor.newChild(1)); } else { - IProject[] reexportedProjects = null; + HashSet reexportedProjects = new HashSet(); String[] projectNames = this.fBuildState.getReexportedComponents(); int length = projectNames.length; if (length != 0) { - List allProjects = new ArrayList(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (int i = 0, max = projectNames.length; i < max; i++) { String projectName = projectNames[i]; @@ -343,14 +352,10 @@ if (project.isAccessible()) { // select only projects that don't exist in the reference baseline if (baseline != null && baseline.getApiComponent(projectName) == null) { - allProjects.add(project); + reexportedProjects.add(project); } } } - if (allProjects.size() != 0) { - reexportedProjects = new IProject[allProjects.size()]; - allProjects.toArray(reexportedProjects); - } } ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(reexportedProjects); for (int i = 0; i < deltas.length; i++) { @@ -392,8 +397,9 @@ } finally { fTypes.clear(); fPackages.clear(); - fTypesToCheck.clear(); - fAddedRemovedDeltas.clear(); + fChangedTypesToCheck.clear(); + fDependentTypesToCheck.clear(); + fAddedDeltas.clear(); fProjectToOutputLocations.clear(); updateMonitor(monitor, 0); fAnalyzer.dispose(); @@ -647,11 +653,11 @@ IApiBaseline wsprofile = null; try { clearLastState(); // so if the build fails, a full build will be triggered - int typesToCheckSize = fTypesToCheck.size(); - SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 2 + (typesToCheckSize != 0 ? 3 : 0)); + int typesToCheckSize = fChangedTypesToCheck.size(); + SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 3 + (typesToCheckSize != 0 ? 3 : 0)); localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_finding_affected_source_files, fCurrentProject.getName())); updateMonitor(localMonitor, 0); - collectAffectedSourceFiles(state, fTypesToCheck); + collectAffectedSourceFiles(state, fDependentTypesToCheck); updateMonitor(localMonitor, 1); if (typesToCheckSize != 0) { IPluginModelBase currentModel = getCurrentModel(); @@ -668,10 +674,34 @@ if(apiComponent == null) { return; } - List tnames = new ArrayList(typesToCheckSize), - cnames = new ArrayList(typesToCheckSize); - collectAllQualifiedNames(fTypesToCheck, tnames, cnames, localMonitor.newChild(1)); + HashSet tnames = new HashSet(typesToCheckSize), + cnames = new HashSet(typesToCheckSize); + //collect changed type qualified names + collectAllQualifiedNames(fChangedTypesToCheck, tnames, cnames, false, localMonitor.newChild(1)); + //collect dependent type qualified names + collectAllQualifiedNames(fDependentTypesToCheck, tnames, cnames, true, localMonitor.newChild(1)); + //make sure a type only appears in one place + fDependentTypesToCheck.removeAll(fChangedTypesToCheck); + IPath path = null; + for(Iterator iter = fRemovedDeltas.iterator(); iter.hasNext();) { + path = resolveJavaPathFromResource(((IResourceDelta) iter.next()).getResource()); + if(path != null) { + cnames.add(path.toString().replace('/', '.')); + } + } updateMonitor(localMonitor, 1); + //clean up markers on the manifest + IResource manifestFile = Util.getManifestFile(this.fCurrentProject); + if (manifestFile != null) { + try { + IMarker[] markers = manifestFile.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); + cleanMarkersWithTypeNames(markers, tnames); + cleanMarkersWithTypeNames(markers, getTypeNamesFromDeltas(this.fAddedDeltas, IResourceDelta.ADDED, true)); + cleanMarkersWithTypeNames(manifestFile.findMarkers(IApiMarkerConstants.SINCE_TAGS_PROBLEM_MARKER, false, IResource.DEPTH_ZERO), tnames); + } catch (CoreException e) { + ApiPlugin.log(e.getStatus()); + } + } fAnalyzer.analyzeComponent(fBuildState, null, null, @@ -704,146 +734,122 @@ * @param cnames the list to collect the changed type names into * @param monitor */ - private void collectAllQualifiedNames(final HashSet alltypes, List tnames, List cnames, final IProgressMonitor monitor) { + private void collectAllQualifiedNames(final HashSet alltypes, Set tnames, Set cnames, boolean dependenttypes, final IProgressMonitor monitor) { IType[] types = null; IFile file = null; for (Iterator iterator = alltypes.iterator(); iterator.hasNext(); ) { file = (IFile) iterator.next(); - ICompilationUnit unit = (ICompilationUnit) JavaCore.create(file); - if(!unit.exists()) { - continue; - } - IType type = unit.findPrimaryType(); + IType type = getTypeFromResource(file); if(type == null) { continue; } + if(dependenttypes) { + tnames.add(type.getFullyQualifiedName()); + } + else { + cnames.add(type.getFullyQualifiedName()); + } updateMonitor(monitor, 0); + cleanupUnsupportedTagMarkers(file); updateMonitor(monitor, 0); cleanupCompatibilityMarkers(file); updateMonitor(monitor, 0); - cnames.add(type.getFullyQualifiedName()); + cleanupUsageMarkers(file); + updateMonitor(monitor, 0); + try { - cleanupUsageMarkers(file); - updateMonitor(monitor, 0); - types = unit.getAllTypes(); - String tname = null; + types = type.getCompilationUnit().getAllTypes(); for (int i = 0; i < types.length; i++) { IType type2 = types[i]; if (type2.isMember()) { - tname = type2.getFullyQualifiedName('$'); + tnames.add(type2.getFullyQualifiedName('$')); } else { - tname = type2.getFullyQualifiedName(); + tnames.add(type2.getFullyQualifiedName()); } - tnames.add(tname); } } catch (JavaModelException e) { ApiPlugin.log(e.getStatus()); } updateMonitor(monitor, 0); } - // inject removed types inside changed type names so that we can properly detect type removal - for (Iterator iterator = this.fAddedRemovedDeltas.iterator(); iterator.hasNext(); ) { - IResourceDelta delta = (IResourceDelta) iterator.next(); - if (delta.getKind() != IResourceDelta.REMOVED) continue; - IResource resource = delta.getResource(); - IPath typePath = resolveJavaPathFromResource(resource); - if(typePath == null) { + } + + /** + * Returns the primary {@link IType} for the {@link IJavaElement} represented by the + * given {@link IResource}, or null if the element does not exist + * + * @param resource + * @return + */ + private IType getTypeFromResource(IResource resource) { + ICompilationUnit unit = (ICompilationUnit) JavaCore.create(resource); + if(unit.exists()) { + return unit.findPrimaryType(); + } + return null; + } + + /** + * Collects the fully qualified type names from the elements in the collection + * of {@link IResourceDelta}s. + * + * @param deltas the collection of deltas + * @param deltakind the kind of delta we should care about + * @param includesubstypes if we should include sub-types for a root type from the delta + * @return a list of fully qualified type names + * @throws CoreException + */ + private Set/**/ getTypeNamesFromDeltas(Collection/**/ deltas, int deltakind, boolean includesubstypes) throws CoreException { + HashSet names = new HashSet(deltas.size()); + IResourceDelta delta = null; + IType type = null; + IType[] types = null; + for (Iterator iterator = deltas.iterator(); iterator.hasNext();) { + delta = (IResourceDelta) iterator.next(); + if(delta.getKind() != deltakind) { continue; } - // record removed type names (package + type) - StringBuffer buffer = new StringBuffer(); - String[] segments = typePath.segments(); - for (int i = 0, max = segments.length; i < max; i++) { - if (i > 0) { - buffer.append('.'); - } - buffer.append(segments[i]); + type = getTypeFromResource(delta.getResource()); + if(type == null) { + continue; } - cnames.add(String.valueOf(buffer)); - } - // clean up markers on added deltas - if (!this.fAddedRemovedDeltas.isEmpty()) { - IResource manifestFile = Util.getManifestFile(this.fCurrentProject); - if (manifestFile != null) { - try { - IMarker[] markers = manifestFile.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE); - for (int i = 0, max = markers.length; i < max; i++) { - IMarker marker = markers[i]; - String typeName = marker.getAttribute(IApiMarkerConstants.MARKER_ATTR_PROBLEM_TYPE_NAME, null); - if (typeName != null) { - for (Iterator iterator = this.fAddedRemovedDeltas.iterator(); iterator.hasNext(); ) { - IResourceDelta delta = (IResourceDelta) iterator.next(); - if (delta.getKind() != IResourceDelta.ADDED) continue; - ICompilationUnit unit = (ICompilationUnit) JavaCore.create(delta.getResource()); - if(!unit.exists()) { - continue; - } - IType type = unit.findPrimaryType(); - if(type == null) { - continue; - } - if (typeName.equals(type.getFullyQualifiedName())) { - marker.delete(); - return; - } else { - // check secondary types - try { - types = unit.getAllTypes(); - for (int j = 0; j < types.length; j++) { - IType type2 = types[i]; - String fullyQualifiedName = null; - if (type2.isMember()) { - fullyQualifiedName = type2.getFullyQualifiedName('$'); - } else { - fullyQualifiedName = type2.getFullyQualifiedName(); - } - if (typeName.equals(fullyQualifiedName)) { - marker.delete(); - return; - } - } - } catch (JavaModelException e) { - ApiPlugin.log(e.getStatus()); - } - } - } - } + names.add(type.getFullyQualifiedName()); + if(includesubstypes) { + types = type.getCompilationUnit().getAllTypes(); + for (int j = 0; j < types.length; j++) { + IType type2 = types[j]; + if (type2.isMember()) { + names.add(type2.getFullyQualifiedName('$')); + } else { + names.add(type2.getFullyQualifiedName()); } - } catch (CoreException e) { - ApiPlugin.log(e.getStatus()); } } } - IResource resource = fCurrentProject.findMember(MANIFEST_PATH); - if (resource != null) { - try { - IMarker[] markers = resource.findMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); - loop: for (int i = 0, max = markers.length; i < max; i++) { - IMarker marker = markers[i]; - String typeNameFromMarker = Util.getTypeNameFromMarker(marker); - for (Iterator iterator = tnames.iterator(); iterator.hasNext(); ) { - String typeName = (String) iterator.next(); - if (typeName.equals(typeNameFromMarker)) { - marker.delete(); - continue loop; - } - } - } - markers = resource.findMarkers(IApiMarkerConstants.SINCE_TAGS_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); - loop: for (int i = 0, max = markers.length; i < max; i++) { - IMarker marker = markers[i]; - String typeNameFromMarker = Util.getTypeNameFromMarker(marker); - for (Iterator iterator = tnames.iterator(); iterator.hasNext(); ) { - String typeName = (String) iterator.next(); - if (typeName.equals(typeNameFromMarker)) { - marker.delete(); - continue loop; - } + return names; + } + + /** + * Deletes markers from the workspace that have a type name that is in the given listing + * of type names. + * + * @param markers the list of markers to examine + * @param typenames the list of type names to check for in the listing of markers + * @throws CoreException + */ + private void cleanMarkersWithTypeNames(IMarker[] markers, final Set/**/ typenames) throws CoreException { + if((markers != null && markers.length > 0) && (typenames != null && typenames.size() > 0)) { + loop: for (int i = 0, max = markers.length; i < max; i++) { + IMarker marker = markers[i]; + String typeNameFromMarker = Util.getTypeNameFromMarker(marker); + for (Iterator iterator = typenames.iterator(); iterator.hasNext(); ) { + String typeName = (String) iterator.next(); + if (typeName.equals(typeNameFromMarker)) { + marker.delete(); + continue loop; } } - } catch (CoreException e) { - ApiPlugin.log(e); } } } @@ -928,9 +934,9 @@ if (Util.isClassFile(resource.getName())) { switch (binaryDelta.getKind()) { case IResourceDelta.REMOVED : - fAddedRemovedDeltas.add(binaryDelta); + fRemovedDeltas.add(binaryDelta); //$FALL-THROUGH$ - case IResourceDelta.ADDED : { + case IResourceDelta.ADDED : { IPath typePath = resolveJavaPathFromResource(resource); if(typePath == null) { return;