| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation and others. |
| * |
| * 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: |
| * IBM Corporation - initial API and implementation |
| * James Blackburn (Broadcom Corp.) - ongoing development |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427 |
| *******************************************************************************/ |
| package org.eclipse.core.internal.resources; |
| |
| import java.io.*; |
| import java.util.*; |
| import org.eclipse.core.internal.localstore.SafeChunkyInputStream; |
| import org.eclipse.core.internal.localstore.SafeFileInputStream; |
| import org.eclipse.core.internal.utils.Messages; |
| import org.eclipse.core.internal.utils.Policy; |
| import org.eclipse.core.internal.watson.*; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * A marker manager stores and retrieves markers on resources in the workspace. |
| */ |
| public class MarkerManager implements IManager { |
| |
| // singletons |
| private static final MarkerInfo[] NO_MARKER_INFO = new MarkerInfo[0]; |
| private static final IMarker[] NO_MARKERS = new IMarker[0]; |
| protected MarkerTypeDefinitionCache cache = new MarkerTypeDefinitionCache(); |
| private long changeId = 0; |
| protected Map<IPath, MarkerSet> currentDeltas = null; |
| protected final MarkerDeltaManager deltaManager = new MarkerDeltaManager(); |
| |
| protected Workspace workspace; |
| protected MarkerWriter writer = new MarkerWriter(this); |
| |
| /** |
| * Creates a new marker manager |
| */ |
| public MarkerManager(Workspace workspace) { |
| this.workspace = workspace; |
| } |
| |
| /** |
| * Adds the given markers to the given resource. |
| * |
| * @see IResource#createMarker(String) |
| */ |
| public void add(IResource resource, MarkerInfo newMarker) throws CoreException { |
| Resource target = (Resource) resource; |
| ResourceInfo info = workspace.getResourceInfo(target.getFullPath(), false, false); |
| target.checkExists(target.getFlags(info), false); |
| info = workspace.getResourceInfo(resource.getFullPath(), false, true); |
| // resource may have been deleted concurrently -- just bail out if this happens |
| if (info == null) |
| return; |
| // set the M_MARKERS_SNAP_DIRTY flag to indicate that this |
| // resource's markers have changed since the last snapshot |
| if (isPersistent(newMarker)) |
| info.set(ICoreConstants.M_MARKERS_SNAP_DIRTY); |
| // Concurrency: copy the marker set on modify |
| MarkerSet markers = info.getMarkers(true); |
| if (markers == null) |
| markers = new MarkerSet(1); |
| basicAdd(resource, markers, newMarker); |
| if (!markers.isEmpty()) |
| info.setMarkers(markers); |
| } |
| |
| /** |
| * Adds the new markers to the given set of markers. If added, the markers are |
| * associated with the specified resource.IMarkerDeltas for Added markers are |
| * generated. |
| */ |
| private void basicAdd(IResource resource, MarkerSet markers, MarkerInfo newMarker) throws CoreException { |
| // should always be a new marker. |
| if (newMarker.getId() != MarkerInfo.UNDEFINED_ID) { |
| String message = Messages.resources_changeInAdd; |
| throw new ResourceException( |
| new ResourceStatus(IResourceStatus.INTERNAL_ERROR, resource.getFullPath(), message)); |
| } |
| newMarker.setId(workspace.nextMarkerId()); |
| markers.add(newMarker); |
| IMarkerSetElement[] changes = new IMarkerSetElement[1]; |
| changes[0] = new MarkerDelta(IResourceDelta.ADDED, resource, newMarker); |
| changedMarkers(resource, changes); |
| } |
| |
| /** |
| * Returns the markers in the given set of markers which match the given type. |
| */ |
| protected MarkerInfo[] basicFindMatching(MarkerSet markers, String type, boolean includeSubtypes) { |
| int size = markers.size(); |
| if (size <= 0) |
| return NO_MARKER_INFO; |
| List<MarkerInfo> result = new ArrayList<>(size); |
| IMarkerSetElement[] elements = markers.elements(); |
| for (IMarkerSetElement element : elements) { |
| MarkerInfo marker = (MarkerInfo) element; |
| // if the type is null then we are looking for all types of markers |
| if (type == null) |
| result.add(marker); |
| else { |
| if (includeSubtypes) { |
| if (cache.isSubtype(marker.getType(), type)) |
| result.add(marker); |
| } else { |
| if (marker.getType().equals(type)) |
| result.add(marker); |
| } |
| } |
| } |
| size = result.size(); |
| if (size <= 0) |
| return NO_MARKER_INFO; |
| return result.toArray(new MarkerInfo[size]); |
| } |
| |
| protected int basicFindMaxSeverity(MarkerSet markers, String type, boolean includeSubtypes) { |
| int max = -1; |
| int size = markers.size(); |
| if (size <= 0) |
| return max; |
| IMarkerSetElement[] elements = markers.elements(); |
| for (IMarkerSetElement element : elements) { |
| MarkerInfo marker = (MarkerInfo) element; |
| // if the type is null then we are looking for all types of markers |
| if (type == null) |
| max = Math.max(max, getSeverity(marker)); |
| else { |
| if (includeSubtypes) { |
| if (cache.isSubtype(marker.getType(), type)) |
| max = Math.max(max, getSeverity(marker)); |
| } else { |
| if (marker.getType().equals(type)) |
| max = Math.max(max, getSeverity(marker)); |
| } |
| } |
| if (max >= IMarker.SEVERITY_ERROR) { |
| break; |
| } |
| } |
| return max; |
| } |
| |
| private int getSeverity(MarkerInfo marker) { |
| Object o = marker.getAttribute(IMarker.SEVERITY); |
| if (o instanceof Integer) { |
| Integer i = (Integer) o; |
| return i.intValue(); |
| } |
| return -1; |
| } |
| |
| /** |
| * Removes markers of the specified type from the given resource. Note: this |
| * method is protected to avoid creation of a synthetic accessor (it is called |
| * from an anonymous inner class). |
| */ |
| protected void basicRemoveMarkers(ResourceInfo info, IPathRequestor requestor, String type, |
| boolean includeSubtypes) { |
| MarkerSet markers = info.getMarkers(false); |
| if (markers == null) |
| return; |
| IMarkerSetElement[] matching; |
| IPath path; |
| if (type == null) { |
| // if the type is null, all markers are to be removed. |
| // now we need to crack open the tree |
| path = requestor.requestPath(); |
| info = workspace.getResourceInfo(path, false, true); |
| info.setMarkers(null); |
| matching = markers.elements(); |
| } else { |
| matching = basicFindMatching(markers, type, includeSubtypes); |
| // if none match, there is nothing to remove |
| if (matching.length == 0) |
| return; |
| // now we need to crack open the tree |
| path = requestor.requestPath(); |
| info = workspace.getResourceInfo(path, false, true); |
| // Concurrency: copy the marker set on modify |
| markers = info.getMarkers(true); |
| // remove all the matching markers and also the whole |
| // set if there are no remaining markers |
| if (markers.size() == matching.length) { |
| info.setMarkers(null); |
| } else { |
| markers.removeAll(matching); |
| info.setMarkers(markers); |
| } |
| } |
| info.set(ICoreConstants.M_MARKERS_SNAP_DIRTY); |
| IMarkerSetElement[] changes = new IMarkerSetElement[matching.length]; |
| IResource resource = workspace.getRoot().findMember(path); |
| for (int i = 0; i < matching.length; i++) |
| changes[i] = new MarkerDelta(IResourceDelta.REMOVED, resource, (MarkerInfo) matching[i]); |
| changedMarkers(resource, changes); |
| return; |
| } |
| |
| /** |
| * Adds the markers on the given target which match the specified type to the |
| * list. |
| */ |
| protected void buildMarkers(IMarkerSetElement[] markers, IPath path, int type, ArrayList<IMarker> list) { |
| if (markers.length == 0) |
| return; |
| IResource resource = workspace.newResource(path, type); |
| list.ensureCapacity(list.size() + markers.length); |
| for (IMarkerSetElement marker : markers) { |
| list.add(new Marker(resource, ((MarkerInfo) marker).getId())); |
| } |
| } |
| |
| /** |
| * Markers have changed on the given resource. Remember the changes for |
| * subsequent notification. |
| */ |
| protected void changedMarkers(IResource resource, IMarkerSetElement[] changes) { |
| if (changes == null || changes.length == 0) |
| return; |
| changeId++; |
| if (currentDeltas == null) |
| currentDeltas = deltaManager.newGeneration(changeId); |
| IPath path = resource.getFullPath(); |
| MarkerSet previousChanges = currentDeltas.get(path); |
| MarkerSet result = MarkerDelta.merge(previousChanges, changes); |
| if (result.size() == 0) |
| currentDeltas.remove(path); |
| else |
| currentDeltas.put(path, result); |
| ResourceInfo info = workspace.getResourceInfo(path, false, true); |
| if (info != null) |
| info.incrementMarkerGenerationCount(); |
| } |
| |
| /** |
| * Returns the marker with the given id or <code>null</code> if none is found. |
| */ |
| public IMarker findMarker(IResource resource, long id) { |
| MarkerInfo info = findMarkerInfo(resource, id); |
| return info == null ? null : new Marker(resource, info.getId()); |
| } |
| |
| /** |
| * Returns the marker with the given id or <code>null</code> if none is found. |
| */ |
| public MarkerInfo findMarkerInfo(IResource resource, long id) { |
| ResourceInfo info = workspace.getResourceInfo(resource.getFullPath(), false, false); |
| if (info == null) |
| return null; |
| MarkerSet markers = info.getMarkers(false); |
| if (markers == null) |
| return null; |
| return (MarkerInfo) markers.get(id); |
| } |
| |
| /** |
| * Returns all markers of the specified type on the given target, with option to |
| * search the target's children. Passing <code>null</code> for the type |
| * specifies a match for all types (i.e., <code>null</code> is a wildcard. |
| */ |
| public IMarker[] findMarkers(IResource target, final String type, final boolean includeSubtypes, int depth) { |
| ArrayList<IMarker> result = new ArrayList<>(); |
| doFindMarkers(target, result, type, includeSubtypes, depth); |
| if (result.isEmpty()) |
| return NO_MARKERS; |
| return result.toArray(new IMarker[result.size()]); |
| } |
| |
| /** |
| * Fills the provided list with all markers of the specified type on the given |
| * target, with option to search the target's children. Passing |
| * <code>null</code> for the type specifies a match for all types (i.e., |
| * <code>null</code> is a wildcard. |
| */ |
| public void doFindMarkers(IResource target, ArrayList<IMarker> result, final String type, |
| final boolean includeSubtypes, int depth) { |
| // optimize the deep searches with an element tree visitor |
| if (depth == IResource.DEPTH_INFINITE && target.getType() != IResource.FILE) |
| visitorFindMarkers(target.getFullPath(), result, type, includeSubtypes); |
| else |
| recursiveFindMarkers(target.getFullPath(), result, type, includeSubtypes, depth); |
| } |
| |
| /** |
| * Finds the max severity across all problem markers on the given target, with |
| * option to search the target's children. |
| */ |
| public int findMaxProblemSeverity(IResource target, String type, boolean includeSubtypes, int depth) { |
| // optimize the deep searches with an element tree visitor |
| if (depth == IResource.DEPTH_INFINITE && target.getType() != IResource.FILE) |
| return visitorFindMaxSeverity(target.getFullPath(), type, includeSubtypes); |
| return recursiveFindMaxSeverity(target.getFullPath(), type, includeSubtypes, depth); |
| } |
| |
| public long getChangeId() { |
| return changeId; |
| } |
| |
| /** |
| * Returns the map of all marker deltas since the given change Id. |
| */ |
| public Map<IPath, MarkerSet> getMarkerDeltas(long startChangeId) { |
| return deltaManager.assembleDeltas(startChangeId); |
| } |
| |
| /** |
| * Returns true if this manager has a marker delta record for the given marker |
| * id, and false otherwise. |
| */ |
| boolean hasDelta(IPath path, long id) { |
| if (currentDeltas == null) |
| return false; |
| MarkerSet set = currentDeltas.get(path); |
| if (set == null) |
| return false; |
| return set.get(id) != null; |
| } |
| |
| /** |
| * Returns true if the given marker is persistent, and false otherwise. |
| */ |
| public boolean isPersistent(MarkerInfo info) { |
| if (!cache.isPersistent(info.getType())) |
| return false; |
| Object isTransient = info.getAttribute(IMarker.TRANSIENT); |
| return isTransient == null || !(isTransient instanceof Boolean) || !((Boolean) isTransient).booleanValue(); |
| } |
| |
| /** |
| * Returns true if the given marker type is persistent, and false otherwise. |
| */ |
| public boolean isPersistentType(String type) { |
| return cache.isPersistent(type); |
| } |
| |
| /** |
| * Returns true if <code>type</code> is a sub type of <code>superType</code>. |
| */ |
| public boolean isSubtype(String type, String superType) { |
| return cache.isSubtype(type, superType); |
| } |
| |
| public void moved(final IResource source, final IResource destination, int depth) throws CoreException { |
| final int count = destination.getFullPath().segmentCount(); |
| |
| // we removed from the source and added to the destination |
| IResourceVisitor visitor = resource -> { |
| Resource r = (Resource) resource; |
| ResourceInfo info = r.getResourceInfo(false, true); |
| MarkerSet markers = info.getMarkers(false); |
| if (markers == null) |
| return true; |
| info.set(ICoreConstants.M_MARKERS_SNAP_DIRTY); |
| IMarkerSetElement[] removed = new IMarkerSetElement[markers.size()]; |
| IMarkerSetElement[] added = new IMarkerSetElement[markers.size()]; |
| IPath path = resource.getFullPath().removeFirstSegments(count); |
| path = source.getFullPath().append(path); |
| IResource sourceChild = workspace.newResource(path, resource.getType()); |
| IMarkerSetElement[] elements = markers.elements(); |
| for (int i = 0; i < elements.length; i++) { |
| // calculate the ADDED delta |
| MarkerInfo markerInfo = (MarkerInfo) elements[i]; |
| MarkerDelta delta = new MarkerDelta(IResourceDelta.ADDED, resource, markerInfo); |
| added[i] = delta; |
| // calculate the REMOVED delta |
| delta = new MarkerDelta(IResourceDelta.REMOVED, sourceChild, markerInfo); |
| removed[i] = delta; |
| } |
| changedMarkers(resource, added); |
| changedMarkers(sourceChild, removed); |
| return true; |
| }; |
| destination.accept(visitor, depth, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| } |
| |
| /** |
| * Adds the markers for a subtree of resources to the list. |
| */ |
| private void recursiveFindMarkers(IPath path, ArrayList<IMarker> list, String type, boolean includeSubtypes, |
| int depth) { |
| ResourceInfo info = workspace.getResourceInfo(path, false, false); |
| if (info == null) |
| return; |
| MarkerSet markers = info.getMarkers(false); |
| |
| // add the matching markers for this resource |
| if (markers != null) { |
| IMarkerSetElement[] matching; |
| if (type == null) |
| matching = markers.elements(); |
| else |
| matching = basicFindMatching(markers, type, includeSubtypes); |
| buildMarkers(matching, path, info.getType(), list); |
| } |
| |
| // recurse |
| if (depth == IResource.DEPTH_ZERO || info.getType() == IResource.FILE) |
| return; |
| if (depth == IResource.DEPTH_ONE) |
| depth = IResource.DEPTH_ZERO; |
| for (IPath child : workspace.getElementTree().getChildren(path)) { |
| recursiveFindMarkers(child, list, type, includeSubtypes, depth); |
| } |
| } |
| |
| /** |
| * Finds the max severity across problem markers for a subtree of resources. |
| */ |
| private int recursiveFindMaxSeverity(IPath path, String type, boolean includeSubtypes, int depth) { |
| ResourceInfo info = workspace.getResourceInfo(path, false, false); |
| if (info == null) |
| return -1; |
| MarkerSet markers = info.getMarkers(false); |
| |
| // add the matching markers for this resource |
| int max = -1; |
| if (markers != null) { |
| max = basicFindMaxSeverity(markers, type, includeSubtypes); |
| if (max >= IMarker.SEVERITY_ERROR) { |
| return max; |
| } |
| } |
| |
| // recurse |
| if (depth == IResource.DEPTH_ZERO || info.getType() == IResource.FILE) |
| return max; |
| if (depth == IResource.DEPTH_ONE) |
| depth = IResource.DEPTH_ZERO; |
| for (IPath child : workspace.getElementTree().getChildren(path)) { |
| max = Math.max(max, recursiveFindMaxSeverity(child, type, includeSubtypes, depth)); |
| if (max >= IMarker.SEVERITY_ERROR) { |
| break; |
| } |
| } |
| return max; |
| } |
| |
| /** |
| * Adds the markers for a subtree of resources to the list. |
| */ |
| private void recursiveRemoveMarkers(final IPath path, String type, boolean includeSubtypes, int depth) { |
| ResourceInfo info = workspace.getResourceInfo(path, false, false); |
| if (info == null) // phantoms don't have markers |
| return; |
| IPathRequestor requestor = new IPathRequestor() { |
| @Override |
| public String requestName() { |
| return path.lastSegment(); |
| } |
| |
| @Override |
| public IPath requestPath() { |
| return path; |
| } |
| }; |
| basicRemoveMarkers(info, requestor, type, includeSubtypes); |
| // recurse |
| if (depth == IResource.DEPTH_ZERO || info.getType() == IResource.FILE) |
| return; |
| if (depth == IResource.DEPTH_ONE) |
| depth = IResource.DEPTH_ZERO; |
| for (IPath child : workspace.getElementTree().getChildren(path)) { |
| recursiveRemoveMarkers(child, type, includeSubtypes, depth); |
| } |
| } |
| |
| /** |
| * Removes the specified marker |
| */ |
| public void removeMarker(IResource resource, long id) { |
| MarkerInfo markerInfo = findMarkerInfo(resource, id); |
| if (markerInfo == null) |
| return; |
| ResourceInfo info = ((Workspace) resource.getWorkspace()).getResourceInfo(resource.getFullPath(), false, true); |
| // Concurrency: copy the marker set on modify |
| MarkerSet markers = info.getMarkers(true); |
| int size = markers.size(); |
| markers.remove(markerInfo); |
| // if that was the last marker remove the set to save space. |
| info.setMarkers(markers.size() == 0 ? null : markers); |
| // if we actually did remove a marker, post a delta for the change. |
| if (markers.size() != size) { |
| if (isPersistent(markerInfo)) |
| info.set(ICoreConstants.M_MARKERS_SNAP_DIRTY); |
| IMarkerSetElement[] change = new IMarkerSetElement[] { |
| new MarkerDelta(IResourceDelta.REMOVED, resource, markerInfo) }; |
| changedMarkers(resource, change); |
| } |
| } |
| |
| /** |
| * Remove all markers for the given resource to the specified depth. |
| */ |
| public void removeMarkers(IResource resource, int depth) { |
| removeMarkers(resource, null, false, depth); |
| } |
| |
| /** |
| * Remove all markers with the given type from the node at the given path. |
| * Passing <code>null</code> for the type specifies a match for all types (i.e., |
| * <code>null</code> is a wildcard. |
| */ |
| public void removeMarkers(IResource target, final String type, final boolean includeSubtypes, int depth) { |
| if (depth == IResource.DEPTH_INFINITE && target.getType() != IResource.FILE) |
| visitorRemoveMarkers(target.getFullPath(), type, includeSubtypes); |
| else |
| recursiveRemoveMarkers(target.getFullPath(), type, includeSubtypes, depth); |
| } |
| |
| /** |
| * Reset the marker deltas up to but not including the given start Id. |
| */ |
| public void resetMarkerDeltas(long startId) { |
| currentDeltas = null; |
| deltaManager.resetDeltas(startId); |
| } |
| |
| public void restore(IResource resource, boolean generateDeltas, IProgressMonitor monitor) throws CoreException { |
| // first try and load the last saved file, then apply the snapshots |
| restoreFromSave(resource, generateDeltas); |
| restoreFromSnap(resource); |
| } |
| |
| protected void restoreFromSave(IResource resource, boolean generateDeltas) throws CoreException { |
| IPath sourceLocation = workspace.getMetaArea().getMarkersLocationFor(resource); |
| IPath tempLocation = workspace.getMetaArea().getBackupLocationFor(sourceLocation); |
| java.io.File sourceFile = new java.io.File(sourceLocation.toOSString()); |
| java.io.File tempFile = new java.io.File(tempLocation.toOSString()); |
| if (!sourceFile.exists() && !tempFile.exists()) |
| return; |
| try (DataInputStream input = new DataInputStream( |
| new SafeFileInputStream(sourceLocation.toOSString(), tempLocation.toOSString()))) { |
| MarkerReader reader = new MarkerReader(workspace); |
| reader.read(input, generateDeltas); |
| } catch (Exception e) { |
| // don't let runtime exceptions such as ArrayIndexOutOfBounds prevent startup |
| String msg = NLS.bind(Messages.resources_readMeta, sourceLocation); |
| throw new ResourceException(IResourceStatus.FAILED_READ_METADATA, sourceLocation, msg, e); |
| } |
| } |
| |
| protected void restoreFromSnap(IResource resource) { |
| IPath sourceLocation = workspace.getMetaArea().getMarkersSnapshotLocationFor(resource); |
| if (!sourceLocation.toFile().exists()) |
| return; |
| try (DataInputStream input = new DataInputStream(new SafeChunkyInputStream(sourceLocation.toFile()))) { |
| MarkerSnapshotReader reader = new MarkerSnapshotReader(workspace); |
| while (true) |
| reader.read(input); |
| } catch (EOFException eof) { |
| // ignore end of file |
| } catch (Exception e) { |
| // only log the exception, we should not fail restoring the snapshot |
| String msg = NLS.bind(Messages.resources_readMeta, sourceLocation); |
| Policy.log(new ResourceStatus(IResourceStatus.FAILED_READ_METADATA, sourceLocation, msg, e)); |
| } |
| } |
| |
| public void save(ResourceInfo info, IPathRequestor requestor, DataOutputStream output, List<String> list) |
| throws IOException { |
| writer.save(info, requestor, output, list); |
| } |
| |
| @Override |
| public void shutdown(IProgressMonitor monitor) { |
| // do nothing |
| } |
| |
| public void snap(ResourceInfo info, IPathRequestor requestor, DataOutputStream output) throws IOException { |
| writer.snap(info, requestor, output); |
| } |
| |
| @Override |
| public void startup(IProgressMonitor monitor) { |
| // do nothing |
| } |
| |
| /** |
| * Adds the markers for a subtree of resources to the list. |
| */ |
| private void visitorFindMarkers(IPath path, final ArrayList<IMarker> list, final String type, |
| final boolean includeSubtypes) { |
| IElementContentVisitor visitor = (tree, requestor, elementContents) -> { |
| ResourceInfo info = (ResourceInfo) elementContents; |
| if (info == null) |
| return false; |
| MarkerSet markers = info.getMarkers(false); |
| |
| // add the matching markers for this resource |
| if (markers != null) { |
| IMarkerSetElement[] matching; |
| if (type == null) |
| matching = markers.elements(); |
| else |
| matching = basicFindMatching(markers, type, includeSubtypes); |
| buildMarkers(matching, requestor.requestPath(), info.getType(), list); |
| } |
| return true; |
| }; |
| new ElementTreeIterator(workspace.getElementTree(), path).iterate(visitor); |
| } |
| |
| /** |
| * Finds the max severity across problem markers for a subtree of resources. |
| */ |
| private int visitorFindMaxSeverity(IPath path, final String type, final boolean includeSubtypes) { |
| class MaxSeverityVisitor implements IElementContentVisitor { |
| int max = -1; |
| |
| @Override |
| public boolean visitElement(ElementTree tree, IPathRequestor requestor, Object elementContents) { |
| // bail if an earlier sibling already hit the max |
| if (max >= IMarker.SEVERITY_ERROR) { |
| return false; |
| } |
| ResourceInfo info = (ResourceInfo) elementContents; |
| if (info == null) |
| return false; |
| MarkerSet markers = info.getMarkers(false); |
| |
| // add the matching markers for this resource |
| if (markers != null) { |
| max = Math.max(max, basicFindMaxSeverity(markers, type, includeSubtypes)); |
| } |
| return max < IMarker.SEVERITY_ERROR; |
| } |
| } |
| MaxSeverityVisitor visitor = new MaxSeverityVisitor(); |
| new ElementTreeIterator(workspace.getElementTree(), path).iterate(visitor); |
| return visitor.max; |
| } |
| |
| /** |
| * Adds the markers for a subtree of resources to the list. |
| */ |
| private void visitorRemoveMarkers(IPath path, final String type, final boolean includeSubtypes) { |
| IElementContentVisitor visitor = (tree, requestor, elementContents) -> { |
| ResourceInfo info = (ResourceInfo) elementContents; |
| if (info == null) |
| return false; |
| basicRemoveMarkers(info, requestor, type, includeSubtypes); |
| return true; |
| }; |
| new ElementTreeIterator(workspace.getElementTree(), path).iterate(visitor); |
| } |
| } |