### Eclipse Workspace Patch 1.0
#P org.eclipse.pde.api.tools
Index: src/org/eclipse/pde/api/tools/internal/builder/BaseApiAnalyzer.java
===================================================================
RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/BaseApiAnalyzer.java,v
retrieving revision 1.87
diff -u -r1.87 BaseApiAnalyzer.java
--- src/org/eclipse/pde/api/tools/internal/builder/BaseApiAnalyzer.java 4 Mar 2009 01:44:08 -0000 1.87
+++ src/org/eclipse/pde/api/tools/internal/builder/BaseApiAnalyzer.java 6 Mar 2009 19:52:48 -0000
@@ -301,7 +301,7 @@
}
}
if (changedTypes != null) {
- // check the ones not already checked as part of typenames check
+ // check the ones not already checked as part of type names check
for (int i = 0; i < changedTypes.length; i++) {
String typeName = changedTypes[i];
if (typeNamesSet == null || !typeNamesSet.remove(typeName)) {
@@ -1550,7 +1550,7 @@
Util.EMPTY_STRING);
}
}
- // analyse version of required components
+ // analyze version of required components
ReexportedBundleVersionInfo info = null;
if (problem != null) {
switch (problem.getKind()) {
@@ -1580,7 +1580,7 @@
}
break;
case IApiProblem.MINOR_VERSION_CHANGE :
- // check if there is a version change required due to reexported bundles
+ // check if there is a version change required due to re-exported bundles
info = checkBundleVersionsOfReexportedBundles(reference, component);
if (info != null) {
switch(info.kind) {
@@ -1602,7 +1602,7 @@
}
break;
case IApiProblem.MINOR_VERSION_CHANGE_NO_NEW_API :
- // check if there is a version change required due to reexported bundles
+ // check if there is a version change required due to re-exported bundles
info = checkBundleVersionsOfReexportedBundles(reference, component);
if (info != null) {
switch(info.kind) {
Index: src/org/eclipse/pde/api/tools/internal/builder/BuilderMessages.java
===================================================================
RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/BuilderMessages.java,v
retrieving revision 1.32
diff -u -r1.32 BuilderMessages.java
--- src/org/eclipse/pde/api/tools/internal/builder/BuilderMessages.java 7 Jan 2009 19:29:01 -0000 1.32
+++ src/org/eclipse/pde/api/tools/internal/builder/BuilderMessages.java 6 Mar 2009 19:52:48 -0000
@@ -20,6 +20,7 @@
public static String checking_api_usage;
public static String AbstractTypeLeakDetector_vis_type_has_no_api_description;
+ public static String ApiAnalysisBuilder_builder_for_project;
public static String ApiAnalysisBuilder_finding_affected_source_files;
public static String ApiAnalysisBuilder_initializing_analyzer;
public static String ApiProblemFactory_problem_message_not_found;
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.93
diff -u -r1.93 ApiAnalysisBuilder.java
--- src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java 5 Mar 2009 20:57:12 -0000 1.93
+++ src/org/eclipse/pde/api/tools/internal/builder/ApiAnalysisBuilder.java 6 Mar 2009 19:52:47 -0000
@@ -22,18 +22,14 @@
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;
-import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
-import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -41,7 +37,6 @@
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
@@ -49,16 +44,9 @@
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.internal.core.JavaModelManager;
-import org.eclipse.jdt.internal.core.builder.ReferenceCollection;
-import org.eclipse.jdt.internal.core.builder.State;
-import org.eclipse.jdt.internal.core.builder.StringSet;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.api.tools.internal.ApiDescriptionManager;
@@ -82,93 +70,30 @@
*/
public class ApiAnalysisBuilder extends IncrementalProjectBuilder {
/**
- * Visits a resource delta to determine if the changes have been made that might required a rebuild:
- * - modification to the manifest file
- * - removal of the .api_filter file
- */
- class ResourceDeltaVisitor implements IResourceDeltaVisitor {
- IProject[] projects;
- public ResourceDeltaVisitor(IProject[] projects) {
- this.projects = projects;
- }
- private boolean fRequireFullBuild = false;
-
- /**
- * Returns whether a full build should be run.
- *
- * @return whether a full build should be run
- */
- boolean shouldRunFullBuild() {
- return fRequireFullBuild;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
- */
- public boolean visit(IResourceDelta delta) throws CoreException {
- switch (delta.getResource().getType()) {
- case IResource.ROOT:
- case IResource.PROJECT:
- return !fRequireFullBuild;
- case IResource.FOLDER:
- return !fRequireFullBuild;
- case IResource.FILE:
- if (delta.getResource().getProjectRelativePath().equals(MANIFEST_PATH)) {
- fRequireFullBuild = true;
- break;
- }
- IResource resource = delta.getResource();
- String fileName = resource.getName();
- if (Util.isClassFile(fileName)) {
- findAffectedSourceFiles(delta);
- } else if (Util.isJavaFileName(fileName)) {
- 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;
- }
- }
- }
- } else if (!fRequireFullBuild && IApiCoreConstants.API_FILTERS_XML_NAME.equals(fileName)) {
- switch(delta.getKind()) {
- case IResourceDelta.REMOVED :
- case IResourceDelta.REPLACED :
- case IResourceDelta.CHANGED :
- case IResourceDelta.ADDED :
- fRequireFullBuild = true;
- }
- }
- }
- return false;
- }
- }
- /**
* Constant used for controlling tracing in the API tool builder
*/
- private static boolean DEBUG = Util.DEBUG;
+ static boolean DEBUG = Util.DEBUG;
/**
* Project relative path to the manifest file.
*/
- private static final IPath MANIFEST_PATH = new Path(JarFile.MANIFEST_NAME);
+ static final IPath MANIFEST_PATH = new Path(JarFile.MANIFEST_NAME);
/**
- * Internal flag used to determine what created the marker, as there is overlap for reference kinds and deltas
+ * Project relative path to the .api_filters file
*/
- public static final int REF_TYPE_FLAG = 0;
+ static final IPath FILTER_PATH = new Path(".settings").append(IApiCoreConstants.API_FILTERS_XML_NAME); //$NON-NLS-1$
+
+ /**
+ * Empty listing of projects to be returned by the builder if there is nothing to do
+ */
+ static final IProject[] NO_PROJECTS = new IProject[0];
/**
* Constant representing the name of the 'source' attribute on API tooling markers.
* Value is Api Tooling
*/
- public static final String SOURCE = "Api Tooling"; //$NON-NLS-1$
+ static final String SOURCE = "Api Tooling"; //$NON-NLS-1$
/**
* Method used for initializing tracing in the API tool builder
@@ -176,51 +101,33 @@
public static void setDebug(boolean debugValue) {
DEBUG = debugValue || Util.DEBUG;
}
+
/**
* The current project for which this builder was defined
*/
- private IProject fCurrentProject = null;
+ private IProject currentproject = null;
/**
* The API analyzer for this builder
*/
- private IApiAnalyzer fAnalyzer = null;
+ private IApiAnalyzer analyzer = null;
/**
* Maps prerequisite projects to their output location(s)
*/
- private HashMap fProjectToOutputLocations = new HashMap();
-
- /**
- * List of type names to lookup for each project context to find dependents of
- */
- private StringSet fTypes = new StringSet(3);
-
- /**
- * List of package names to qualify type names
- */
- private StringSet fPackages = new StringSet(3);
-
- /**
- * The type that we want to check for API problems
- */
- private HashSet fTypesToCheck = new HashSet();
- /**
- * The set of added/removed deltas that come directly from the builder resource delta
- */
- private HashSet fAddedRemovedDeltas = new HashSet(5);
+ private HashMap projecttooutputlocations = new HashMap();
/**
* Current build state
*/
- private BuildState fBuildState;
+ private BuildState buildstate = null;
/**
* Cleans up markers associated with API tooling on the given resource.
*
* @param resource
*/
- public static void cleanupMarkers(IResource resource) {
+ void cleanupMarkers(IResource resource) {
cleanupUsageMarkers(resource);
cleanupCompatibilityMarkers(resource);
cleanupUnsupportedTagMarkers(resource);
@@ -230,7 +137,7 @@
* Cleans up unsupported Javadoc tag markers on the specified resource
* @param resource
*/
- private static void cleanupUnsupportedTagMarkers(IResource resource) {
+ void cleanupUnsupportedTagMarkers(IResource resource) {
try {
if(DEBUG) {
System.out.println("cleaning unsupported tag problems"); //$NON-NLS-1$
@@ -245,7 +152,7 @@
* Cleans up only API compatibility markers on the given {@link IResource}
* @param resource the given resource
*/
- private static void cleanupCompatibilityMarkers(IResource resource) {
+ void cleanupCompatibilityMarkers(IResource resource) {
try {
if (resource != null && resource.isAccessible()) {
resource.deleteMarkers(IApiMarkerConstants.COMPATIBILITY_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
@@ -266,7 +173,7 @@
* cleans up only API usage markers from the given {@link IResource}
* @param resource
*/
- private static void cleanupUsageMarkers(IResource resource) {
+ void cleanupUsageMarkers(IResource resource) {
try {
if (resource != null && resource.isAccessible()) {
resource.deleteMarkers(IApiMarkerConstants.API_USAGE_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
@@ -276,39 +183,17 @@
}
}
- /**
- * Adds a type to search for dependents of in considered projects for an incremental build
- *
- * @param path
- */
- private void addDependentsOf(IPath path) {
- // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
- path = path.setDevice(null);
- String packageName = path.removeLastSegments(1).toString();
- String typeName = path.lastSegment();
- int memberIndex = typeName.indexOf('$');
- if (memberIndex > 0) {
- typeName = typeName.substring(0, memberIndex);
- }
- 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$
- }
- }
-
/* (non-Javadoc)
* @see org.eclipse.core.resources.IncrementalProjectBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
*/
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
- fCurrentProject = getProject();
- fAnalyzer = getAnalyzer();
- if (fCurrentProject == null ||
- !fCurrentProject.isAccessible() ||
- !fCurrentProject.hasNature(ApiPlugin.NATURE_ID) ||
- hasBeenBuilt(fCurrentProject)) {
- return new IProject[0];
+ this.currentproject = getProject();
+ this.analyzer = getAnalyzer();
+ if (!this.currentproject.isAccessible() || !this.currentproject.hasNature(ApiPlugin.NATURE_ID) || hasBeenBuilt(this.currentproject)) {
+ return NO_PROJECTS;
}
if (DEBUG) {
- System.out.println("\nStarting build of " + fCurrentProject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
+ System.out.println("\nStarting build of " + this.currentproject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
}
updateMonitor(monitor, 0);
SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_builder, 2);
@@ -326,63 +211,60 @@
case AUTO_BUILD :
case INCREMENTAL_BUILD : {
IResourceDelta[] deltas = getDeltas(projects);
- boolean shouldRunFullBuild = false;
- fBuildState = getLastBuiltState(fCurrentProject);
- if (fBuildState == null) {
+ if(deltas.length == 0) {
buildAll(baseline, localMonitor.newChild(1));
- } else {
- IProject[] reexportedProjects = null;
- 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];
- IProject project = root.getProject(projectName);
- if (project.isAccessible()) {
- // select only projects that don't exist in the reference baseline
- if (baseline != null && baseline.getApiComponent(projectName) == null) {
- allProjects.add(project);
- }
- }
- }
- if (allProjects.size() != 0) {
- reexportedProjects = new IProject[allProjects.size()];
- allProjects.toArray(reexportedProjects);
- }
+ break;
+ }
+ this.buildstate = getLastBuiltState(currentproject);
+ if (this.buildstate == null) {
+ buildAll(baseline, localMonitor.newChild(1));
+ break;
+ }
+ IResourceDelta manifest = null;
+ IResourceDelta filters = null;
+ for (int i = 0; i < deltas.length; i++) {
+ manifest = deltas[i].findMember(MANIFEST_PATH);
+ if(manifest != null) {
+ break;
+ }
+ filters = deltas[i].findMember(FILTER_PATH);
+ if(filters != null){
+ break;
}
- ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(reexportedProjects);
- for (int i = 0; i < deltas.length; i++) {
- deltas[i].accept(visitor);
- if (visitor.shouldRunFullBuild()) {
- shouldRunFullBuild = true;
- break;
- }
+ }
+ if (manifest != null || filters != null) {
+ if (DEBUG) {
+ System.out.println("Performing full build since MANIFEST.MF or .api_filters was modified"); //$NON-NLS-1$
}
- if (shouldRunFullBuild) {
- if (DEBUG) {
- System.out.println("Performing full build since MANIFEST.MF was modified"); //$NON-NLS-1$
- }
- buildAll(baseline, localMonitor.newChild(1));
- } else if (deltas.length == 0) {
- if (DEBUG) {
- System.out.println("Performing full build since deltas are missing after incremental request"); //$NON-NLS-1$
- }
- buildAll(baseline, localMonitor.newChild(1));
- } else {
- State state = (State)JavaModelManager.getJavaModelManager().getLastBuiltState(fCurrentProject, new NullProgressMonitor());
- if (state == null) {
- buildAll(baseline, localMonitor.newChild(1));
- } else {
- build(state, baseline, localMonitor.newChild(1));
+ buildAll(baseline, localMonitor.newChild(1));
+ }
+ IProject[] reexportedProjects = null;
+ String[] projectNames = this.buildstate.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];
+ IProject project = root.getProject(projectName);
+ if (project.isAccessible()) {
+ // select only projects that don't exist in the reference baseline
+ if (baseline != null && baseline.getApiComponent(projectName) == null) {
+ allProjects.add(project);
+ }
}
}
+ if (allProjects.size() != 0) {
+ reexportedProjects = new IProject[allProjects.size()];
+ allProjects.toArray(reexportedProjects);
+ }
+ }
+ IncrementalApiBuilder incbuilder = new IncrementalApiBuilder(this);
+ incbuilder.build(baseline, deltas, localMonitor.newChild(1));
}
break;
}
- }
- updateMonitor(monitor, 0);
+ updateMonitor(monitor, 0);
} catch(CoreException e) {
IStatus status = e.getStatus();
if (status == null || status.getCode() != ApiPlugin.REPORT_BASELINE_IS_DISPOSED) {
@@ -390,26 +272,22 @@
}
ApiPlugin.log(e);
} finally {
- fTypes.clear();
- fPackages.clear();
- fTypesToCheck.clear();
- fAddedRemovedDeltas.clear();
- fProjectToOutputLocations.clear();
+ this.projecttooutputlocations.clear();
updateMonitor(monitor, 0);
- fAnalyzer.dispose();
+ this.analyzer.dispose();
if(baseline != null) {
baseline.close();
}
if(monitor != null) {
monitor.done();
}
- if (fBuildState != null) {
- saveBuiltState(fCurrentProject, fBuildState);
- fBuildState = null;
+ if (this.buildstate != null) {
+ saveBuiltState(this.currentproject, this.buildstate);
+ this.buildstate = null;
}
}
if (DEBUG) {
- System.out.println("Finished build of " + fCurrentProject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
+ System.out.println("Finished build of " + currentproject.getName() + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$ //$NON-NLS-2$
}
return projects;
}
@@ -418,14 +296,14 @@
* Performs a full build for the project
* @param monitor
*/
- private void buildAll(IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
+ void buildAll(IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
IApiBaseline wsprofile = null;
try {
clearLastState();
- fBuildState = new BuildState();
+ this.buildstate = new BuildState();
SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 4);
- localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_initializing_analyzer, fCurrentProject.getName()));
- cleanupMarkers(fCurrentProject);
+ localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_initializing_analyzer, currentproject.getName()));
+ cleanupMarkers(this.currentproject);
IPluginModelBase currentModel = getCurrentModel();
if (currentModel != null) {
localMonitor.subTask(BuilderMessages.building_workspace_profile);
@@ -441,7 +319,7 @@
// Compatibility checks
IApiComponent apiComponent = wsprofile.getApiComponent(id);
if(apiComponent != null) {
- fAnalyzer.analyzeComponent(fBuildState, null, null, baseline, apiComponent, null, null, localMonitor.newChild(1));
+ this.analyzer.analyzeComponent(this.buildstate, null, null, baseline, apiComponent, null, null, localMonitor.newChild(1));
updateMonitor(localMonitor, 1);
createMarkers();
updateMonitor(localMonitor, 1);
@@ -465,13 +343,13 @@
*/
protected void createMarkers() {
try {
- fCurrentProject.deleteMarkers(IApiMarkerConstants.VERSION_NUMBERING_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
- fCurrentProject.deleteMarkers(IApiMarkerConstants.DEFAULT_API_BASELINE_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
- fCurrentProject.deleteMarkers(IApiMarkerConstants.API_COMPONENT_RESOLUTION_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
+ this.currentproject.deleteMarkers(IApiMarkerConstants.VERSION_NUMBERING_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE);
+ this.currentproject.deleteMarkers(IApiMarkerConstants.DEFAULT_API_BASELINE_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
+ this.currentproject.deleteMarkers(IApiMarkerConstants.API_COMPONENT_RESOLUTION_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
} catch (CoreException e) {
ApiPlugin.log(e);
}
- IApiProblem[] problems = fAnalyzer.getProblems();
+ IApiProblem[] problems = this.analyzer.getProblems();
String type = null;
for(int i = 0; i < problems.length; i++) {
int category = problems[i].getCategory();
@@ -555,7 +433,7 @@
IApiMarkerConstants.MARKER_ATTR_PROBLEM_ID},
new Object[] {
problem.getMessage(),
- new Integer(ApiPlugin.getDefault().getSeverityLevel(ApiProblemFactory.getProblemSeverityId(problem), this.fCurrentProject)),
+ new Integer(ApiPlugin.getDefault().getSeverityLevel(ApiProblemFactory.getProblemSeverityId(problem), this.currentproject)),
new Integer(line),
new Integer(problem.getCharStart()),
new Integer(problem.getCharEnd()),
@@ -597,7 +475,7 @@
if (resourcePath == null) {
return null;
}
- IResource resource = fCurrentProject.findMember(new Path(resourcePath));
+ IResource resource = currentproject.findMember(new Path(resourcePath));
if(resource == null) {
return null;
}
@@ -631,7 +509,7 @@
* @param ticks
* @throws OperationCanceledException
*/
- private void updateMonitor(IProgressMonitor monitor, int ticks) throws OperationCanceledException {
+ void updateMonitor(IProgressMonitor monitor, int ticks) throws OperationCanceledException {
if(monitor != null) {
monitor.worked(ticks);
if (monitor.isCanceled()) {
@@ -640,232 +518,21 @@
}
}
- /**
- * Builds an API delta using the default profile (from the workspace settings and the current
- * workspace profile
- * @param state
- * @param monitor
- */
- private void build(final State state, IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
- 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));
- localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_finding_affected_source_files, fCurrentProject.getName()));
- updateMonitor(localMonitor, 0);
- collectAffectedSourceFiles(state, fTypesToCheck);
- updateMonitor(localMonitor, 1);
- if (typesToCheckSize != 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(typesToCheckSize),
- cnames = new ArrayList(typesToCheckSize);
- collectAllQualifiedNames(fTypesToCheck, tnames, cnames, localMonitor.newChild(1));
- updateMonitor(localMonitor, 1);
- fAnalyzer.analyzeComponent(fBuildState,
- null,
- null,
- baseline,
- 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);
- }
- }
- }
- finally {
- if(wsprofile != null) {
- wsprofile.close();
- }
- if(monitor != null) {
- monitor.done();
- }
- }
- }
-
- /**
- * Returns an array of type names, and cleans up markers for the specified resource
- * @param alltypes the listing of {@link IFile}s to get qualified names from
- * @param changedtypes the listing of {@link IFile}s that have actually changed (from the {@link IResourceDelta}
- * @param tnames the list to collect all type names into (including inner member names)
- * @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) {
- 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();
- if(type == null) {
- continue;
- }
- updateMonitor(monitor, 0);
- cleanupUnsupportedTagMarkers(file);
- updateMonitor(monitor, 0);
- cleanupCompatibilityMarkers(file);
- updateMonitor(monitor, 0);
- cnames.add(type.getFullyQualifiedName());
- try {
- cleanupUsageMarkers(file);
- updateMonitor(monitor, 0);
- types = unit.getAllTypes();
- String tname = null;
- for (int i = 0; i < types.length; i++) {
- IType type2 = types[i];
- if (type2.isMember()) {
- tname = type2.getFullyQualifiedName('$');
- } else {
- tname = 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) {
- 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]);
- }
- 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());
- }
- }
- }
- }
- }
- } 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;
- }
- }
- }
- } catch (CoreException e) {
- ApiPlugin.log(e);
- }
- }
- }
-
/* (non-Javadoc)
* @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor)
*/
protected void clean(IProgressMonitor monitor) throws CoreException {
- fCurrentProject = getProject();
- SubMonitor localmonitor = SubMonitor.convert(monitor, MessageFormat.format(BuilderMessages.CleaningAPIDescription, new String[] {fCurrentProject.getName()}), 2);
+ this.currentproject = getProject();
+ SubMonitor localmonitor = SubMonitor.convert(monitor, MessageFormat.format(BuilderMessages.CleaningAPIDescription, new String[] {currentproject.getName()}), 2);
try {
// clean up all existing markers
- cleanupUsageMarkers(fCurrentProject);
- cleanupCompatibilityMarkers(fCurrentProject);
- cleanupUnsupportedTagMarkers(fCurrentProject);
- fCurrentProject.deleteMarkers(IApiMarkerConstants.UNUSED_FILTER_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+ cleanupUsageMarkers(this.currentproject);
+ cleanupCompatibilityMarkers(this.currentproject);
+ cleanupUnsupportedTagMarkers(this.currentproject);
+ this.currentproject.deleteMarkers(IApiMarkerConstants.UNUSED_FILTER_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
updateMonitor(localmonitor, 1);
//clean up the .api_settings
- cleanupApiDescription(fCurrentProject);
+ cleanupApiDescription(this.currentproject);
updateMonitor(localmonitor, 1);
}
finally {
@@ -882,93 +549,13 @@
ApiDescriptionManager.getDefault().clean(JavaCore.create(project), true, false);
}
}
- /**
- * Collects the complete set of affected source files from the current project context based on the current JDT build state.
- *
- * @param state
- */
- private void collectAffectedSourceFiles(State state, Set typesToCheck) {
- // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
- char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(fPackages);
- // if a well known qualified name was found then we can skip over these
- if (internedQualifiedNames.length < fPackages.elementSize) {
- internedQualifiedNames = null;
- }
- char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(fTypes, true);
- // if a well known name was found then we can skip over these
- if (internedSimpleNames.length < fTypes.elementSize) {
- internedSimpleNames = null;
- }
- Object[] keyTable = state.getReferences().keyTable;
- Object[] valueTable = state.getReferences().valueTable;
- next : for (int i = 0, l = valueTable.length; i < l; i++) {
- String typeLocator = (String) keyTable[i];
- if (typeLocator != null) {
- ReferenceCollection refs = (ReferenceCollection) valueTable[i];
- if (refs.includes(internedQualifiedNames, internedSimpleNames, null)) {
- IFile file = fCurrentProject.getFile(typeLocator);
- if (file == null) {
- continue next;
- }
- if (DEBUG) {
- System.out.println(" adding affected source file " + typeLocator); //$NON-NLS-1$
- }
- typesToCheck.add(file);
- }
- }
- }
- }
-
-
- /**
- * Finds affected source files for a resource that has changed that either contains class files or is itself a class file
- * @param binaryDelta
- */
- private void findAffectedSourceFiles(IResourceDelta binaryDelta) {
- IResource resource = binaryDelta.getResource();
- if(resource.getType() == IResource.FILE) {
- if (Util.isClassFile(resource.getName())) {
- switch (binaryDelta.getKind()) {
- case IResourceDelta.REMOVED :
- fAddedRemovedDeltas.add(binaryDelta);
- //$FALL-THROUGH$
- case IResourceDelta.ADDED : {
- IPath typePath = resolveJavaPathFromResource(resource);
- if(typePath == null) {
- return;
- }
- if (DEBUG) {
- System.out.println("Found added/removed class file " + typePath); //$NON-NLS-1$
- }
- addDependentsOf(typePath);
- return;
- }
- case IResourceDelta.CHANGED : {
- if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) {
- return; // skip it since it really isn't changed
- }
- IPath typePath = resolveJavaPathFromResource(resource);
- if(typePath == null) {
- return;
- }
- if (DEBUG) {
- System.out.println("Found changed class file " + typePath); //$NON-NLS-1$
- }
- addDependentsOf(typePath);
- }
- }
- return;
- }
- }
- }
-
/**
* @return the current {@link IPluginModelBase} based on the current project for this builder
*/
- private IPluginModelBase getCurrentModel() {
+ IPluginModelBase getCurrentModel() {
IPluginModelBase[] workspaceModels = PluginRegistry.getWorkspaceModels();
- IPath location = fCurrentProject.getLocation();
+ IPath location = this.currentproject.getLocation();
IPluginModelBase currentModel = null;
BundleDescription desc = null;
loop: for (int i = 0, max = workspaceModels.length; i < max; i++) {
@@ -994,10 +581,10 @@
*/
private IResourceDelta[] getDeltas(IProject[] projects) {
if(DEBUG) {
- System.out.println("Searching for deltas for build of project: "+fCurrentProject.getName()); //$NON-NLS-1$
+ System.out.println("Searching for deltas for build of project: "+this.currentproject.getName()); //$NON-NLS-1$
}
ArrayList deltas = new ArrayList();
- IResourceDelta delta = getDelta(fCurrentProject);
+ IResourceDelta delta = getDelta(this.currentproject);
if(delta != null) {
if (DEBUG) {
System.out.println("Found a delta: " + delta); //$NON-NLS-1$
@@ -1032,15 +619,15 @@
*/
private IProject[] getRequiredProjects(boolean includebinaries) throws CoreException {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
- if (fCurrentProject == null || workspaceRoot == null) {
+ if (this.currentproject == null || workspaceRoot == null) {
return new IProject[0];
}
ArrayList projects = new ArrayList();
try {
- IJavaProject javaProject = JavaCore.create(fCurrentProject);
+ IJavaProject javaProject = JavaCore.create(this.currentproject);
HashSet blocations = new HashSet();
blocations.add(javaProject.getOutputLocation());
- fProjectToOutputLocations.put(fCurrentProject, blocations);
+ projecttooutputlocations.put(this.currentproject, blocations);
IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
for (int i = 0, l = entries.length; i < l; i++) {
IClasspathEntry entry = entries[i];
@@ -1088,7 +675,7 @@
}
}
}
- fProjectToOutputLocations.put(p, bins);
+ this.projecttooutputlocations.put(p, bins);
}
}
}
@@ -1104,9 +691,19 @@
/**
* @return the workspace {@link IApiProfile}
*/
- private IApiBaseline getWorkspaceProfile() throws CoreException {
+ IApiBaseline getWorkspaceProfile() throws CoreException {
return ApiPlugin.getDefault().getApiBaselineManager().getWorkspaceBaseline();
}
+
+ /**
+ * Returns the output paths of the given project or null
if none have been computed
+ * @param project
+ * @return the output paths for the given project or null
+ */
+ HashSet getProjectOutputPaths(IProject project) {
+ return (HashSet) this.projecttooutputlocations.get(project);
+ }
+
/**
* Returns is the given classpath entry is optional or not
* @param entry
@@ -1121,39 +718,12 @@
}
return false;
}
-
- /**
- * Resolves the java path from the given resource
- * @param resource
- * @return the resolved path or null
if the resource is not part of the java model
- */
- private IPath resolveJavaPathFromResource(IResource resource) {
- IJavaElement element = JavaCore.create(resource);
- if(element != null) {
- switch(element.getElementType()) {
- case IJavaElement.CLASS_FILE: {
- org.eclipse.jdt.core.IClassFile classfile = (org.eclipse.jdt.core.IClassFile) element;
- IType type = classfile.getType();
- HashSet paths = (HashSet) fProjectToOutputLocations.get(resource.getProject());
- IPath prefix = null;
- for(Iterator iter = paths.iterator(); iter.hasNext();) {
- prefix = (IPath) iter.next();
- if(prefix.isPrefixOf(type.getPath())) {
- return type.getPath().removeFirstSegments(prefix.segmentCount()).removeFileExtension();
- }
- }
- break;
- }
- }
- }
- return null;
- }
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
- return "Builder for project: ["+fCurrentProject.getName()+"]"; //$NON-NLS-1$ //$NON-NLS-2$
+ return NLS.bind(BuilderMessages.ApiAnalysisBuilder_builder_for_project, this.currentproject.getName());
}
/**
@@ -1170,7 +740,7 @@
/**
* Reads the build state for the relevant project.
*/
- protected static BuildState readState(IProject project) throws CoreException {
+ static BuildState readState(IProject project) throws CoreException {
File file = getSerializationFile(project);
if (file != null && file.exists()) {
try {
@@ -1221,7 +791,7 @@
/**
* Returns the File to use for saving and restoring the last built state for the given project.
*/
- private static File getSerializationFile(IProject project) {
+ static File getSerializationFile(IProject project) {
if (!project.exists()) {
return null;
}
@@ -1235,7 +805,7 @@
* @param state
* @throws CoreException
*/
- private static void saveBuiltState(IProject project, BuildState state) throws CoreException {
+ static void saveBuiltState(IProject project, BuildState state) throws CoreException {
if (DEBUG) {
System.out.println("Saving build state for project: "+project.getName()); //$NON-NLS-1$
}
@@ -1281,7 +851,7 @@
* Clears the last build state by setting it to null
* @throws CoreException
*/
- private void clearLastState() throws CoreException {
- setLastBuiltState(fCurrentProject, null);
+ void clearLastState() throws CoreException {
+ setLastBuiltState(this.currentproject, null);
}
}
Index: src/org/eclipse/pde/api/tools/internal/builder/buildermessages.properties
===================================================================
RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/builder/buildermessages.properties,v
retrieving revision 1.44
diff -u -r1.44 buildermessages.properties
--- src/org/eclipse/pde/api/tools/internal/builder/buildermessages.properties 7 Jan 2009 19:29:01 -0000 1.44
+++ src/org/eclipse/pde/api/tools/internal/builder/buildermessages.properties 6 Mar 2009 19:52:48 -0000
@@ -13,6 +13,7 @@
building_workspace_profile=Building workspace API profile
checking_api_usage=Checking API use of ''{0}''
AbstractTypeLeakDetector_vis_type_has_no_api_description=Visible type {0} has no API description
+ApiAnalysisBuilder_builder_for_project=Builder for project: [{0}]
ApiAnalysisBuilder_finding_affected_source_files=Finding affected source in ''{0}''
ApiAnalysisBuilder_initializing_analyzer=Initializing analyzer for ''{0}''
ApiProblemFactory_problem_message_not_found=Message not found for id: {0}
Index: src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java
===================================================================
RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java,v
retrieving revision 1.6
diff -u -r1.6 ApiBaselineManager.java
--- src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java 26 Feb 2009 16:23:30 -0000 1.6
+++ src/org/eclipse/pde/api/tools/internal/ApiBaselineManager.java 6 Mar 2009 19:52:46 -0000
@@ -56,7 +56,6 @@
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.pde.api.tools.internal.builder.ApiAnalysisBuilder;
import org.eclipse.pde.api.tools.internal.model.ApiBaseline;
import org.eclipse.pde.api.tools.internal.model.ApiModelFactory;
import org.eclipse.pde.api.tools.internal.model.StubApiComponent;
@@ -880,7 +879,6 @@
IJavaProject jp = JavaCore.create(project);
if (jp.exists()) {
ApiDescriptionManager.getDefault().clean(jp, true, true);
- ApiAnalysisBuilder.cleanupMarkers(resource);
}
}
} catch (CoreException e) {
Index: src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java
===================================================================
RCS file: /cvsroot/eclipse/pde/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java,v
retrieving revision 1.19
diff -u -r1.19 ApiDescriptionManager.java
--- src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java 4 Mar 2009 00:24:40 -0000 1.19
+++ src/org/eclipse/pde/api/tools/internal/ApiDescriptionManager.java 6 Mar 2009 19:52:46 -0000
@@ -139,8 +139,8 @@
* Cleans the API description for the given project.
*
* @param project
- * @param whether to delete the file on disk
- * @param whether to remove the cached API description
+ * @param delete whether to delete the file on disk
+ * @param remove whether to remove the cached API description
*/
public synchronized void clean(IJavaProject project, boolean delete, boolean remove) {
ProjectApiDescription desc = null;
Index: src/org/eclipse/pde/api/tools/internal/builder/IncrementalApiBuilder.java
===================================================================
RCS file: src/org/eclipse/pde/api/tools/internal/builder/IncrementalApiBuilder.java
diff -N src/org/eclipse/pde/api/tools/internal/builder/IncrementalApiBuilder.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/pde/api/tools/internal/builder/IncrementalApiBuilder.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,507 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.api.tools.internal.builder;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.builder.ReferenceCollection;
+import org.eclipse.jdt.internal.core.builder.State;
+import org.eclipse.jdt.internal.core.builder.StringSet;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
+import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
+import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
+import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
+import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
+import org.eclipse.pde.api.tools.internal.util.Util;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+
+/**
+ * Used to incrementally build changed Java types
+ *
+ * @since 3.5
+ */
+public class IncrementalApiBuilder {
+
+ /**
+ * Visits a resource delta to determine if the changes have been made that might required a rebuild:
+ * - modification to the manifest file
+ * - removal of the .api_filter file
+ */
+ class ResourceDeltaVisitor implements IResourceDeltaVisitor {
+ IProject[] projects;
+ public ResourceDeltaVisitor(IProject[] projects) {
+ this.projects = projects;
+ }
+ private boolean fRequireFullBuild = false;
+
+ /**
+ * Returns whether a full build should be run.
+ *
+ * @return whether a full build should be run
+ */
+ boolean shouldRunFullBuild() {
+ return fRequireFullBuild;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
+ */
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ switch (delta.getResource().getType()) {
+ case IResource.ROOT:
+ case IResource.PROJECT:
+ return !fRequireFullBuild;
+ case IResource.FOLDER:
+ return !fRequireFullBuild;
+ case IResource.FILE:
+ IResource resource = delta.getResource();
+ String fileName = resource.getName();
+ if (Util.isClassFile(fileName)) {
+ findAffectedSourceFiles(delta);
+ } else if (Util.isJavaFileName(fileName)) {
+ IProject project = resource.getProject();
+ if (IncrementalApiBuilder.this.project.equals(project)) {
+ if (delta.getKind() == IResourceDelta.ADDED) {
+ IncrementalApiBuilder.this.addremovedeltas.add(delta);
+ }
+ IncrementalApiBuilder.this.changedtypes.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)) {
+ IncrementalApiBuilder.this.changedtypes.add(resource);
+ break loop;
+ }
+ }
+ }
+ } else if (!fRequireFullBuild && IApiCoreConstants.API_FILTERS_XML_NAME.equals(fileName)) {
+ switch(delta.getKind()) {
+ case IResourceDelta.REMOVED :
+ case IResourceDelta.REPLACED :
+ case IResourceDelta.CHANGED :
+ case IResourceDelta.ADDED :
+ fRequireFullBuild = true;
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ State state = null;
+ ApiAnalysisBuilder builder = null;
+ IProject project = null;
+ HashSet changedtypes = new HashSet(16);
+ HashSet addremovedeltas = new HashSet(8);
+ StringSet typenames = new StringSet(16);
+ StringSet packages = new StringSet(16);
+
+
+ /**
+ * Constructor
+ * @param project the current project context being built
+ * @param delta the {@link IResourceDelta} from the build framework
+ * @param buildstate the current build state from the {@link org.eclipse.jdt.internal.core.builder.JavaBuilder}
+ */
+ public IncrementalApiBuilder(ApiAnalysisBuilder builder) {
+ this.builder = builder;
+ this.state = null;
+ }
+
+ /**
+ * Incrementally builds using the {@link org.eclipse.pde.api.tools.internal.provisional.builder.IApiAnalyzer}
+ * from the given {@link ApiAnalysisBuilder}
+ *
+ * @param baseline
+ * @param deltas
+ * @param monitor
+ * @throws CoreException
+ */
+ public void build(IApiBaseline baseline, IResourceDelta[] deltas, IProgressMonitor monitor) throws CoreException {
+ this.project = this.builder.getProject();
+ SubMonitor localmonitor = SubMonitor.convert(monitor, NLS.bind("API analysis: Incrementally building... {0}", this.project), 10);
+ try {
+ this.state = (State)JavaModelManager.getJavaModelManager().getLastBuiltState(this.project, localmonitor.newChild(1));
+ if(this.state == null) {
+ this.builder.buildAll(baseline, localmonitor);
+ }
+ this.builder.clearLastState();
+ //start incremental preparing
+ build(this.state, baseline, localmonitor.newChild(1));
+ }
+ finally {
+ if(!localmonitor.isCanceled()) {
+ localmonitor.done();
+ }
+ this.changedtypes.clear();
+ }
+ }
+
+ /**
+ * Collects the complete set of affected source files from the current project context based on the current JDT build state.
+ *
+ * @param state
+ */
+ private void collectAffectedSourceFiles(State state, Set typesToCheck) {
+ // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
+ char[][][] internedQualifiedNames = ReferenceCollection.internQualifiedNames(this.packages);
+ // if a well known qualified name was found then we can skip over these
+ if (internedQualifiedNames.length < this.packages.elementSize) {
+ internedQualifiedNames = null;
+ }
+ char[][] internedSimpleNames = ReferenceCollection.internSimpleNames(this.typenames, true);
+ // if a well known name was found then we can skip over these
+ if (internedSimpleNames.length < this.typenames.elementSize) {
+ internedSimpleNames = null;
+ }
+ Object[] keyTable = state.getReferences().keyTable;
+ Object[] valueTable = state.getReferences().valueTable;
+ next : for (int i = 0, l = valueTable.length; i < l; i++) {
+ String typeLocator = (String) keyTable[i];
+ if (typeLocator != null) {
+ ReferenceCollection refs = (ReferenceCollection) valueTable[i];
+ if (refs.includes(internedQualifiedNames, internedSimpleNames, null)) {
+ IFile file = this.project.getFile(typeLocator);
+ if (file == null) {
+ continue next;
+ }
+ if (ApiAnalysisBuilder.DEBUG) {
+ System.out.println(" adding affected source file " + typeLocator); //$NON-NLS-1$
+ }
+ typesToCheck.add(file);
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds affected source files for a resource that has changed that either contains class files or is itself a class file
+ * @param binaryDelta
+ */
+ private void findAffectedSourceFiles(IResourceDelta binaryDelta) {
+ IResource resource = binaryDelta.getResource();
+ if(resource.getType() == IResource.FILE) {
+ if (Util.isClassFile(resource.getName())) {
+ switch (binaryDelta.getKind()) {
+ case IResourceDelta.REMOVED :
+ //fAddedRemovedDeltas.add(binaryDelta);
+ //$FALL-THROUGH$
+ case IResourceDelta.ADDED : {
+ IPath typePath = resolveJavaPathFromResource(resource);
+ if(typePath == null) {
+ return;
+ }
+ if (ApiAnalysisBuilder.DEBUG) {
+ System.out.println("Found added/removed class file " + typePath); //$NON-NLS-1$
+ }
+ addDependentsOf(typePath);
+ return;
+ }
+ case IResourceDelta.CHANGED : {
+ if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0) {
+ return; // skip it since it really isn't changed
+ }
+ IPath typePath = resolveJavaPathFromResource(resource);
+ if(typePath == null) {
+ return;
+ }
+ if (ApiAnalysisBuilder.DEBUG) {
+ System.out.println("Found changed class file " + typePath); //$NON-NLS-1$
+ }
+ addDependentsOf(typePath);
+ }
+ }
+ return;
+ }
+ }
+ }
+
+ /**
+ * Adds a type to search for dependents of in considered projects for an incremental build
+ *
+ * @param path
+ */
+ void addDependentsOf(IPath path) {
+ // the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
+ path = path.setDevice(null);
+ String packageName = path.removeLastSegments(1).toString();
+ String typeName = path.lastSegment();
+ int memberIndex = typeName.indexOf('$');
+ if (memberIndex > 0) {
+ typeName = typeName.substring(0, memberIndex);
+ }
+ if (this.typenames.add(typeName) && this.packages.add(packageName) && ApiAnalysisBuilder.DEBUG) {
+ System.out.println(" will look for dependents of " + typeName + " in " + packageName); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Builds an API delta using the default profile (from the workspace settings and the current
+ * workspace profile
+ * @param state
+ * @param monitor
+ */
+ private void build(final State state, IApiBaseline baseline, IProgressMonitor monitor) throws CoreException {
+ IApiBaseline wsprofile = null;
+ try {
+ int typesToCheckSize = this.changedtypes.size();
+ SubMonitor localMonitor = SubMonitor.convert(monitor, BuilderMessages.api_analysis_on_0, 2 + (typesToCheckSize != 0 ? 3 : 0));
+ localMonitor.subTask(NLS.bind(BuilderMessages.ApiAnalysisBuilder_finding_affected_source_files, this.project.getName()));
+ this.builder.updateMonitor(localMonitor, 0);
+ collectAffectedSourceFiles(state, this.changedtypes);
+ this.builder.updateMonitor(localMonitor, 1);
+ if (typesToCheckSize != 0) {
+ IPluginModelBase currentModel = this.builder.getCurrentModel();
+ if (currentModel != null) {
+ wsprofile = this.builder.getWorkspaceProfile();
+ if (wsprofile == null) {
+ if (ApiAnalysisBuilder.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(typesToCheckSize),
+ cnames = new ArrayList(typesToCheckSize);
+ collectAllQualifiedNames(this.changedtypes, tnames, cnames, localMonitor.newChild(1));
+ this.builder.updateMonitor(localMonitor, 1);
+ this.builder.getAnalyzer().analyzeComponent(null,
+ null,
+ null,
+ baseline,
+ apiComponent,
+ (String[])tnames.toArray(new String[tnames.size()]),
+ (String[])cnames.toArray(new String[cnames.size()]),
+ localMonitor.newChild(1));
+ this.builder.updateMonitor(localMonitor, 1);
+ this.builder.createMarkers();
+ this.builder.updateMonitor(localMonitor, 1);
+ }
+ }
+ }
+ finally {
+ if(wsprofile != null) {
+ wsprofile.close();
+ }
+ if(monitor != null) {
+ monitor.done();
+ }
+ }
+ }
+
+ /**
+ * Returns an array of type names, and cleans up markers for the specified resource
+ * @param alltypes the listing of {@link IFile}s to get qualified names from
+ * @param changedtypes the listing of {@link IFile}s that have actually changed (from the {@link IResourceDelta}
+ * @param tnames the list to collect all type names into (including inner member names)
+ * @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) {
+ 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();
+ if(type == null) {
+ continue;
+ }
+ this.builder.updateMonitor(monitor, 0);
+ this.builder.cleanupUnsupportedTagMarkers(file);
+ this.builder.updateMonitor(monitor, 0);
+ this.builder.cleanupCompatibilityMarkers(file);
+ this.builder.updateMonitor(monitor, 0);
+ cnames.add(type.getFullyQualifiedName());
+ try {
+ this.builder.cleanupUsageMarkers(file);
+ this.builder.updateMonitor(monitor, 0);
+ types = unit.getAllTypes();
+ String tname = null;
+ for (int i = 0; i < types.length; i++) {
+ IType type2 = types[i];
+ if (type2.isMember()) {
+ tname = type2.getFullyQualifiedName('$');
+ } else {
+ tname = type2.getFullyQualifiedName();
+ }
+ tnames.add(tname);
+ }
+ } catch (JavaModelException e) {
+ ApiPlugin.log(e.getStatus());
+ }
+ this.builder.updateMonitor(monitor, 0);
+ }
+ // inject removed types inside changed type names so that we can properly detect type removal
+ for (Iterator iterator = this.addremovedeltas.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) {
+ 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]);
+ }
+ cnames.add(String.valueOf(buffer));
+ }
+ // clean up markers on added deltas
+ if (!this.addremovedeltas.isEmpty()) {
+ IResource manifestFile = Util.getManifestFile(this.project);
+ 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.addremovedeltas.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());
+ }
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ ApiPlugin.log(e.getStatus());
+ }
+ }
+ }
+ IResource resource = this.project.findMember(ApiAnalysisBuilder.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;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ ApiPlugin.log(e);
+ }
+ }
+ }
+
+ /**
+ * Resolves the java path from the given resource
+ * @param resource
+ * @return the resolved path or null
if the resource is not part of the java model
+ */
+ IPath resolveJavaPathFromResource(IResource resource) {
+ IJavaElement element = JavaCore.create(resource);
+ if(element != null) {
+ switch(element.getElementType()) {
+ case IJavaElement.CLASS_FILE: {
+ org.eclipse.jdt.core.IClassFile classfile = (org.eclipse.jdt.core.IClassFile) element;
+ IType type = classfile.getType();
+ HashSet paths = this.builder.getProjectOutputPaths(resource.getProject());
+ if(paths == null) {
+ return null;
+ }
+ IPath prefix = null;
+ for(Iterator iter = paths.iterator(); iter.hasNext();) {
+ prefix = (IPath) iter.next();
+ if(prefix.isPrefixOf(type.getPath())) {
+ return type.getPath().removeFirstSegments(prefix.segmentCount()).removeFileExtension();
+ }
+ }
+ break;
+ }
+ }
+ }
+ return null;
+ }
+}