Bug 539990 - make problem marker creation incremental

The current error reporting first deletes all markers and recreates
them. This modifies the workspace's element tree and thereby invalidates
the cached delta in BuildManager even if no markers actually change.

This change introduces IncrementalErrorReporter which collects marker
attributes for reported problems and tries to find an existing marker
with equal attributes. If it finds one, the marker is kept and no
changes to the element tree are necessary.

Change-Id: I8135d04229d56b9c0e5ce3fbde6ed8e7df24d2fa
Signed-off-by: Julian Honnen <julian.honnen@vector.com>
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BuildErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BuildErrorReporter.java
index 6e4af4c..2413040 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BuildErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BuildErrorReporter.java
@@ -37,6 +37,7 @@
 import org.eclipse.pde.internal.build.IBuildPropertiesConstants;
 import org.eclipse.pde.internal.core.*;
 import org.eclipse.pde.internal.core.build.WorkspaceBuildModel;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.eclipse.pde.internal.core.ibundle.*;
 import org.eclipse.pde.internal.core.project.PDEProject;
 import org.eclipse.pde.internal.core.text.build.BuildEntry;
@@ -1105,14 +1106,12 @@
 				lineNum = getLineNumber(buildEntry, bp.fEntryToken);
 
 			if (lineNum > 0) {
-				IMarker marker = report(bp.fMessage, lineNum, bp.fFixId, bp.fEntryName, bp.fEntryToken, bp.fSeverity, bp.fCategory);
+				VirtualMarker marker = report(bp.fMessage, lineNum, bp.fFixId, bp.fEntryName, bp.fEntryToken,
+						bp.fSeverity, bp.fCategory);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,bp.fCompilerKey);
 				if (marker != null && bp.attributes != null) {
 					for (String attribute : bp.attributes.keySet()) {
-						try {
-							marker.setAttribute(attribute, bp.attributes.get(attribute));
-						} catch (CoreException e) {
-						}
+						marker.setAttribute(attribute, bp.attributes.get(attribute));
 					}
 				}
 			}
@@ -1205,14 +1204,11 @@
 	 * @param category
 	 * @return a new marker or <code>null</code>
 	 */
-	private IMarker report(String message, int line, int problemID, String buildEntry, String buildToken, int severity, String category) {
-		IMarker marker = report(message, line, severity, problemID, category);
+	private VirtualMarker report(String message, int line, int problemID, String buildEntry, String buildToken, int severity, String category) {
+		VirtualMarker marker = report(message, line, severity, problemID, category);
 		if (marker != null) {
-			try {
-				marker.setAttribute(PDEMarkerFactory.BK_BUILD_ENTRY, buildEntry);
-				marker.setAttribute(PDEMarkerFactory.BK_BUILD_TOKEN, buildToken);
-			} catch (CoreException e) {
-			}
+			marker.setAttribute(PDEMarkerFactory.BK_BUILD_ENTRY, buildEntry);
+			marker.setAttribute(PDEMarkerFactory.BK_BUILD_TOKEN, buildToken);
 		}
 		return marker;
 	}
@@ -1229,11 +1225,9 @@
 		}
 		return false;
 	}
-	protected void addMarkerAttribute(IMarker marker, String attr, String value) {
+
+	protected void addMarkerAttribute(VirtualMarker marker, String attr, String value) {
 		if (marker != null)
-			try {
-				marker.setAttribute(attr, value);
-			} catch (CoreException e) {
-			}
+			marker.setAttribute(attr, value);
 	}
 }
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java
index 02b2747..d0fa27d 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/BundleErrorReporter.java
@@ -30,6 +30,7 @@
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.core.plugin.*;
 import org.eclipse.pde.internal.core.*;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.eclipse.pde.internal.core.ibundle.*;
 import org.eclipse.pde.internal.core.project.PDEProject;
 import org.eclipse.pde.internal.core.search.PluginJavaSearchUtil;
@@ -48,8 +49,8 @@
 	}
 
 	@Override
-	public void validateContent(IProgressMonitor monitor) {
-		super.validateContent(monitor);
+	protected void validate(IProgressMonitor monitor) {
+		super.validate(monitor);
 		if (fHeaders == null || getErrorCount() > 0)
 			return;
 
@@ -130,7 +131,7 @@
 		if (moduleDescription == null) {
 			IHeader header = fHeaders.get(ICoreConstants.AUTOMATIC_MODULE_NAME.toLowerCase());
 			if (header == null) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_headerMissingAutoModule, ICoreConstants.AUTOMATIC_MODULE_NAME),  1, CompilerFlags.P_NO_AUTOMATIC_MODULE, PDEMarkerFactory.M_NO_AUTOMATIC_MODULE, PDEMarkerFactory.CAT_OTHER);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_headerMissingAutoModule, ICoreConstants.AUTOMATIC_MODULE_NAME),  1, CompilerFlags.P_NO_AUTOMATIC_MODULE, PDEMarkerFactory.M_NO_AUTOMATIC_MODULE, PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_NO_AUTOMATIC_MODULE);
 			}
 		}
@@ -195,7 +196,7 @@
 
 			// if we actually have packages to add
 			if (packages.toString().length() > 0) {
-				IMarker marker = report(PDECoreMessages.BundleErrorReporter_missingPackagesInProject, header == null ? 1 : header.getLineNumber() + 1, CompilerFlags.P_MISSING_EXPORT_PKGS, PDEMarkerFactory.M_MISSING_EXPORT_PKGS, PDEMarkerFactory.CAT_OTHER);
+				VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_missingPackagesInProject, header == null ? 1 : header.getLineNumber() + 1, CompilerFlags.P_MISSING_EXPORT_PKGS, PDEMarkerFactory.M_MISSING_EXPORT_PKGS, PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_MISSING_EXPORT_PKGS);
 				addMarkerAttribute(marker, "packages", packages.toString()); //$NON-NLS-1$
 			}
@@ -301,7 +302,7 @@
 					if ("true".equals(singletonAttr)) { //$NON-NLS-1$
 						if (isCheckDeprecated() && fOsgiR4) {
 							String message = PDECoreMessages.BundleErrorReporter_deprecated_attribute_singleton;
-							IMarker marker = report(message, getLine(header, ICoreConstants.SINGLETON_ATTRIBUTE + "="), //$NON-NLS-1$
+							VirtualMarker marker = report(message, getLine(header, ICoreConstants.SINGLETON_ATTRIBUTE + "="), //$NON-NLS-1$
 									CompilerFlags.P_DEPRECATED, PDEMarkerFactory.M_SINGLETON_DIR_NOT_SET, PDEMarkerFactory.CAT_DEPRECATION);
 							addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 							return;
@@ -323,7 +324,7 @@
 			if (singletonAttr != null) {
 				if (isCheckDeprecated()) {
 					String message = PDECoreMessages.BundleErrorReporter_deprecated_attribute_singleton;
-					IMarker marker = report(message, getLine(header, ICoreConstants.SINGLETON_ATTRIBUTE + "="), //$NON-NLS-1$
+					VirtualMarker marker = report(message, getLine(header, ICoreConstants.SINGLETON_ATTRIBUTE + "="), //$NON-NLS-1$
 							CompilerFlags.P_DEPRECATED, PDEMarkerFactory.M_SINGLETON_DIR_NOT_SET, PDEMarkerFactory.CAT_OTHER);
 					addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 				}
@@ -331,7 +332,7 @@
 		} else if (singletonDir != null) {
 			if (isCheckDeprecated()) {
 				String message = PDECoreMessages.BundleErrorReporter_unsupportedSingletonDirective;
-				IMarker marker = report(message, getLine(header, Constants.SINGLETON_DIRECTIVE + ":="), //$NON-NLS-1$
+				VirtualMarker marker = report(message, getLine(header, Constants.SINGLETON_DIRECTIVE + ":="), //$NON-NLS-1$
 						CompilerFlags.P_DEPRECATED, PDEMarkerFactory.M_SINGLETON_DIR_NOT_SUPPORTED, PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 
@@ -345,7 +346,7 @@
 		IHeader header = getHeader(Constants.FRAGMENT_HOST);
 		if (header == null) {
 			if (isCheckNoRequiredAttr() && PDEProject.getFragmentXml(fProject).exists()) {
-				IMarker marker = report(PDECoreMessages.BundleErrorReporter_HostNeeded, 1, CompilerFlags.P_NO_REQUIRED_ATT, PDEMarkerFactory.CAT_FATAL);
+				VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_HostNeeded, 1, CompilerFlags.P_NO_REQUIRED_ATT, PDEMarkerFactory.CAT_FATAL);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_NO_REQUIRED_ATT);
 			}
 			return;
@@ -353,7 +354,7 @@
 
 		if (header.getElements().length == 0) {
 			if (isCheckNoRequiredAttr()) {
-				IMarker marker = report(PDECoreMessages.BundleErrorReporter_HostNeeded, 1, CompilerFlags.P_NO_REQUIRED_ATT, PDEMarkerFactory.CAT_FATAL);
+				VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_HostNeeded, 1, CompilerFlags.P_NO_REQUIRED_ATT, PDEMarkerFactory.CAT_FATAL);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_NO_REQUIRED_ATT);
 			}
 			return;
@@ -372,7 +373,7 @@
 			if (elems.length > 0) {
 				if (!VersionUtil.validateVersionRange(elems[0].getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE)).isOK()) {
 					int line = getLine(header, header.getValue());
-					IMarker marker = report(UtilMessages.BundleErrorReporter_InvalidFormatInBundleVersion, line,CompilerFlags.ERROR, PDEMarkerFactory.CAT_FATAL);
+					VirtualMarker marker = report(UtilMessages.BundleErrorReporter_InvalidFormatInBundleVersion, line,CompilerFlags.ERROR, PDEMarkerFactory.CAT_FATAL);
 					addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNRESOLVED_IMPORTS);
 				}
 			}
@@ -415,7 +416,7 @@
 				}
 
 				if (!resolved) {
-					IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unresolvedHost, name), getLine(header, name), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.CAT_FATAL);
+					VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unresolvedHost, name), getLine(header, name), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.CAT_FATAL);
 					addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNRESOLVED_IMPORTS);
 					return;
 				}
@@ -424,7 +425,7 @@
 
 		IPluginModelBase model = PluginRegistry.findModel(name);
 		if (model == null || model instanceof IFragmentModel || !model.isEnabled()) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_HostNotExistPDE, name), getLine(header, name), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.CAT_FATAL);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_HostNotExistPDE, name), getLine(header, name), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.CAT_FATAL);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_UNRESOLVED_IMPORTS);
 		}
 	}
@@ -473,7 +474,7 @@
 							if (JavaRuntime.newDefaultJREContainerPath().matchingFirstSegments(currentPath) > 0) {
 								String eeId = JavaRuntime.getExecutionEnvironmentId(currentPath);
 								if (eeId != null) {
-									IMarker marker = report(PDECoreMessages.BundleErrorReporter_noExecutionEnvironmentSet, 1, sev, PDEMarkerFactory.M_EXECUTION_ENVIRONMENT_NOT_SET, PDEMarkerFactory.CAT_EE);
+									VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_noExecutionEnvironmentSet, 1, sev, PDEMarkerFactory.M_EXECUTION_ENVIRONMENT_NOT_SET, PDEMarkerFactory.CAT_EE);
 									addMarkerAttribute(marker, "ee_id", eeId); //$NON-NLS-1$
 									addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,	CompilerFlags.P_INCOMPATIBLE_ENV);
 									return;
@@ -501,7 +502,7 @@
 				for (IExecutionEnvironment systemEnv : systemEnvs) {
 					// Get strictly compatible EE for the default VM
 					if (systemEnv.isStrictlyCompatible(vm)) {
-						IMarker marker = report(PDECoreMessages.BundleErrorReporter_noExecutionEnvironmentSet, 1, sev, PDEMarkerFactory.M_EXECUTION_ENVIRONMENT_NOT_SET, PDEMarkerFactory.CAT_EE);
+						VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_noExecutionEnvironmentSet, 1, sev, PDEMarkerFactory.M_EXECUTION_ENVIRONMENT_NOT_SET, PDEMarkerFactory.CAT_EE);
 						addMarkerAttribute(marker, "ee_id", systemEnv.getId()); //$NON-NLS-1$
 						addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_INCOMPATIBLE_ENV);
 						break;
@@ -534,7 +535,7 @@
 						// Check if the user is using a perfect match JRE
 						IVMInstall vm = JavaRuntime.getVMInstall(currentPath);
 						if (vm == null || !env.isStrictlyCompatible(vm)) {
-							IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_reqExecEnv_conflict, bundleEnvs[0]),getLine(header, bundleEnvs[0]), sev, PDEMarkerFactory.M_MISMATCHED_EXEC_ENV,PDEMarkerFactory.CAT_EE);
+							VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_reqExecEnv_conflict, bundleEnvs[0]),getLine(header, bundleEnvs[0]), sev, PDEMarkerFactory.M_MISMATCHED_EXEC_ENV,PDEMarkerFactory.CAT_EE);
 							addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,CompilerFlags.P_INCOMPATIBLE_ENV);
 						}
 					}
@@ -552,7 +553,7 @@
 				}
 			}
 			if (!found) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_reqExecEnv_unknown, bundleEnv),
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_reqExecEnv_unknown, bundleEnv),
 						getLine(header, bundleEnv), sev, PDEMarkerFactory.M_UNKNOW_EXEC_ENV, PDEMarkerFactory.CAT_EE);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_INCOMPATIBLE_ENV);
 				break;
@@ -592,14 +593,14 @@
 				ResolverError[] errors = desc.getContainingState().getResolverErrors(desc);
 				for (ResolverError error : errors) {
 					if (error.getType() == ResolverError.PLATFORM_FILTER) {
-						IMarker marker = report(PDECoreMessages.BundleErrorReporter_badFilter,
+						VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_badFilter,
 								header.getLineNumber() + 1, severity, PDEMarkerFactory.CAT_OTHER);
 						addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_INCOMPATIBLE_ENV);
 					}
 				}
 			}
 		} catch (InvalidSyntaxException ise) {
-			IMarker marker = report(PDECoreMessages.BundleErrorReporter_invalidFilterSyntax, header.getLineNumber() + 1,
+			VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_invalidFilterSyntax, header.getLineNumber() + 1,
 					CompilerFlags.ERROR, PDEMarkerFactory.CAT_FATAL);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_INCOMPATIBLE_ENV);
 		}
@@ -613,7 +614,7 @@
 		String message;
 		if ((TargetPlatformHelper.getTargetVersion() >= 3.7) && isCheckDeprecated()) {
 			message = NLS.bind(PDECoreMessages.BundleErrorReporter_eclipse_genericCapabilityDeprecated, ICoreConstants.ECLIPSE_GENERIC_CAPABILITY, Constants.PROVIDE_CAPABILITY);
-			IMarker marker = report(message, header.getLineNumber() + 1, CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
+			VirtualMarker marker = report(message, header.getLineNumber() + 1, CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 		}
 
@@ -627,7 +628,7 @@
 		String message;
 		if ((TargetPlatformHelper.getTargetVersion() >= 3.7) && isCheckDeprecated()) {
 			message = NLS.bind(PDECoreMessages.BundleErrorReporter_eclipse_genericRequireDeprecated, ICoreConstants.ECLIPSE_GENERIC_REQUIRED, Constants.REQUIRE_CAPABILITY);
-			IMarker marker = report(message, header.getLineNumber() + 1, CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
+			VirtualMarker marker = report(message, header.getLineNumber() + 1, CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 		}
 
@@ -652,7 +653,7 @@
 
 					// Look for this activator in the project's classpath
 					if (!PDEJavaHelper.isOnClasspath(activator, javaProject)) {
-						IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_NoExist, activator), getLine(header, activator), CompilerFlags.P_UNKNOWN_CLASS, PDEMarkerFactory.M_UNKNOWN_ACTIVATOR, PDEMarkerFactory.CAT_FATAL);
+						VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_NoExist, activator), getLine(header, activator), CompilerFlags.P_UNKNOWN_CLASS, PDEMarkerFactory.M_UNKNOWN_ACTIVATOR, PDEMarkerFactory.CAT_FATAL);
 						addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNKNOWN_CLASS);
 					}
 				}
@@ -711,15 +712,12 @@
 			// It is possible for the bundle description to not match the headers
 			if (specs != null && specs[i].getSupplier() == null) {
 				if (desc.getContainingState().getBundle(specs[i].getName(), null) == null) {
-					IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_NotExistPDE, bundleID), getPackageLine(header, required[i]), severity, PDEMarkerFactory.M_REQ_BUNDLE_NOT_AVAILABLE, PDEMarkerFactory.CAT_FATAL);
+					VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_NotExistPDE, bundleID), getPackageLine(header, required[i]), severity, PDEMarkerFactory.M_REQ_BUNDLE_NOT_AVAILABLE, PDEMarkerFactory.CAT_FATAL);
 					addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNRESOLVED_IMPORTS);
-					try {
-						if (marker != null) {
-							marker.setAttribute("bundleId", required[i].getValue()); //$NON-NLS-1$
-							if (optional)
-								marker.setAttribute("optional", true); //$NON-NLS-1$
-						}
-					} catch (CoreException e) {
+					if (marker != null) {
+						marker.setAttribute("bundleId", required[i].getValue()); //$NON-NLS-1$
+						if (optional)
+							marker.setAttribute("optional", true); //$NON-NLS-1$
 					}
 				} else {
 					report(NLS.bind(PDECoreMessages.BundleErrorReporter_BundleRangeInvalidInBundleVersion, bundleID + ": " + specs[i].getVersionRange()), //$NON-NLS-1$
@@ -738,13 +736,13 @@
 		String versionRange = element.getAttribute(Constants.BUNDLE_VERSION_ATTRIBUTE);
 		int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_MISSING_VERSION_REQ_BUNDLE);
 		if (severity != CompilerFlags.IGNORE && versionRange == null) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_MissingVersion, element.getValue()),
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_MissingVersion, element.getValue()),
 					getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_MISSING_VERSION_REQ_BUNDLE);
 		}
 
 		if (versionRange != null && !VersionUtil.validateVersionRange(versionRange).isOK()) {
-			IMarker marker = report(
+			VirtualMarker marker = report(
 					NLS.bind(UtilMessages.BundleErrorReporter_InvalidFormatInBundleVersion, element.getValue()),
 					getPackageLine(header, element), CompilerFlags.ERROR, PDEMarkerFactory.CAT_FATAL);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_MISSING_VERSION_REQ_BUNDLE);
@@ -765,7 +763,7 @@
 			validateBooleanAttributeValue(header, element, ICoreConstants.REPROVIDE_ATTRIBUTE);
 			if (fOsgiR4 && isCheckDeprecated()) {
 				message = NLS.bind(PDECoreMessages.BundleErrorReporter_deprecated_attribute_reprovide, ICoreConstants.REPROVIDE_ATTRIBUTE);
-				IMarker marker = report(message, getLine(header, ICoreConstants.REPROVIDE_ATTRIBUTE + "="), //$NON-NLS-1$
+				VirtualMarker marker = report(message, getLine(header, ICoreConstants.REPROVIDE_ATTRIBUTE + "="), //$NON-NLS-1$
 						CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 			}
@@ -795,7 +793,7 @@
 		if (rexport != null) {
 			validateBooleanAttributeValue(header, element, ICoreConstants.OPTIONAL_ATTRIBUTE);
 			if (fOsgiR4 && isCheckDeprecated()) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_deprecated_attribute_optional, ICoreConstants.OPTIONAL_ATTRIBUTE), getLine(header, ICoreConstants.OPTIONAL_ATTRIBUTE + "="), //$NON-NLS-1$
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_deprecated_attribute_optional, ICoreConstants.OPTIONAL_ATTRIBUTE), getLine(header, ICoreConstants.OPTIONAL_ATTRIBUTE + "="), //$NON-NLS-1$
 						CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 			}
@@ -876,23 +874,20 @@
 						Version version = export.getVersion();
 						org.eclipse.osgi.service.resolver.VersionRange range = importSpec.getVersionRange();
 						if (range != null && !range.isIncluded(version)) {
-							IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unsatisfiedConstraint,importSpec.toString()),getPackageLine(header, element), severity, PDEMarkerFactory.CAT_FATAL);
+							VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unsatisfiedConstraint,importSpec.toString()),getPackageLine(header, element), severity, PDEMarkerFactory.CAT_FATAL);
 							addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,CompilerFlags.P_UNRESOLVED_IMPORTS);
 						}
 					} else {
-						IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unresolvedExporter,new String[] { export.getSupplier().getSymbolicName(), name }),getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
+						VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unresolvedExporter,new String[] { export.getSupplier().getSymbolicName(), name }),getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
 						addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_UNRESOLVED_IMPORTS);
 					}
 				} else {
-					IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_PackageNotExported, name), getPackageLine(header, element), severity, PDEMarkerFactory.M_IMPORT_PKG_NOT_AVAILABLE, PDEMarkerFactory.CAT_FATAL);
+					VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_PackageNotExported, name), getPackageLine(header, element), severity, PDEMarkerFactory.M_IMPORT_PKG_NOT_AVAILABLE, PDEMarkerFactory.CAT_FATAL);
 					addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_UNRESOLVED_IMPORTS);
-					try {
-						if (marker != null) {
-							marker.setAttribute("packageName", name); //$NON-NLS-1$
-							if (optional)
-								marker.setAttribute("optional", true); //$NON-NLS-1$
-						}
-					} catch (CoreException e) {
+					if (marker != null) {
+						marker.setAttribute("packageName", name); //$NON-NLS-1$
+						if (optional)
+							marker.setAttribute("optional", true); //$NON-NLS-1$
 					}
 				}
 			}
@@ -956,7 +951,7 @@
 				/* The exported package does not exist in the bundle.  Allow project folders to be packages (see bug 166680 comment 17)*/
 				if (!getExportedPackages().contains(name) && !(fProject.getFolder(name.replace('.', '/')).exists())) {
 					message = NLS.bind(PDECoreMessages.BundleErrorReporter_NotExistInProject, name);
-					IMarker marker = report(message, getPackageLine(header, element), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.M_EXPORT_PKG_NOT_EXIST, PDEMarkerFactory.CAT_OTHER);
+					VirtualMarker marker = report(message, getPackageLine(header, element), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.M_EXPORT_PKG_NOT_EXIST, PDEMarkerFactory.CAT_OTHER);
 					addMarkerAttribute(marker, "packageName", name); //$NON-NLS-1$
 					addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNRESOLVED_IMPORTS);
 
@@ -1081,12 +1076,12 @@
 			if (header != null) {
 				String value = header.getValue();
 				if (!value.startsWith("%")) { //$NON-NLS-1$
-					IMarker marker =report(NLS.bind(PDECoreMessages.Builders_Manifest_non_ext_attribute, header.getName()), getLine(header, value), severity, PDEMarkerFactory.P_UNTRANSLATED_NODE, header.getName(), PDEMarkerFactory.CAT_NLS);
+					VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_non_ext_attribute, header.getName()), getLine(header, value), severity, PDEMarkerFactory.P_UNTRANSLATED_NODE, header.getName(), PDEMarkerFactory.CAT_NLS);
 					addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_NOT_EXTERNALIZED);
 				} else if (fModel instanceof AbstractNLModel) {
 					NLResourceHelper helper = ((AbstractNLModel) fModel).getNLResourceHelper();
 					if (helper == null || !helper.resourceExists(value)) {
-						IMarker marker =report(NLS.bind(PDECoreMessages.Builders_Manifest_key_not_found, value.substring(1), PDEManager.getBundleLocalization(fModel).concat(".properties")), getLine(header, value), severity, PDEMarkerFactory.CAT_NLS); //$NON-NLS-1$
+						VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_key_not_found, value.substring(1), PDEManager.getBundleLocalization(fModel).concat(".properties")), getLine(header, value), severity, PDEMarkerFactory.CAT_NLS); //$NON-NLS-1$
 						addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_NOT_EXTERNALIZED);
 					}
 				}
@@ -1102,7 +1097,7 @@
 		}
 		if (isCheckDeprecated()) {
 			if (fOsgiR4 && version != null) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_deprecated_attribute_specification_version, ICoreConstants.PACKAGE_SPECIFICATION_VERSION), getPackageLine(header, element), CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_deprecated_attribute_specification_version, ICoreConstants.PACKAGE_SPECIFICATION_VERSION), getPackageLine(header, element), CompilerFlags.P_DEPRECATED, PDEMarkerFactory.CAT_DEPRECATION);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 			}
 		}
@@ -1112,7 +1107,7 @@
 		String version = element.getAttribute(Constants.VERSION_ATTRIBUTE);
 		int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_MISSING_VERSION_IMP_PKG);
 		if (severity != CompilerFlags.IGNORE && version == null) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_MissingVersion, element.getValue()), getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_MissingVersion, element.getValue()), getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_MISSING_VERSION_IMP_PKG);
 		}
 		validateVersionAttribute(header, element, true);
@@ -1122,7 +1117,7 @@
 		String version = element.getAttribute(Constants.VERSION_ATTRIBUTE);
 		int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_MISSING_VERSION_EXP_PKG);
 		if (severity != CompilerFlags.IGNORE && version == null) {
-			IMarker marker =report(NLS.bind(PDECoreMessages.BundleErrorReporter_MissingVersion, element.getValue()), getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_MissingVersion, element.getValue()), getPackageLine(header, element), severity, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_MISSING_VERSION_EXP_PKG);
 		}
 		validateVersionAttribute(header, element, false);
@@ -1156,7 +1151,7 @@
 		String internal = element.getDirective(ICoreConstants.INTERNAL_DIRECTIVE);
 		if (friends != null && internal != null) {
 			String message = NLS.bind(PDECoreMessages.BundleErrorReporter_directive_hasNoEffectWith_, new String[] {ICoreConstants.FRIENDS_DIRECTIVE, ICoreConstants.INTERNAL_DIRECTIVE});
-			IMarker marker = report(message, getPackageLine(header, element), CompilerFlags.WARNING, PDEMarkerFactory.M_DIRECTIVE_HAS_NO_EFFECT, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(message, getPackageLine(header, element), CompilerFlags.WARNING, PDEMarkerFactory.M_DIRECTIVE_HAS_NO_EFFECT, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, "packageName", element.getValue()); //$NON-NLS-1$
 		}
 	}
@@ -1174,7 +1169,7 @@
 		if (TargetPlatformHelper.getTargetVersion() >= 3.3) {
 			validateHeaderValue(header, new String[] {Constants.ACTIVATION_LAZY});
 		} else if (severity != CompilerFlags.IGNORE && !containsValidActivationHeader()) {
-			IMarker marker =report(PDECoreMessages.BundleErrorReporter_bundleActivationPolicy_unsupported, header.getLineNumber() + 1, severity, PDEMarkerFactory.NO_RESOLUTION, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_bundleActivationPolicy_unsupported, header.getLineNumber() + 1, severity, PDEMarkerFactory.NO_RESOLUTION, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_DEPRECATED);
 		}
 	}
@@ -1188,16 +1183,13 @@
 		if (severity != CompilerFlags.IGNORE && TargetPlatformHelper.getTargetVersion() >= 3.2 && !containsValidActivationHeader()) {
 			int line = header.getLineNumber();
 			String message = NLS.bind(PDECoreMessages.BundleErrorReporter_startHeader_autoStartDeprecated, new Object[] {ICoreConstants.ECLIPSE_AUTOSTART, getCurrentActivationHeader()});
-			IMarker marker = report(message, line + 1, severity, PDEMarkerFactory.M_DEPRECATED_AUTOSTART, PDEMarkerFactory.CAT_DEPRECATION);
+			VirtualMarker marker = report(message, line + 1, severity, PDEMarkerFactory.M_DEPRECATED_AUTOSTART, PDEMarkerFactory.CAT_DEPRECATION);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 			if (marker != null) {
-				try {
-					marker.setAttribute(PDEMarkerFactory.ATTR_HEADER, ICoreConstants.ECLIPSE_AUTOSTART);
-					ManifestElement elem = header.getElements()[0];
-					boolean unnecessary = elem.getValue().equals("false") && elem.getAttribute("excludes") == null; //$NON-NLS-1$ //$NON-NLS-2$
-					marker.setAttribute(PDEMarkerFactory.ATTR_CAN_ADD, !unnecessary);
-				} catch (CoreException e) {
-				}
+				marker.setAttribute(PDEMarkerFactory.ATTR_HEADER, ICoreConstants.ECLIPSE_AUTOSTART);
+				ManifestElement elem = header.getElements()[0];
+				boolean unnecessary = elem.getValue().equals("false") && elem.getAttribute("excludes") == null; //$NON-NLS-1$ //$NON-NLS-2$
+				marker.setAttribute(PDEMarkerFactory.ATTR_CAN_ADD, !unnecessary);
 			}
 		}
 	}
@@ -1211,22 +1203,19 @@
 				return;
 			double targetVersion = TargetPlatformHelper.getTargetVersion();
 			if (targetVersion < 3.2) {
-				IMarker marker = report(PDECoreMessages.BundleErrorReporter_lazyStart_unsupported, header.getLineNumber() + 1, severity, PDEMarkerFactory.NO_RESOLUTION, PDEMarkerFactory.CAT_OTHER);
+				VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_lazyStart_unsupported, header.getLineNumber() + 1, severity, PDEMarkerFactory.NO_RESOLUTION, PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 			} else if (targetVersion > 3.3) {
 				int line = header.getLineNumber();
 				String message = NLS.bind(PDECoreMessages.BundleErrorReporter_startHeader_autoStartDeprecated, new Object[] {ICoreConstants.ECLIPSE_LAZYSTART, getCurrentActivationHeader()});
-				IMarker marker = report(message, line + 1, severity, PDEMarkerFactory.M_DEPRECATED_AUTOSTART, PDEMarkerFactory.CAT_DEPRECATION);
+				VirtualMarker marker = report(message, line + 1, severity, PDEMarkerFactory.M_DEPRECATED_AUTOSTART, PDEMarkerFactory.CAT_DEPRECATION);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 				if (marker != null) {
-					try {
-						marker.setAttribute(PDEMarkerFactory.ATTR_HEADER, ICoreConstants.ECLIPSE_LAZYSTART);
-						ManifestElement elem = header.getElements()[0];
+					marker.setAttribute(PDEMarkerFactory.ATTR_HEADER, ICoreConstants.ECLIPSE_LAZYSTART);
+					ManifestElement elem = header.getElements()[0];
 
-						boolean unnecessary = elem.getValue().equals("false") && elem.getAttribute("excludes") == null; //$NON-NLS-1$ //$NON-NLS-2$
-						marker.setAttribute(PDEMarkerFactory.ATTR_CAN_ADD, !unnecessary);
-					} catch (CoreException e) {
-					}
+					boolean unnecessary = elem.getValue().equals("false") && elem.getAttribute("excludes") == null; //$NON-NLS-1$ //$NON-NLS-2$
+					marker.setAttribute(PDEMarkerFactory.ATTR_CAN_ADD, !unnecessary);
 				}
 			}
 		}
@@ -1278,7 +1267,7 @@
 						String name = st.nextToken().trim();
 						if (!getExportedPackages().contains(name)) {
 							String message = NLS.bind(PDECoreMessages.BundleErrorReporter_NotExistInProject, name);
-							IMarker marker =report(message, getLine(header, name), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.CAT_OTHER);
+							VirtualMarker marker = report(message, getLine(header, name), CompilerFlags.P_UNRESOLVED_IMPORTS, PDEMarkerFactory.CAT_OTHER);
 							addMarkerAttribute(marker,PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_ATTRIBUTE);
 							return false;
 						}
@@ -1295,14 +1284,10 @@
 			validateBooleanValue(header);
 	}
 
-	public IMarker report(String message, int line, int severity, int problemID, String headerName, String category) {
-		IMarker marker = null;
-		try {
-		    marker = report(message, line, severity, problemID, category);
-			if (marker != null)
-				marker.setAttribute(PDEMarkerFactory.MPK_LOCATION_PATH, headerName);
-		} catch (CoreException e) {
-		}
+	public VirtualMarker report(String message, int line, int severity, int problemID, String headerName, String category) {
+		VirtualMarker marker = report(message, line, severity, problemID, category);
+		if (marker != null)
+			marker.setAttribute(PDEMarkerFactory.MPK_LOCATION_PATH, headerName);
 		return marker;
 	}
 
@@ -1317,13 +1302,13 @@
 
 			if (importHeader != null) {
 				int line = importHeader.getLineNumber();
-				IMarker marker =report(NLS.bind(PDECoreMessages.BundleErrorReporter_importexport_servicesDeprecated, ICoreConstants.IMPORT_SERVICE), line + 1, severity, PDEMarkerFactory.M_DEPRECATED_IMPORT_SERVICE, PDEMarkerFactory.CAT_DEPRECATION);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_importexport_servicesDeprecated, ICoreConstants.IMPORT_SERVICE), line + 1, severity, PDEMarkerFactory.M_DEPRECATED_IMPORT_SERVICE, PDEMarkerFactory.CAT_DEPRECATION);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_DEPRECATED);
 			}
 
 			if (exportHeader != null) {
 				int line = exportHeader.getLineNumber();
-				IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_importexport_servicesDeprecated, ICoreConstants.EXPORT_SERVICE), line + 1, severity, PDEMarkerFactory.M_DEPRECATED_EXPORT_SERVICE, PDEMarkerFactory.CAT_DEPRECATION);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_importexport_servicesDeprecated, ICoreConstants.EXPORT_SERVICE), line + 1, severity, PDEMarkerFactory.M_DEPRECATED_EXPORT_SERVICE, PDEMarkerFactory.CAT_DEPRECATION);
 				addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_DEPRECATED);
 			}
 		}
@@ -1350,7 +1335,7 @@
 
 		IResource res = PDEProject.getBundleRoot(fProject).findMember(location);
 		if (res == null || !(res instanceof IContainer)) {
-			IMarker marker = report(PDECoreMessages.BundleErrorReporter_localization_folder_not_exist, header.getLineNumber() + 1, CompilerFlags.getFlag(fProject, CompilerFlags.P_UNKNOWN_RESOURCE), PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_localization_folder_not_exist, header.getLineNumber() + 1, CompilerFlags.getFlag(fProject, CompilerFlags.P_UNKNOWN_RESOURCE), PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_RESOURCE);
 			return;
 		}
@@ -1366,7 +1351,7 @@
 			}
 		} catch (CoreException e) {
 		}
-		IMarker marker = report(PDECoreMessages.BundleErrorReporter_localization_properties_file_not_exist, header.getLineNumber() + 1, CompilerFlags.getFlag(fProject, CompilerFlags.P_UNKNOWN_RESOURCE), PDEMarkerFactory.CAT_OTHER);
+		VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_localization_properties_file_not_exist, header.getLineNumber() + 1, CompilerFlags.getFlag(fProject, CompilerFlags.P_UNKNOWN_RESOURCE), PDEMarkerFactory.CAT_OTHER);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_RESOURCE);
 	}
 
@@ -1378,7 +1363,7 @@
 		ManifestElement[] elements = header.getElements();
 
 		if (elements[0] != null && elements[0].getValue().equals(element.getValue())) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unecessaryDependencyDueToFragmentHost, element.getValue()), getPackageLine(requireBundleHeader, element), CompilerFlags.WARNING, PDEMarkerFactory.M_UNECESSARY_DEP, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.BundleErrorReporter_unecessaryDependencyDueToFragmentHost, element.getValue()), getPackageLine(requireBundleHeader, element), CompilerFlags.WARNING, PDEMarkerFactory.M_UNECESSARY_DEP, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, "bundleId", element.getValue()); //$NON-NLS-1$
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNRESOLVED_IMPORTS);
 
@@ -1391,17 +1376,14 @@
 			return;
 
 		if (fOsgiR4 && isCheckDeprecated()) {
-			IMarker marker = report(PDECoreMessages.BundleErrorReporter_providePackageHeaderDeprecated, header.getLineNumber() + 1, CompilerFlags.P_DEPRECATED, PDEMarkerFactory.M_DEPRECATED_PROVIDE_PACKAGE, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_providePackageHeaderDeprecated, header.getLineNumber() + 1, CompilerFlags.P_DEPRECATED, PDEMarkerFactory.M_DEPRECATED_PROVIDE_PACKAGE, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,CompilerFlags.P_DEPRECATED );
 		}
 	}
 
-	private void addMarkerAttribute(IMarker marker, String attr, String value) {
+	private void addMarkerAttribute(VirtualMarker marker, String attr, String value) {
 		if (marker != null)
-			try {
-				marker.setAttribute(attr, value);
-			} catch (CoreException e) {
-			}
+			marker.setAttribute(attr, value);
 	}
 
 	/**
@@ -1419,7 +1401,7 @@
 
 		int compilerFlag = CompilerFlags.getFlag(fProject, CompilerFlags.P_SERVICE_COMP_WITHOUT_LAZY_ACT);
 		if (compilerFlag != CompilerFlags.IGNORE) {
-			IMarker marker = report(PDECoreMessages.BundleErrorReporter_serviceComponentLazyStart, header.getLineNumber() + 1, CompilerFlags.P_SERVICE_COMP_WITHOUT_LAZY_ACT, PDEMarkerFactory.M_SERVICECOMPONENT_MISSING_LAZY, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_serviceComponentLazyStart, header.getLineNumber() + 1, CompilerFlags.P_SERVICE_COMP_WITHOUT_LAZY_ACT, PDEMarkerFactory.M_SERVICECOMPONENT_MISSING_LAZY, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_SERVICE_COMP_WITHOUT_LAZY_ACT);
 		}
 	}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ErrorReporter.java
index ee7bc83..d067155 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ErrorReporter.java
@@ -20,40 +20,25 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.pde.internal.core.PDECore;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 
 public abstract class ErrorReporter {
 
-	protected static final String[] BOOLEAN_VALUES = new String[] {"true", "false"}; //$NON-NLS-1$ //$NON-NLS-2$
+	protected static final String[] BOOLEAN_VALUES = new String[] { "true", "false" }; //$NON-NLS-1$ //$NON-NLS-2$
 
-	private int fErrorCount;
-	protected IFile fFile;
+	protected final IFile fFile;
 	protected IProject fProject;
-	private PDEMarkerFactory fMarkerFactory;
+
+	private final IncrementalErrorReporter fErrorReporter;
 
 	public ErrorReporter(IFile file) {
-		fErrorCount = 0;
 		fFile = file;
-		if (fFile != null) {
-			fProject = fFile.getProject();
-		}
+		fErrorReporter = new IncrementalErrorReporter(file);
+		fProject = file.getProject();
 	}
 
-	protected IMarker addMarker(String message, int lineNumber, int severity, int problemID, String category) {
-		try {
-			IMarker marker = getMarkerFactory().createMarker(fFile, problemID, category);
-			marker.setAttribute(IMarker.MESSAGE, message);
-			marker.setAttribute(IMarker.SEVERITY, severity);
-			if (lineNumber == -1)
-				lineNumber = 1;
-			marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
-			if (severity == IMarker.SEVERITY_ERROR) {
-				fErrorCount += 1;
-			}
-			return marker;
-		} catch (CoreException e) {
-			PDECore.logException(e);
-		}
-		return null;
+	protected VirtualMarker addMarker(String message, int lineNumber, int severity, int problemID, String category) {
+		return fErrorReporter.addMarker(message, lineNumber, severity, problemID, category);
 	}
 
 	protected IDocument createDocument(IFile file) {
@@ -77,26 +62,13 @@
 	}
 
 	public int getErrorCount() {
-		return fErrorCount;
-	}
-
-	private PDEMarkerFactory getMarkerFactory() {
-		if (fMarkerFactory == null)
-			fMarkerFactory = new PDEMarkerFactory();
-		return fMarkerFactory;
-	}
-
-	private void removeFileMarkers() {
-		try {
-			fFile.deleteMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
-			fFile.deleteMarkers(PDEMarkerFactory.MARKER_ID, false, IResource.DEPTH_ZERO);
-		} catch (CoreException e) {
-			PDECore.logException(e);
-		}
+		return fErrorReporter.getErrorCount();
 	}
 
 	/**
-	 * Return a new marker with the provided attributes.  May return <code>null</code> if no marker should be created because of severity settings.
+	 * Return a new marker with the provided attributes. May return
+	 * <code>null</code> if no marker should be created because of severity
+	 * settings.
 	 *
 	 * @param message
 	 * @param line
@@ -105,7 +77,7 @@
 	 * @param category
 	 * @return a new marker or <code>null</code>
 	 */
-	public IMarker report(String message, int line, int severity, int problemID, String category) {
+	public VirtualMarker report(String message, int line, int severity, int problemID, String category) {
 		if (severity == CompilerFlags.ERROR)
 			return addMarker(message, line, IMarker.SEVERITY_ERROR, problemID, category);
 		else if (severity == CompilerFlags.WARNING)
@@ -113,11 +85,11 @@
 		return null;
 	}
 
-	public IMarker report(String message, int line, int severity, String category) {
+	public VirtualMarker report(String message, int line, int severity, String category) {
 		return report(message, line, severity, PDEMarkerFactory.M_ONLY_CONFIG_SEV, category);
 	}
 
-	protected IMarker report(String message, int line, String compilerFlag, int problemID, String category) {
+	protected VirtualMarker report(String message, int line, String compilerFlag, int problemID, String category) {
 		int severity = CompilerFlags.getFlag(fProject, compilerFlag);
 		if (severity != CompilerFlags.IGNORE) {
 			return report(message, line, severity, problemID, category);
@@ -125,13 +97,13 @@
 		return null;
 	}
 
-	protected IMarker report(String message, int line, String compilerFlag, String category) {
+	protected VirtualMarker report(String message, int line, String compilerFlag, String category) {
 		return report(message, line, compilerFlag, PDEMarkerFactory.M_ONLY_CONFIG_SEV, category);
 	}
 
-	public void validateContent(IProgressMonitor monitor) {
-		removeFileMarkers();
+	public final void validateContent(IProgressMonitor monitor) {
 		validate(monitor);
+		fErrorReporter.applyMarkers();
 	}
 
 	protected abstract void validate(IProgressMonitor monitor);
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionPointSchemaBuilder.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionPointSchemaBuilder.java
index 26eb78c..357e954 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionPointSchemaBuilder.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionPointSchemaBuilder.java
@@ -115,7 +115,7 @@
 
 		SchemaErrorReporter reporter = new SchemaErrorReporter(file);
 		DefaultSAXParser.parse(file, reporter);
-		reporter.validateContent(monitor);
+		reporter.validate(monitor);
 
 		try (StringWriter swriter = new StringWriter(); PrintWriter writer = new PrintWriter(swriter)) {
 			boolean generateDoc = CompilerFlags.getBoolean(file.getProject(), CompilerFlags.S_CREATE_DOCS);
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionsErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionsErrorReporter.java
index e1382de..db32551 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionsErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ExtensionsErrorReporter.java
@@ -25,6 +25,7 @@
 import org.eclipse.pde.core.build.IBuild;
 import org.eclipse.pde.core.plugin.*;
 import org.eclipse.pde.internal.core.*;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.eclipse.pde.internal.core.ischema.*;
 import org.eclipse.pde.internal.core.project.PDEProject;
 import org.eclipse.pde.internal.core.schema.SchemaRegistry;
@@ -58,7 +59,7 @@
 	}
 
 	@Override
-	public void validateContent(IProgressMonitor monitor) {
+	public void validate(IProgressMonitor monitor) {
 		Element element = getDocumentRoot();
 		if (element == null)
 			return;
@@ -113,7 +114,7 @@
 		if (!PDECore.getDefault().getExtensionsRegistry().hasExtensionPoint(pointID)) {
 			int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_UNRESOLVED_EX_POINTS);
 			if (severity != CompilerFlags.IGNORE) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_ex_point, pointID), getLine(element, "point"), severity, PDEMarkerFactory.CAT_OTHER); //$NON-NLS-1$
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_ex_point, pointID), getLine(element, "point"), severity, PDEMarkerFactory.CAT_OTHER); //$NON-NLS-1$
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNRESOLVED_EX_POINTS);
 			}
 		} else {
@@ -133,7 +134,7 @@
 		Element childElement = result.getElement();
 		String allowedOccurrences = Integer.toString(result.getAllowedOccurrences());
 		String message = NLS.bind(PDECoreMessages.ExtensionsErrorReporter_maxOccurrence, new String[] {allowedOccurrences, childElement.getNodeName()});
-		IMarker marker = report(message, getLine(childElement), severity, PDEMarkerFactory.P_ILLEGAL_XML_NODE, childElement, null, PDEMarkerFactory.CAT_FATAL);
+		VirtualMarker marker = report(message, getLine(childElement), severity, PDEMarkerFactory.P_ILLEGAL_XML_NODE, childElement, null, PDEMarkerFactory.CAT_FATAL);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNKNOWN_ELEMENT);
 	}
 
@@ -146,7 +147,7 @@
 		ISchemaElement childElement = result.getSchemaElement();
 		String allowedOccurrences = Integer.toString(result.getAllowedOccurrences());
 		String message = NLS.bind(PDECoreMessages.ExtensionsErrorReporter_minOccurrence, new String[] {allowedOccurrences, childElement.getName()});
-		IMarker marker = report(message, getLine(parentElement), severity, PDEMarkerFactory.CAT_FATAL);
+		VirtualMarker marker = report(message, getLine(parentElement), severity, PDEMarkerFactory.CAT_FATAL);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNKNOWN_ELEMENT);
 	}
 
@@ -235,7 +236,7 @@
 				String point = element.getAttribute("point"); //$NON-NLS-1$
 				if (point == null)
 					return; // should never come to this...
-				IMarker marker =report(NLS.bind(PDECoreMessages.Builders_Manifest_internal_rootElement, point), getLine(element, "point"), severity, PDEMarkerFactory.CAT_DEPRECATION); //$NON-NLS-1$
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_internal_rootElement, point), getLine(element, "point"), severity, PDEMarkerFactory.CAT_DEPRECATION); //$NON-NLS-1$
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_INTERNAL);
 			}
 		}
@@ -427,7 +428,7 @@
 			if (errorMessage != null) {
 				severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_UNKNOWN_RESOURCE);
 				if (severity != CompilerFlags.IGNORE) {
-					IMarker marker = report(NLS.bind(errorMessage, schemaValue), getLine(element), severity, PDEMarkerFactory.CAT_OTHER);
+					VirtualMarker marker = report(NLS.bind(errorMessage, schemaValue), getLine(element), severity, PDEMarkerFactory.CAT_OTHER);
 					addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_RESOURCE);
 				}
 			}
@@ -442,12 +443,12 @@
 			return;
 		String value = attr.getValue();
 		if (!value.startsWith("%")) { //$NON-NLS-1$
-			IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_non_ext_attribute, attr.getName()), getLine(element, attr.getName()), severity, PDEMarkerFactory.P_UNTRANSLATED_NODE, element, attr.getName(), PDEMarkerFactory.CAT_NLS);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_non_ext_attribute, attr.getName()), getLine(element, attr.getName()), severity, PDEMarkerFactory.P_UNTRANSLATED_NODE, element, attr.getName(), PDEMarkerFactory.CAT_NLS);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_NOT_EXTERNALIZED);
 		} else if (fModel instanceof AbstractNLModel) {
 			NLResourceHelper helper = ((AbstractNLModel) fModel).getNLResourceHelper();
 			if (helper == null || !helper.resourceExists(value)) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_key_not_found, value.substring(1), PDEManager.getBundleLocalization(fModel).concat(".properties")), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_NLS); //$NON-NLS-1$
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_key_not_found, value.substring(1), PDEManager.getBundleLocalization(fModel).concat(".properties")), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_NLS); //$NON-NLS-1$
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_NOT_EXTERNALIZED);
 			}
 		}
@@ -461,12 +462,12 @@
 		if (value == null)
 			return;
 		if (!value.startsWith("%")) { //$NON-NLS-1$
-			IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_non_ext_element, element.getNodeName()), getLine(element), severity, PDEMarkerFactory.P_UNTRANSLATED_NODE, element, null, PDEMarkerFactory.CAT_NLS);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_non_ext_element, element.getNodeName()), getLine(element), severity, PDEMarkerFactory.P_UNTRANSLATED_NODE, element, null, PDEMarkerFactory.CAT_NLS);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_NOT_EXTERNALIZED);
 		} else if (fModel instanceof AbstractNLModel) {
 			NLResourceHelper helper = ((AbstractNLModel) fModel).getNLResourceHelper();
 			if (helper == null || !helper.resourceExists(value)) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_key_not_found, value.substring(1), PDEManager.getBundleLocalization(fModel).concat(".properties")), getLine(element), severity, PDEMarkerFactory.CAT_NLS); //$NON-NLS-1$
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_key_not_found, value.substring(1), PDEManager.getBundleLocalization(fModel).concat(".properties")), getLine(element), severity, PDEMarkerFactory.CAT_NLS); //$NON-NLS-1$
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_NOT_EXTERNALIZED);
 			}
 		}
@@ -475,7 +476,7 @@
 	protected void validateResourceAttribute(Element element, Attr attr) {
 		int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_UNKNOWN_RESOURCE);
 		if (severity != CompilerFlags.IGNORE && !resourceExists(attr.getValue())) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_resource, (new String[] {attr.getValue(), attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_resource, (new String[] {attr.getValue(), attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_RESOURCE);
 		}
 	}
@@ -563,7 +564,7 @@
 		if (severity != CompilerFlags.IGNORE && javaProject.isOpen()) {
 			onClasspath = PDEJavaHelper.isOnClasspath(value, javaProject);
 			if (!onClasspath) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_class, (new String[] {value, attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.P_UNKNOWN_CLASS, element, attr.getName() + F_ATT_VALUE_PREFIX + attr.getValue(), PDEMarkerFactory.CAT_FATAL);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_class, (new String[] {value, attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.P_UNKNOWN_CLASS, element, attr.getName() + F_ATT_VALUE_PREFIX + attr.getValue(), PDEMarkerFactory.CAT_FATAL);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_CLASS);
 			}
 		}
@@ -578,7 +579,7 @@
 				return;
 			// only check if we're discouraged if there is something on the classpath
 			if (onClasspath && PDEJavaHelper.isDiscouraged(value, javaProject, desc)) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_discouragedClass, (new String[] {value, attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.M_DISCOURAGED_CLASS, element, attr.getName() + F_ATT_VALUE_PREFIX + attr.getValue(), PDEMarkerFactory.CAT_OTHER);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_discouragedClass, (new String[] {value, attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.M_DISCOURAGED_CLASS, element, attr.getName() + F_ATT_VALUE_PREFIX + attr.getValue(), PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DISCOURAGED_CLASS);
 			}
 		}
@@ -607,7 +608,7 @@
 			if (value != null && basedOn != null && value.length() > 0 && basedOn.length() > 0) {
 				Map<?, ?> attributes = PDESchemaHelper.getValidAttributes(attInfo);
 				if (!attributes.containsKey(value)) { // report error if we are missing something
-					IMarker marker = report(NLS.bind(PDECoreMessages.ExtensionsErrorReporter_unknownIdentifier, (new String[] {attr.getValue(), attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
+					VirtualMarker marker = report(NLS.bind(PDECoreMessages.ExtensionsErrorReporter_unknownIdentifier, (new String[] {attr.getValue(), attr.getName()})), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
 					addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.P_UNKNOWN_IDENTIFIER);
 				}
 			}
@@ -616,20 +617,20 @@
 
 	protected void reportUnusedAttribute(Element element, String attName, int severity) {
 		String message = NLS.bind(PDECoreMessages.Builders_Manifest_unused_attribute, attName);
-		IMarker marker =report(message, getLine(element, attName), severity, PDEMarkerFactory.CAT_OTHER);
+		VirtualMarker marker = report(message, getLine(element, attName), severity, PDEMarkerFactory.CAT_OTHER);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 	}
 
 	protected void reportUnusedElement(Element element, int severity) {
 		Node parent = element.getParentNode();
-		IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_unused_element, (new String[] {element.getNodeName(), parent.getNodeName()})), getLine(element), severity, PDEMarkerFactory.CAT_OTHER);
+		VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_unused_element, (new String[] {element.getNodeName(), parent.getNodeName()})), getLine(element), severity, PDEMarkerFactory.CAT_OTHER);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 	}
 
 	protected void reportDeprecatedElement(Element element) {
 		int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_DEPRECATED);
 		if (severity != CompilerFlags.IGNORE) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_element, element.getNodeName()), getLine(element), severity, PDEMarkerFactory.CAT_DEPRECATION);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_element, element.getNodeName()), getLine(element), severity, PDEMarkerFactory.CAT_DEPRECATION);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 		}
 	}
@@ -645,7 +646,7 @@
 				message = NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_rootElementSuggestion, point, suggestion);
 			else
 				message = NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_rootElement, point);
-			IMarker marker = report(message, getLine(element, "point"), severity, PDEMarkerFactory.CAT_DEPRECATION); //$NON-NLS-1$
+			VirtualMarker marker = report(message, getLine(element, "point"), severity, PDEMarkerFactory.CAT_DEPRECATION); //$NON-NLS-1$
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 		}
 	}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/FeatureErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/FeatureErrorReporter.java
index d23cdc1..0b6c3e5 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/FeatureErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/FeatureErrorReporter.java
@@ -18,11 +18,11 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.core.plugin.*;
 import org.eclipse.pde.internal.core.*;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.eclipse.pde.internal.core.ibundle.IBundlePluginModel;
 import org.eclipse.pde.internal.core.ibundle.IManifestHeader;
 import org.eclipse.pde.internal.core.ifeature.IFeatureModel;
@@ -47,7 +47,7 @@
 	}
 
 	@Override
-	public void validateContent(IProgressMonitor monitor) {
+	protected void validate(IProgressMonitor monitor) {
 		fMonitor = monitor;
 		Element element = getDocumentRoot();
 		if (element == null)
@@ -389,7 +389,7 @@
 		if (severity != CompilerFlags.IGNORE) {
 			IPluginModelBase model = PluginRegistry.findModel(id);
 			if (model == null || !model.isEnabled() || (isFragment && !model.isFragmentModel()) || (!isFragment && model.isFragmentModel())) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Feature_reference, id), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Feature_reference, id), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.F_UNRESOLVED_PLUGINS);
 			}
 		}
@@ -400,7 +400,7 @@
 		if (severity != CompilerFlags.IGNORE) {
 			IFeatureModel[] models = PDECore.getDefault().getFeatureModelManager().findFeatureModels(attr.getValue());
 			if (models.length == 0) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Feature_freference, attr.getValue()), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Feature_freference, attr.getValue()), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_OTHER);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.F_UNRESOLVED_FEATURES);
 			}
 		}
@@ -434,7 +434,7 @@
 				String unpackValue = "true".equals(unpack) ? "jar" : "dir"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 				if (value != null && !value.equalsIgnoreCase(unpackValue)) {
 					String message = NLS.bind(PDECoreMessages.Builders_Feature_mismatchUnpackBundleShape, (new String[] {"unpack=" + unpack, parent.getAttribute("id"), "Eclipse-BundleShape: " + value})); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-					IMarker marker = report(message, getLine(parent), severity, PDEMarkerFactory.CAT_OTHER);
+					VirtualMarker marker = report(message, getLine(parent), severity, PDEMarkerFactory.CAT_OTHER);
 					addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.F_UNRESOLVED_PLUGINS);
 				}
 			}
@@ -442,7 +442,7 @@
 
 		if ("true".equals(unpack) && !CoreUtility.guessUnpack(pModel.getBundleDescription())) {//$NON-NLS-1$
 			String message = NLS.bind(PDECoreMessages.Builders_Feature_missingUnpackFalse, (new String[] {parent.getAttribute("id"), "unpack=\"false\""})); //$NON-NLS-1$ //$NON-NLS-2$
-			IMarker marker = report(message, getLine(parent), severity, PDEMarkerFactory.CAT_OTHER);
+			VirtualMarker marker = report(message, getLine(parent), severity, PDEMarkerFactory.CAT_OTHER);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.F_UNRESOLVED_PLUGINS);
 		}
 	}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/IncrementalErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/IncrementalErrorReporter.java
new file mode 100644
index 0000000..d7e97da
--- /dev/null
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/IncrementalErrorReporter.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ *  Copyright (c) 2018 Julian Honnen
+ *
+ *  This program and the accompanying materials
+ *  are made available under the terms of the Eclipse Public License 2.0
+ *  which accompanies this distribution, and is available at
+ *  https://www.eclipse.org/legal/epl-2.0/
+ *
+ *  SPDX-License-Identifier: EPL-2.0
+ *
+ *  Contributors:
+ *     Julian Honnen <julian.honnen@vector.com> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.pde.internal.core.builders;
+
+import java.util.*;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.pde.internal.core.PDECore;
+
+public class IncrementalErrorReporter {
+
+	private final IResource fResource;
+	private final Collection<VirtualMarker> fReportedMarkers = new ArrayList<>();
+	private int fErrorCount;
+
+	public IncrementalErrorReporter(IResource file) {
+		fResource = file;
+	}
+
+	public VirtualMarker addMarker(String message, int lineNumber, int severity, int problemID, String category) {
+
+		if (lineNumber == -1) {
+			lineNumber = 1;
+		}
+
+		if (severity == IMarker.SEVERITY_ERROR) {
+			fErrorCount++;
+		}
+
+		VirtualMarker marker = new VirtualMarker();
+		marker.setAttribute(PDEMarkerFactory.PROBLEM_ID, problemID);
+		marker.setAttribute(PDEMarkerFactory.CAT_ID, category);
+		marker.setAttribute(IMarker.MESSAGE, message);
+		marker.setAttribute(IMarker.SEVERITY, severity);
+		marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
+
+		fReportedMarkers.add(marker);
+
+		return marker;
+	}
+
+	public void applyMarkers() {
+		IMarker[] existingMarkers;
+		try {
+			// This seem to be for compatibility with some legacy code,
+			// PDE builders don't create markers with this type anymore
+			fResource.deleteMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
+			existingMarkers = fResource.findMarkers(PDEMarkerFactory.MARKER_ID, false, IResource.DEPTH_ZERO);
+		} catch (CoreException e) {
+			PDECore.logException(e);
+			// If we can't read existing, let delete them before we create new
+			existingMarkers = new IMarker[0];
+			try {
+				fResource.deleteMarkers(PDEMarkerFactory.MARKER_ID, false, IResource.DEPTH_ZERO);
+			} catch (CoreException e1) {
+				PDECore.logException(e1);
+			}
+		}
+
+		// iterate over existing markers to check which are resolved now
+		for (IMarker marker : existingMarkers) {
+			boolean resolved = true;
+			Map<String, Object> existingAttributes = null;
+
+			// Iterate over new markers to filter out all we already know
+			for (Iterator<VirtualMarker> it = fReportedMarkers.iterator(); it.hasNext();) {
+				VirtualMarker reportedMarker = it.next();
+				if (existingAttributes == null) {
+					try {
+						existingAttributes = marker.getAttributes();
+					} catch (Exception e) {
+						PDECore.logException(e);
+						// assume the marker is not accessible, can be deleted
+						break;
+					}
+				}
+				// Same marker is found, no need to create again
+				if (reportedMarker.getAttributes().equals(existingAttributes)) {
+					resolved = false;
+					it.remove();
+					break;
+				}
+			}
+
+			// The marker was not reported again, the old one can be deleted
+			if (resolved) {
+				try {
+					marker.delete();
+				} catch (CoreException e) {
+					PDECore.logException(e);
+				}
+			}
+		}
+
+		// Create only new markers
+		for (VirtualMarker reportedMarker : fReportedMarkers) {
+			try {
+				fResource.createMarker(PDEMarkerFactory.MARKER_ID).setAttributes(reportedMarker.getAttributes());
+			} catch (CoreException e) {
+				PDECore.logException(e);
+			}
+		}
+	}
+
+	public int getErrorCount() {
+		return fErrorCount;
+	}
+
+	public static class VirtualMarker {
+
+		private final Map<String, Object> fAttributes = new HashMap<>();
+
+		public void setAttribute(String key, Object value) {
+			fAttributes.put(key, value);
+		}
+
+		public Map<String, Object> getAttributes() {
+			return fAttributes;
+		}
+
+		@Override
+		public String toString() {
+			StringBuilder builder = new StringBuilder();
+			builder.append("VirtualMarker ["); //$NON-NLS-1$
+			if (fAttributes != null) {
+				builder.append("attributes="); //$NON-NLS-1$
+				builder.append(fAttributes);
+			}
+			builder.append("]"); //$NON-NLS-1$
+			return builder.toString();
+		}
+
+	}
+
+}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/JarManifestErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/JarManifestErrorReporter.java
index e627aea..1d5625d 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/JarManifestErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/JarManifestErrorReporter.java
@@ -18,13 +18,13 @@
 import java.util.HashMap;
 import java.util.Map;
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.runtime.*;
 import org.eclipse.jface.text.*;
 import org.eclipse.osgi.util.ManifestElement;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.internal.core.PDECore;
 import org.eclipse.pde.internal.core.PDECoreMessages;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 
 public class JarManifestErrorReporter extends ErrorReporter {
 	/**
@@ -187,15 +187,13 @@
 			}
 			if (header != null) {
 				// lingering header, line not terminated
-				IMarker marker = report(PDECoreMessages.BundleErrorReporter_noLineTermination, l, CompilerFlags.ERROR, PDEMarkerFactory.M_NO_LINE_TERMINATION, PDEMarkerFactory.CAT_FATAL);
-				try {
-					if (marker != null) {
-						// Check whether last line is purely whitespace, and add this information to the marker.
-						IRegion lineInfo = document.getLineInformation(document.getNumberOfLines() - 1);
-						String line = document.get(lineInfo.getOffset(), lineInfo.getLength());
-						marker.setAttribute(PDEMarkerFactory.ATTR_HAS_CONTENT, !line.matches("\\s+")); //$NON-NLS-1$
-					}
-				} catch (CoreException e) {
+				VirtualMarker marker = report(PDECoreMessages.BundleErrorReporter_noLineTermination, l, CompilerFlags.ERROR, PDEMarkerFactory.M_NO_LINE_TERMINATION, PDEMarkerFactory.CAT_FATAL);
+				if (marker != null) {
+					// Check whether last line is purely whitespace, and add
+					// this information to the marker.
+					IRegion lineInfo = document.getLineInformation(document.getNumberOfLines() - 1);
+					String line = document.get(lineInfo.getOffset(), lineInfo.getLength());
+					marker.setAttribute(PDEMarkerFactory.ATTR_HAS_CONTENT, !line.matches("\\s+")); //$NON-NLS-1$
 				}
 				return;
 			}
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ManifestErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ManifestErrorReporter.java
index a82f08a..012dd36 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ManifestErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/ManifestErrorReporter.java
@@ -17,16 +17,15 @@
 import java.net.URL;
 import java.util.ArrayList;
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.internal.core.PDECoreMessages;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.eclipse.pde.internal.core.util.IdUtil;
 import org.eclipse.pde.internal.core.util.VersionUtil;
 import org.w3c.dom.*;
 
-public class ManifestErrorReporter extends XMLErrorReporter {
+public abstract class ManifestErrorReporter extends XMLErrorReporter {
 
 	/**
 	 * @param file
@@ -38,17 +37,17 @@
 	protected void reportIllegalElement(Element element, int severity) {
 		Node parent = element.getParentNode();
 		if (parent == null || parent instanceof org.w3c.dom.Document) {
-			IMarker marker = report(PDECoreMessages.Builders_Manifest_illegalRoot, getLine(element), severity, PDEMarkerFactory.CAT_FATAL);
+			VirtualMarker marker = report(PDECoreMessages.Builders_Manifest_illegalRoot, getLine(element), severity, PDEMarkerFactory.CAT_FATAL);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,CompilerFlags.P_UNKNOWN_ELEMENT);
 		} else {
-			IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_child, new String[] {element.getNodeName(), parent.getNodeName()}), getLine(element), severity, PDEMarkerFactory.P_ILLEGAL_XML_NODE, element, null, PDEMarkerFactory.CAT_FATAL);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_child, new String[] {element.getNodeName(), parent.getNodeName()}), getLine(element), severity, PDEMarkerFactory.P_ILLEGAL_XML_NODE, element, null, PDEMarkerFactory.CAT_FATAL);
 			addMarkerAttribute(marker,PDEMarkerFactory.compilerKey,CompilerFlags.P_UNKNOWN_ELEMENT);
 		}
 	}
 
 	protected void reportMissingRequiredAttribute(Element element, String attName, int severity) {
 		String message = NLS.bind(PDECoreMessages.Builders_Manifest_missingRequired, (new String[] {attName, element.getNodeName()})); //
-		IMarker marker = report(message, getLine(element), severity, PDEMarkerFactory.CAT_FATAL);
+		VirtualMarker marker = report(message, getLine(element), severity, PDEMarkerFactory.CAT_FATAL);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_NO_REQUIRED_ATT);
 	}
 
@@ -63,7 +62,7 @@
 
 	protected void reportUnknownAttribute(Element element, String attName, int severity) {
 		String message = NLS.bind(PDECoreMessages.Builders_Manifest_attribute, attName);
-		IMarker marker = report(message, getLine(element, attName), severity, PDEMarkerFactory.P_ILLEGAL_XML_NODE, element, attName, PDEMarkerFactory.CAT_OTHER);
+		VirtualMarker marker = report(message, getLine(element, attName), severity, PDEMarkerFactory.P_ILLEGAL_XML_NODE, element, attName, PDEMarkerFactory.CAT_OTHER);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNKNOWN_ATTRIBUTE);
 	}
 
@@ -180,16 +179,13 @@
 	protected void reportDeprecatedAttribute(Element element, Attr attr) {
 		int severity = CompilerFlags.getFlag(fProject, CompilerFlags.P_DEPRECATED);
 		if (severity != CompilerFlags.IGNORE) {
-			IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_attribute, attr.getName()), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_DEPRECATION);
+			VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_attribute, attr.getName()), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_DEPRECATION);
 			addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 		}
 	}
-	protected void addMarkerAttribute(IMarker marker, String attr, String value) {
+	protected void addMarkerAttribute(VirtualMarker marker, String attr, String value) {
 		if (marker != null)
-			try {
-				marker.setAttribute(attr, value);
-			} catch (CoreException e) {
-			}
+			marker.setAttribute(attr, value);
 	}
 
 }
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/PluginBaseErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/PluginBaseErrorReporter.java
index 4868088..40f7cfe 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/PluginBaseErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/PluginBaseErrorReporter.java
@@ -14,12 +14,12 @@
 package org.eclipse.pde.internal.core.builders;
 
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.core.plugin.IPluginModelBase;
 import org.eclipse.pde.core.plugin.PluginRegistry;
 import org.eclipse.pde.internal.core.PDECoreMessages;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.w3c.dom.*;
 
 public abstract class PluginBaseErrorReporter extends ExtensionsErrorReporter {
@@ -29,7 +29,7 @@
 	}
 
 	@Override
-	public void validateContent(IProgressMonitor monitor) {
+	public void validate(IProgressMonitor monitor) {
 		Element element = getDocumentRoot();
 		if (element == null)
 			return;
@@ -157,14 +157,14 @@
 		if (severity != CompilerFlags.IGNORE) {
 			IPluginModelBase model = PluginRegistry.findModel(attr.getValue());
 			if (model == null || !model.isEnabled()) {
-				IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_dependency, attr.getValue()), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_FATAL);
+				VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_dependency, attr.getValue()), getLine(element, attr.getName()), severity, PDEMarkerFactory.CAT_FATAL);
 				addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_UNRESOLVED_IMPORTS);
 			}
 		}
 	}
 
 	private void reportDeprecatedElement(Element element, int severity) {
-		IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_3_0, element.getNodeName()), getLine(element), severity, PDEMarkerFactory.CAT_DEPRECATION);
+		VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Manifest_deprecated_3_0, element.getNodeName()), getLine(element), severity, PDEMarkerFactory.CAT_DEPRECATION);
 		addMarkerAttribute(marker, PDEMarkerFactory.compilerKey, CompilerFlags.P_DEPRECATED);
 	}
 
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/SchemaErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/SchemaErrorReporter.java
index c648765..91211ca 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/SchemaErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/SchemaErrorReporter.java
@@ -18,11 +18,10 @@
 import java.net.URL;
 import java.util.*;
 import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.pde.internal.core.PDECoreMessages;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.eclipse.pde.internal.core.ischema.*;
 import org.eclipse.pde.internal.core.schema.IncludedSchemaDescriptor;
 import org.eclipse.pde.internal.core.schema.SchemaDescriptor;
@@ -90,7 +89,7 @@
 	}
 
 	@Override
-	public void validateContent(IProgressMonitor monitor) {
+	public void validate(IProgressMonitor monitor) {
 		List<String> elements = new ArrayList<>();
 		Element element = getDocumentRoot();
 		if (element != null) {
@@ -181,7 +180,7 @@
 								if (tagName.endsWith("/")) { //$NON-NLS-1$
 									tagName = getTagName(tagName.substring(0, tagName.length() - 1));
 									if (forbiddenEndTag(tagName)) {
-										IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Schema_forbiddenEndTag, tagName), lineNumber, flag, PDEMarkerFactory.CAT_OTHER);
+										VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Schema_forbiddenEndTag, tagName), lineNumber, flag, PDEMarkerFactory.CAT_OTHER);
 										addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.S_OPEN_TAGS);
 										errorReported = true;
 									}
@@ -202,7 +201,7 @@
 										}
 									}
 									if (stack.isEmpty() && !found) {
-										IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Schema_noMatchingStartTag, tagName), lineNumber, flag, PDEMarkerFactory.CAT_OTHER);
+										VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Schema_noMatchingStartTag, tagName), lineNumber, flag, PDEMarkerFactory.CAT_OTHER);
 										addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.S_OPEN_TAGS);
 										errorReported = true;
 									}
@@ -222,7 +221,7 @@
 					if (!stack.isEmpty()) {
 						StackEntry entry = stack.pop();
 						if (!optionalEndTag(entry.tag)) {
-							IMarker marker = report(NLS.bind(PDECoreMessages.Builders_Schema_noMatchingEndTag, entry.tag), entry.line, flag, PDEMarkerFactory.CAT_OTHER);
+							VirtualMarker marker = report(NLS.bind(PDECoreMessages.Builders_Schema_noMatchingEndTag, entry.tag), entry.line, flag, PDEMarkerFactory.CAT_OTHER);
 							addMarkerAttribute(marker, PDEMarkerFactory.compilerKey,  CompilerFlags.S_OPEN_TAGS);
 						}
 					}
@@ -232,12 +231,9 @@
 		}
 	}
 
-	private void addMarkerAttribute(IMarker marker, String attr, String value) {
+	private void addMarkerAttribute(VirtualMarker marker, String attr, String value) {
 		if (marker != null)
-			try {
-				marker.setAttribute(attr, value);
-			} catch (CoreException e) {
-			}
+			marker.setAttribute(attr, value);
 	}
 	private String getTagName(String text) {
 		StringTokenizer tokenizer = new StringTokenizer(text);
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteBuilder.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteBuilder.java
index 63c8b66..bfade45 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteBuilder.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteBuilder.java
@@ -88,7 +88,7 @@
 		UpdateSiteErrorReporter reporter = new UpdateSiteErrorReporter(file);
 		DefaultSAXParser.parse(file, reporter);
 		if (reporter.getErrorCount() == 0) {
-			reporter.validateContent(monitor);
+			reporter.validate(monitor);
 		}
 		monitor.subTask(PDECoreMessages.Builders_updating);
 		monitor.done();
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteErrorReporter.java
index ff62ca5..6e1dda3 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/UpdateSiteErrorReporter.java
@@ -26,7 +26,7 @@
 	}
 
 	@Override
-	public void validateContent(IProgressMonitor monitor) {
+	public void validate(IProgressMonitor monitor) {
 		fMonitor = monitor;
 		Element root = getDocumentRoot();
 		if (root == null)
diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/XMLErrorReporter.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/XMLErrorReporter.java
index ad14c81..79b6dca 100644
--- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/XMLErrorReporter.java
+++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/builders/XMLErrorReporter.java
@@ -24,12 +24,13 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jface.text.*;
 import org.eclipse.pde.internal.core.*;
+import org.eclipse.pde.internal.core.builders.IncrementalErrorReporter.VirtualMarker;
 import org.w3c.dom.*;
 import org.w3c.dom.Document;
 import org.xml.sax.*;
 import org.xml.sax.helpers.DefaultHandler;
 
-public class XMLErrorReporter extends DefaultHandler {
+public abstract class XMLErrorReporter extends DefaultHandler {
 
 	public static final char F_ATT_PREFIX = '@';
 	public static final char F_ATT_VALUE_PREFIX = '!';
@@ -48,9 +49,7 @@
 
 	protected IProject fProject;
 
-	private int fErrorCount;
-
-	private PDEMarkerFactory fMarkerFactory;
+	private final IncrementalErrorReporter fErrorReporter;
 
 	private org.w3c.dom.Document fXMLDocument;
 
@@ -71,6 +70,8 @@
 	private double fSchemaVersion = 2.1;
 
 	public XMLErrorReporter(IFile file) {
+		fErrorReporter = new IncrementalErrorReporter(file);
+
 		ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
 		try {
 			fFile = file;
@@ -81,7 +82,6 @@
 			fFindReplaceAdapter = new FindReplaceDocumentAdapter(fTextDocument);
 			fOffsetTable = new HashMap<>();
 			fElementStack = new Stack<>();
-			removeFileMarkers();
 		} catch (CoreException e) {
 			PDECore.log(e);
 		}
@@ -91,27 +91,8 @@
 		return fFile;
 	}
 
-	private IMarker addMarker(String message, int lineNumber, int severity, int fixId, String category) {
-		try {
-			IMarker marker = getMarkerFactory().createMarker(fFile, fixId, category);
-			marker.setAttribute(IMarker.MESSAGE, message);
-			marker.setAttribute(IMarker.SEVERITY, severity);
-			if (lineNumber == -1)
-				lineNumber = 1;
-			marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
-			if (severity == IMarker.SEVERITY_ERROR)
-				fErrorCount += 1;
-			return marker;
-		} catch (CoreException e) {
-			PDECore.logException(e);
-		}
-		return null;
-	}
-
-	private PDEMarkerFactory getMarkerFactory() {
-		if (fMarkerFactory == null)
-			fMarkerFactory = new PDEMarkerFactory();
-		return fMarkerFactory;
+	private VirtualMarker addMarker(String message, int lineNumber, int severity, int fixId, String category) {
+		return fErrorReporter.addMarker(message, lineNumber, severity, fixId, category);
 	}
 
 	private void addMarker(SAXParseException e, int severity) {
@@ -131,27 +112,15 @@
 	}
 
 	public int getErrorCount() {
-		return fErrorCount;
+		return fErrorReporter.getErrorCount();
 	}
 
-	private void removeFileMarkers() {
-		try {
-			fFile.deleteMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
-			fFile.deleteMarkers(PDEMarkerFactory.MARKER_ID, false, IResource.DEPTH_ZERO);
-		} catch (CoreException e) {
-			PDECore.logException(e);
-		}
-	}
-
-	public IMarker report(String message, int line, int severity, int fixId, Element element, String attrName,
+	public VirtualMarker report(String message, int line, int severity, int fixId, Element element, String attrName,
 			String category) {
-		IMarker marker = report(message, line, severity, fixId, category);
+		VirtualMarker marker = report(message, line, severity, fixId, category);
 		if (marker == null)
 			return null;
-		try {
-			marker.setAttribute(PDEMarkerFactory.MPK_LOCATION_PATH, generateLocationPath(element, attrName));
-		} catch (CoreException e) {
-		}
+		marker.setAttribute(PDEMarkerFactory.MPK_LOCATION_PATH, generateLocationPath(element, attrName));
 		return marker;
 	}
 
@@ -185,7 +154,7 @@
 		return sb.toString();
 	}
 
-	public IMarker report(String message, int line, int severity, int fixId, String category) {
+	public VirtualMarker report(String message, int line, int severity, int fixId, String category) {
 		if (severity == CompilerFlags.ERROR)
 			return addMarker(message, line, IMarker.SEVERITY_ERROR, fixId, category);
 		if (severity == CompilerFlags.WARNING)
@@ -193,7 +162,7 @@
 		return null;
 	}
 
-	public IMarker report(String message, int line, int severity, String category) {
+	public VirtualMarker report(String message, int line, int severity, String category) {
 		return report(message, line, severity, PDEMarkerFactory.M_ONLY_CONFIG_SEV, category);
 	}
 
@@ -392,10 +361,13 @@
 		return getLine(element);
 	}
 
-	public void validateContent(IProgressMonitor monitor) {
-
+	public final void validateContent(IProgressMonitor monitor) {
+		validate(monitor);
+		fErrorReporter.applyMarkers();
 	}
 
+	protected abstract void validate(IProgressMonitor monitor);
+
 	public Element getDocumentRoot() {
 		if (fRootElement != null)
 			fRootElement.normalize();
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/build/properties/BuildPropertiesValidationTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/build/properties/BuildPropertiesValidationTest.java
index db6af52..1bd05cf 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/build/properties/BuildPropertiesValidationTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/build/properties/BuildPropertiesValidationTest.java
@@ -13,13 +13,16 @@
  *******************************************************************************/
 package org.eclipse.pde.ui.tests.build.properties;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotEquals;
+
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.PropertyResourceBundle;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.pde.internal.core.builders.CompilerFlags;
+import org.eclipse.pde.internal.core.builders.PDEMarkerFactory;
 import org.osgi.service.prefs.BackingStoreException;
 
 /**
@@ -148,4 +151,23 @@
 			fail("Could not build the project '" + project.getName() + "'");
 		}
 	}
+
+	public void testIncrementalMarkers() throws Exception {
+		IProject project = findProject("org.eclipse.pde.tests.build.properties.1");
+		setPreferences(project, CompilerFlags.ERROR);
+		if (!buildProject(project)) {
+			fail("Could not build the project '" + project.getName() + "'");
+		}
+
+		IResource buildProperty = project.findMember("build.properties");
+		IMarker[] initialMarkers = buildProperty.findMarkers(PDEMarkerFactory.MARKER_ID, false, IResource.DEPTH_ZERO);
+		assertNotEquals(0, initialMarkers.length);
+
+		if (!buildProject(project)) {
+			fail("Could not build the project '" + project.getName() + "'");
+		}
+
+		IMarker[] markersAfterBuild = buildProperty.findMarkers(PDEMarkerFactory.MARKER_ID, false, IResource.DEPTH_ZERO);
+		assertArrayEquals("validation should not have recreated unchanged markers", initialMarkers, markersAfterBuild);
+	}
 }
diff --git a/ui/org.eclipse.pde.ui.tests/tests/build.properties/build.properties.tests.zip b/ui/org.eclipse.pde.ui.tests/tests/build.properties/build.properties.tests.zip
index 4e75d34..c156667 100644
--- a/ui/org.eclipse.pde.ui.tests/tests/build.properties/build.properties.tests.zip
+++ b/ui/org.eclipse.pde.ui.tests/tests/build.properties/build.properties.tests.zip
Binary files differ