### Eclipse Workspace Patch 1.0 #P org.eclipse.pde.api.tools Index: src/org/eclipse/pde/api/tools/internal/ProjectApiDescription.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ProjectApiDescription.java,v retrieving revision 1.19 diff -u -r1.19 ProjectApiDescription.java --- src/org/eclipse/pde/api/tools/internal/ProjectApiDescription.java 21 May 2008 23:40:22 -0000 1.19 +++ src/org/eclipse/pde/api/tools/internal/ProjectApiDescription.java 23 May 2008 20:08:56 -0000 @@ -11,6 +11,7 @@ package org.eclipse.pde.api.tools.internal; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -223,7 +224,9 @@ long stamp = resource.getModificationStamp(); if (stamp != fTimeStamp) { modified(); + Set prevMementos = collectChildrenMementos(); children.clear(); + int previousRestrictions = restrictions; restrictions = RestrictionModifiers.NO_RESTRICTIONS; fTimeStamp = resource.getModificationStamp(); try { @@ -232,6 +235,12 @@ } catch (CoreException e) { ApiPlugin.log(e.getStatus()); } + descriptionChanged = previousRestrictions != restrictions; + // check if any children restrictions changed + if (!descriptionChanged) { + Set currMementos = collectChildrenMementos(); + descriptionChanged = !currMementos.equals(prevMementos); + } } } else { // element has been removed @@ -248,6 +257,29 @@ return this; } + /** + * Returns a set of restriction mementos for all the children of this type node. + * + * @return restriction mementos for all the children of this type node + */ + private Set collectChildrenMementos() { + if (children.size() == 0) { + return Collections.EMPTY_SET; + } + final Set mementos = new HashSet(children.size()*2); + visitChildren( + new ApiDescriptionVisitor() { + public boolean visitElement(IElementDescriptor element, IApiAnnotations description) { + if (description.getRestrictions() != RestrictionModifiers.NO_RESTRICTIONS) { + mementos.add(new RestrictionMemento(element, description.getRestrictions())); + } + return true; + } + }, + children); + return mementos; + } + /* (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.ApiDescription.ManifestNode#persistXML(org.w3c.dom.Document, org.w3c.dom.Element, java.lang.String) */ @@ -278,6 +310,40 @@ } /** + * Used to test if a node's restrictions have changed + */ + class RestrictionMemento { + private IElementDescriptor fTheElement; + private int fTheRestrictions; + /** + * Constructs a new node memento for the given element and restrictions. + * + * @param element + * @param restrictions + */ + public RestrictionMemento(IElementDescriptor element, int restrictions) { + fTheElement = element; + fTheRestrictions = restrictions; + } + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj instanceof RestrictionMemento) { + RestrictionMemento memento = (RestrictionMemento) obj; + return memento.fTheElement.equals(fTheElement) && memento.fTheRestrictions == fTheRestrictions; + } + return false; + } + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return fTheElement.hashCode() + fTheRestrictions; + } + } + + /** * Constructs a new API description for the given Java project. * * @param component @@ -365,8 +431,16 @@ * @see org.eclipse.pde.api.tools.internal.ApiDescription#isInsertOnResolve(org.eclipse.pde.api.tools.internal.provisional.descriptors.IElementDescriptor) */ protected boolean isInsertOnResolve(IElementDescriptor elementDescriptor) { - return elementDescriptor.getElementType() != IElementDescriptor.T_METHOD || - elementDescriptor.getElementType() != IElementDescriptor.T_FIELD; + switch (elementDescriptor.getElementType()) { + case IElementDescriptor.T_METHOD: + case IElementDescriptor.T_FIELD: + return false; + case IElementDescriptor.T_REFERENCE_TYPE: + // no need to insert member types + return ((IReferenceTypeDescriptor) elementDescriptor).getEnclosingType() == null; + default: + return true; + } } /* (non-Javadoc) Index: src/org/eclipse/pde/api/tools/internal/ApiDescription.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescription.java,v retrieving revision 1.18 diff -u -r1.18 ApiDescription.java --- src/org/eclipse/pde/api/tools/internal/ApiDescription.java 13 May 2008 20:42:24 -0000 1.18 +++ src/org/eclipse/pde/api/tools/internal/ApiDescription.java 23 May 2008 20:08:56 -0000 @@ -74,6 +74,7 @@ class ManifestNode implements Comparable { protected IElementDescriptor element = null; protected int visibility, restrictions; + protected boolean descriptionChanged = false; protected ManifestNode parent = null; protected HashMap children = new HashMap(1); @@ -270,7 +271,7 @@ tmp = null; } } - IApiAnnotations desc = new ApiAnnotations(vis, node.restrictions); + IApiAnnotations desc = new ApiAnnotations(vis, node.restrictions, node.descriptionChanged); boolean visitChildren = visitor.visitElement(node.element, desc); if (visitChildren && !node.children.isEmpty()) { visitChildren(visitor, node.children); @@ -345,7 +346,7 @@ if (node.element.equals(element)) { res = node.restrictions; } - return new ApiAnnotations(vis, res); + return new ApiAnnotations(vis, res, node.descriptionChanged); } /** Index: src/org/eclipse/pde/api/tools/internal/ApiAnnotations.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiAnnotations.java,v retrieving revision 1.3 diff -u -r1.3 ApiAnnotations.java --- src/org/eclipse/pde/api/tools/internal/ApiAnnotations.java 7 Apr 2008 21:08:36 -0000 1.3 +++ src/org/eclipse/pde/api/tools/internal/ApiAnnotations.java 23 May 2008 20:08:56 -0000 @@ -22,6 +22,7 @@ public class ApiAnnotations implements IApiAnnotations { private int fVisibility, fRestrictions; + private boolean fHasChanged = false; /** * Constructs API annotations. @@ -29,9 +30,10 @@ * @param visibility the visibility of an element. See {@linkplain VisibilityModifiers} for visibility constants * @param restrictions the restrictions for an element. See {@linkplain RestrictionModifiers} for restriction kind constants */ - public ApiAnnotations(int visibility, int restrictions) { + public ApiAnnotations(int visibility, int restrictions, boolean hasChanged) { fVisibility = visibility; fRestrictions = restrictions; + fHasChanged = hasChanged; } /* (non-Javadoc) @@ -118,5 +120,12 @@ public int hashCode() { return fRestrictions + fVisibility; } + + /* (non-Javadoc) + * @see org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations#hasChanged() + */ + public boolean hasChanged() { + return fHasChanged; + } } Index: src/org/eclipse/pde/api/tools/internal/provisional/IApiAnnotations.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/provisional/IApiAnnotations.java,v retrieving revision 1.2 diff -u -r1.2 IApiAnnotations.java --- src/org/eclipse/pde/api/tools/internal/provisional/IApiAnnotations.java 21 Feb 2008 20:36:19 -0000 1.2 +++ src/org/eclipse/pde/api/tools/internal/provisional/IApiAnnotations.java 23 May 2008 20:08:57 -0000 @@ -33,4 +33,11 @@ */ public int getRestrictions(); + /** + * Returns whether this description has changed + * + * @return + */ + public boolean hasChanged(); + } Index: src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java,v retrieving revision 1.67 diff -u -r1.67 ApiAnalysisBuilder.java --- src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java 22 May 2008 21:31:52 -0000 1.67 +++ src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java 23 May 2008 20:08:57 -0000 @@ -64,7 +64,10 @@ import org.eclipse.pde.api.tools.internal.IApiCoreConstants; import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory; import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; +import org.eclipse.pde.api.tools.internal.provisional.Factory; +import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations; import org.eclipse.pde.api.tools.internal.provisional.IApiComponent; +import org.eclipse.pde.api.tools.internal.provisional.IApiDescription; import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants; import org.eclipse.pde.api.tools.internal.provisional.IApiProfile; import org.eclipse.pde.api.tools.internal.provisional.builder.IApiAnalyzer; @@ -165,6 +168,11 @@ private IProject fCurrentProject = null; /** + * Corresponding API component being analyzed + */ + private IApiComponent fCurrentApiComponent = null; + + /** * The API analyzer for this builder */ private IApiAnalyzer fAnalyzer = null; @@ -272,6 +280,17 @@ if (memberIndex > 0) { typeName = typeName.substring(0, memberIndex); } + if (fCurrentApiComponent != null) { + try { + IApiDescription description = fCurrentApiComponent.getApiDescription(); + IApiAnnotations annotations = description.resolveAnnotations(Factory.packageDescriptor(packageName.replace('/', '.')).getType(typeName)); + if (annotations != null && !annotations.hasChanged()) { + return; + } + } catch (CoreException e) { + ApiPlugin.log(e.getStatus()); + } + } if (fTypes.add(typeName) && fPackages.add(packageName) && DEBUG) { System.out.println(" will look for dependents of " + typeName + " in " + packageName); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -283,6 +302,7 @@ protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { fCurrentProject = getProject(); fAnalyzer = getAnalyzer(); + fCurrentApiComponent = null; if (fCurrentProject == null || !fCurrentProject.isAccessible() || !fCurrentProject.hasNature(ApiPlugin.NATURE_ID) || hasBeenBuilt(fCurrentProject)) { return new IProject[0]; @@ -291,8 +311,23 @@ System.out.println("\nStarting build of " + fCurrentProject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$ } updateMonitor(monitor, 0); - SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_builder, 2); + SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_builder, 3); IProject[] projects = getRequiredProjects(true); + localMonitor.subTask(BuilderMessages.building_workspace_profile); + IPluginModelBase currentModel = getCurrentModel(); + IApiProfile wsprofile = null; + if (currentModel != null) { + wsprofile = getWorkspaceProfile(); + if (wsprofile != null) { + String id = currentModel.getBundleDescription().getSymbolicName(); + fCurrentApiComponent = wsprofile.getApiComponent(id); + } else { + if (DEBUG) { + System.err.println("Could not retrieve a workspace profile"); //$NON-NLS-1$ + } + } + } + updateMonitor(localMonitor, 1); try { switch(kind) { case FULL_BUILD : { @@ -342,6 +377,7 @@ } updateMonitor(monitor, 0); } finally { + fCurrentApiComponent = null; fTypes.clear(); fPackages.clear(); fTypesToCheck.clear(); @@ -356,6 +392,9 @@ saveBuiltState(fCurrentProject, fBuildState); fBuildState = null; } + if (wsprofile != null) { + wsprofile.close(); + } } if (DEBUG) { System.out.println("Finished build of " + fCurrentProject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$ @@ -368,41 +407,23 @@ * @param monitor */ private void buildAll(IProgressMonitor monitor) throws CoreException { - IApiProfile wsprofile = null; try { clearLastState(); fBuildState = new BuildState(); - SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 4); + SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 3); localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_initializing_analyzer, fCurrentProject.getName())); IApiProfile profile = ApiPlugin.getDefault().getApiProfileManager().getDefaultApiProfile(); cleanupMarkers(fCurrentProject); cleanupUnsupportedTagMarkers(fCurrentProject); - IPluginModelBase currentModel = getCurrentModel(); - if (currentModel != null) { - localMonitor.subTask(BuilderMessages.building_workspace_profile); - wsprofile = getWorkspaceProfile(); + // Compatibility checks + if(fCurrentApiComponent != null) { + fAnalyzer.analyzeComponent(fBuildState, null, profile, fCurrentApiComponent, null, null, localMonitor.newChild(1)); + updateMonitor(localMonitor, 1); + createMarkers(); updateMonitor(localMonitor, 1); - if (wsprofile == null) { - if (DEBUG) { - System.err.println("Could not retrieve a workspace profile"); //$NON-NLS-1$ - } - return; - } - String id = currentModel.getBundleDescription().getSymbolicName(); - // Compatibility checks - IApiComponent apiComponent = wsprofile.getApiComponent(id); - if(apiComponent != null) { - fAnalyzer.analyzeComponent(fBuildState, null, profile, apiComponent, null, null, localMonitor.newChild(1)); - updateMonitor(localMonitor, 1); - createMarkers(); - updateMonitor(localMonitor, 1); - } } } finally { - if(wsprofile != null) { - wsprofile.close(); - } if(monitor != null) { monitor.done(); } @@ -581,7 +602,6 @@ * @param monitor */ private void build(final State state, IProgressMonitor monitor) throws CoreException { - IApiProfile wsprofile = null; try { clearLastState(); // so if the build fails, a full build will be triggered SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 6); @@ -590,36 +610,21 @@ collectAffectedSourceFiles(state); updateMonitor(localMonitor, 1); if (fTypesToCheck.size() != 0) { - IPluginModelBase currentModel = getCurrentModel(); - if (currentModel != null) { - wsprofile = getWorkspaceProfile(); - if (wsprofile == null) { - if (DEBUG) { - System.err.println("Could not retrieve a workspace profile"); //$NON-NLS-1$ - } - return; - } - String id = currentModel.getBundleDescription().getSymbolicName(); - IApiComponent apiComponent = wsprofile.getApiComponent(id); - if(apiComponent == null) { - return; - } - List tnames = new ArrayList(fTypesToCheck.size()), - cnames = new ArrayList(fChangedTypes.size()); - collectAllQualifiedNames(fTypesToCheck, fChangedTypes, tnames, cnames, localMonitor.newChild(1)); - updateMonitor(localMonitor, 1); - IApiProfile profile = ApiPlugin.getDefault().getApiProfileManager().getDefaultApiProfile(); - fAnalyzer.analyzeComponent(fBuildState, null, profile, apiComponent, (String[])tnames.toArray(new String[tnames.size()]), (String[])cnames.toArray(new String[cnames.size()]), localMonitor.newChild(1)); - updateMonitor(localMonitor, 1); - createMarkers(); - updateMonitor(localMonitor, 1); + if(fCurrentApiComponent == null) { + return; } + List tnames = new ArrayList(fTypesToCheck.size()), + cnames = new ArrayList(fChangedTypes.size()); + collectAllQualifiedNames(fTypesToCheck, fChangedTypes, tnames, cnames, localMonitor.newChild(1)); + updateMonitor(localMonitor, 1); + IApiProfile profile = ApiPlugin.getDefault().getApiProfileManager().getDefaultApiProfile(); + fAnalyzer.analyzeComponent(fBuildState, null, profile, fCurrentApiComponent, (String[])tnames.toArray(new String[tnames.size()]), (String[])cnames.toArray(new String[cnames.size()]), localMonitor.newChild(1)); + updateMonitor(localMonitor, 1); + createMarkers(); + updateMonitor(localMonitor, 1); } } finally { - if(wsprofile != null) { - wsprofile.close(); - } if(monitor != null) { monitor.done(); }