org.eclipse.jdt.internal.core.JavaElementDelta Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2017 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
* Vladimir Piskarev - Building large Java element deltas is really slow - https://bugs.eclipse.org/443928
* Vladimir Piskarev - F_CONTENT sometimes lost when merging deltas - https://bugs.eclipse.org/520336
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.jdt.core.IClasspathAttributeDelta;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.dom.CompilationUnit;
/**
* @see IJavaElementDelta
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class JavaElementDelta extends SimpleDelta implements IJavaElementDelta {
/**
* @see #getAffectedChildren()
*/
IJavaElementDelta[] affectedChildren = EMPTY_DELTA;
/*
* The AST created during the last reconcile operation.
* Non-null only iff:
* - in a POST_RECONCILE event
* - an AST was requested during the last reconcile operation
* - the changed element is an ICompilationUnit in working copy mode
*/
CompilationUnit ast = null;
/*
* The element that this delta describes the change to.
*/
IJavaElement changedElement;
/**
* Collection of resource deltas that correspond to non java resources deltas.
*/
IResourceDelta[] resourceDeltas = null;
/**
* Counter of resource deltas
*/
int resourceDeltasCounter;
/**
* @see #getMovedFromElement()
*/
IJavaElement movedFromHandle = null;
/**
* @see #getMovedToElement()
*/
IJavaElement movedToHandle = null;
IJavaElementDelta[] annotationDeltas = EMPTY_DELTA;
/**
* Empty array of IJavaElementDelta
*/
static IJavaElementDelta[] EMPTY_DELTA= new IJavaElementDelta[] {};
/**
* Child index is needed iff affectedChildren.length >= NEED_CHILD_INDEX
*/
static int NEED_CHILD_INDEX = 3;
/**
* On-demand index into affectedChildren
*/
Map childIndex;
public boolean ignoreFromTests = false;
private List attributeDeltas;
/**
* The delta key
*/
protected static class Key {
public final IJavaElement element;
public Key(IJavaElement element) {
this.element = element;
}
@Override
public int hashCode() {
return this.element.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Key))
return false;
return equalsAndSameParent(this.element, ((Key) obj).element);
}
}
/**
* Creates the root delta. To create the nested delta
* hierarchies use the following convenience methods. The root
* delta can be created at any level (for example: project, package root,
* package fragment...).
*
* added(IJavaElement)
* changed(IJavaElement)
* moved(IJavaElement, IJavaElement)
* removed(IJavaElement)
* renamed(IJavaElement, IJavaElement)
*
*/
public JavaElementDelta(IJavaElement element) {
this.changedElement = element;
this.attributeDeltas = null;
}
/**
* Adds the child delta to the collection of affected children. If the
* child is already in the collection, walk down the hierarchy.
*/
protected void addAffectedChild(JavaElementDelta child) {
switch (this.kind) {
case ADDED:
case REMOVED:
// no need to add a child if this parent is added or removed
return;
case CHANGED:
this.changeFlags |= F_CHILDREN;
break;
default:
this.kind = CHANGED;
this.changeFlags |= F_CHILDREN;
}
// if a child delta is added to a compilation unit delta or below,
// it's a fine grained delta
if (this.changedElement.getElementType() >= IJavaElement.COMPILATION_UNIT) {
fineGrained();
}
Key childKey = new Key(child.getElement());
Integer existingChildIndex = getChildIndex(childKey);
if (existingChildIndex == null) { //new affected child
addNewChild(child);
} else {
JavaElementDelta existingChild = (JavaElementDelta) this.affectedChildren[existingChildIndex];
switch (existingChild.getKind()) {
case ADDED:
switch (child.getKind()) {
case ADDED: // child was added then added -> it is added
case CHANGED: // child was added then changed -> it is added
return;
case REMOVED: // child was added then removed -> noop
removeExistingChild(childKey, existingChildIndex);
return;
}
break;
case REMOVED:
switch (child.getKind()) {
case ADDED: // child was removed then added -> it is changed
child.kind = CHANGED;
this.affectedChildren[existingChildIndex] = child;
return;
case CHANGED: // child was removed then changed -> it is removed
case REMOVED: // child was removed then removed -> it is removed
return;
}
break;
case CHANGED:
switch (child.getKind()) {
case ADDED: // child was changed then added -> it is added
case REMOVED: // child was changed then removed -> it is removed
this.affectedChildren[existingChildIndex] = child;
return;
case CHANGED: // child was changed then changed -> it is changed
IJavaElementDelta[] children = child.getAffectedChildren();
for (int i = 0; i < children.length; i++) {
JavaElementDelta childsChild = (JavaElementDelta) children[i];
existingChild.addAffectedChild(childsChild);
}
// update flags
int flags = child.changeFlags;
// case of fine grained delta (existing child) and delta coming from
// DeltaProcessor (child): ensure F_CONTENT is not propagated from child
if ((existingChild.changeFlags & F_FINE_GRAINED) != 0 && (flags & F_FINE_GRAINED) == 0) {
flags &= ~F_CONTENT;
}
existingChild.changeFlags |= flags;
// add the non-java resource deltas if needed
// note that the child delta always takes precedence over this existing child delta
// as non-java resource deltas are always created last (by the DeltaProcessor)
IResourceDelta[] resDeltas = child.getResourceDeltas();
if (resDeltas != null) {
existingChild.resourceDeltas = resDeltas;
existingChild.resourceDeltasCounter = child.resourceDeltasCounter;
}
return;
}
break;
default:
// unknown -> existing child becomes the child with the existing child's flags
int flags = existingChild.getFlags();
this.affectedChildren[existingChildIndex] = child;
child.changeFlags |= flags;
}
}
}
/**
* Creates the nested deltas resulting from an add operation.
* Convenience method for creating add deltas.
* The constructor should be used to create the root delta
* and then an add operation should call this method.
*/
public void added(IJavaElement element) {
added(element, 0);
}
public void added(IJavaElement element, int flags) {
JavaElementDelta addedDelta = new JavaElementDelta(element);
addedDelta.added();
addedDelta.changeFlags |= flags;
insertDeltaTree(element, addedDelta);
}
/**
* Adds the new child delta to the collection of affected children.
*/
protected void addNewChild(JavaElementDelta child) {
this.affectedChildren = growAndAddToArray(this.affectedChildren, child);
if (this.childIndex != null) {
this.childIndex.put(new Key(child.getElement()), this.affectedChildren.length - 1);
}
}
/**
* Adds the child delta to the collection of affected children. If the
* child is already in the collection, walk down the hierarchy.
*/
protected void addResourceDelta(IResourceDelta child) {
switch (this.kind) {
case ADDED:
case REMOVED:
// no need to add a child if this parent is added or removed
return;
case CHANGED:
this.changeFlags |= F_CONTENT;
break;
default:
this.kind = CHANGED;
this.changeFlags |= F_CONTENT;
}
if (this.resourceDeltas == null) {
this.resourceDeltas = new IResourceDelta[5];
this.resourceDeltas[this.resourceDeltasCounter++] = child;
return;
}
if (this.resourceDeltas.length == this.resourceDeltasCounter) {
// need a resize
System.arraycopy(this.resourceDeltas, 0, (this.resourceDeltas = new IResourceDelta[this.resourceDeltasCounter * 2]), 0, this.resourceDeltasCounter);
}
this.resourceDeltas[this.resourceDeltasCounter++] = child;
}
/**
* Creates the nested deltas resulting from a change operation.
* Convenience method for creating change deltas.
* The constructor should be used to create the root delta
* and then a change operation should call this method.
*/
public JavaElementDelta changed(IJavaElement element, int changeFlag) {
JavaElementDelta changedDelta = new JavaElementDelta(element);
changedDelta.changed(changeFlag);
insertDeltaTree(element, changedDelta);
return changedDelta;
}
/*
* Records the last changed AST .
*/
public void changedAST(CompilationUnit changedAST) {
this.ast = changedAST;
changed(F_AST_AFFECTED);
}
/**
* Clears the collection of affected children.
*/
protected void clearAffectedChildren() {
this.affectedChildren = EMPTY_DELTA;
this.childIndex = null;
}
/**
* Mark this delta as a content changed delta.
*/
public void contentChanged() {
this.changeFlags |= F_CONTENT;
}
/**
* Creates the nested deltas for a closed element.
*/
public void closed(IJavaElement element) {
JavaElementDelta delta = new JavaElementDelta(element);
delta.changed(F_CLOSED);
insertDeltaTree(element, delta);
}
/**
* Creates the nested delta deltas based on the affected element
* its delta, and the root of this delta tree. Returns the root
* of the created delta tree.
*/
protected JavaElementDelta createDeltaTree(IJavaElement element, JavaElementDelta delta) {
JavaElementDelta childDelta = delta;
ArrayList ancestors= getAncestors(element);
if (ancestors == null) {
if (equalsAndSameParent(delta.getElement(), getElement())) { // handle case of two jars that can be equals but not in the same project
// the element being changed is the root element
this.kind= delta.kind;
this.changeFlags = delta.changeFlags;
this.movedToHandle = delta.movedToHandle;
this.movedFromHandle = delta.movedFromHandle;
}
} else {
for (int i = 0, size = ancestors.size(); i < size; i++) {
IJavaElement ancestor = (IJavaElement) ancestors.get(i);
JavaElementDelta ancestorDelta = new JavaElementDelta(ancestor);
ancestorDelta.addAffectedChild(childDelta);
childDelta = ancestorDelta;
}
}
return childDelta;
}
/**
* Returns whether the two java elements are equals and have the same parent.
*/
protected static boolean equalsAndSameParent(IJavaElement e1, IJavaElement e2) {
IJavaElement parent1;
return e1.equals(e2) && ((parent1 = e1.getParent()) != null) && parent1.equals(e2.getParent());
}
/**
* Returns the JavaElementDelta
for the given element
* in the delta tree, or null, if no delta for the given element is found.
*/
protected JavaElementDelta find(IJavaElement e) {
if (equalsAndSameParent(getElement(), e)) // handle case of two jars that can be equals but not in the same project
return this;
return findDescendant(new Key(e));
}
/**
* Returns the descendant delta for the given key, or null
,
* if no delta for the given key is found in the delta tree below this delta.
*/
protected JavaElementDelta findDescendant(Key key) {
if (this.affectedChildren.length == 0)
return null;
Integer index = getChildIndex(key);
if (index != null)
return (JavaElementDelta) this.affectedChildren[index];
for (IJavaElementDelta child : this.affectedChildren) {
JavaElementDelta delta = ((JavaElementDelta) child).findDescendant(key);
if (delta != null)
return delta;
}
return null;
}
/**
* Mark this delta as a fine-grained delta.
*/
public void fineGrained() {
changed(F_FINE_GRAINED);
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElementDelta[] getAddedChildren() {
return getChildrenOfType(ADDED);
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElementDelta[] getAffectedChildren() {
return this.affectedChildren;
}
/**
* Returns a collection of all the parents of this element up to (but
* not including) the root of this tree in bottom-up order. If the given
* element is not a descendant of the root of this tree, null
* is returned.
*/
private ArrayList getAncestors(IJavaElement element) {
IJavaElement parent = element.getParent();
if (parent == null) {
return null;
}
ArrayList parents = new ArrayList();
while (!parent.equals(this.changedElement)) {
parents.add(parent);
parent = parent.getParent();
if (parent == null) {
return null;
}
}
parents.trimToSize();
return parents;
}
@Override
public CompilationUnit getCompilationUnitAST() {
return this.ast;
}
@Override
public IJavaElementDelta[] getAnnotationDeltas() {
return this.annotationDeltas;
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElementDelta[] getChangedChildren() {
return getChildrenOfType(CHANGED);
}
/**
* Returns the index of the delta in the collection of affected children,
* or null
if the child delta for the given key is not found.
*/
protected Integer getChildIndex(Key key) {
int length = this.affectedChildren.length;
if (length < NEED_CHILD_INDEX) {
for (int i = 0; i < length; i++) {
if (equalsAndSameParent(key.element, this.affectedChildren[i].getElement())) {
return i;
}
}
return null;
}
if (this.childIndex == null) {
this.childIndex = new HashMap<>();
for (int i = 0; i < length; i++) {
this.childIndex.put(new Key(this.affectedChildren[i].getElement()), i);
}
}
return this.childIndex.get(key);
}
/**
* @see IJavaElementDelta
*/
protected IJavaElementDelta[] getChildrenOfType(int type) {
int length = this.affectedChildren.length;
if (length == 0) {
return new IJavaElementDelta[] {};
}
ArrayList children= new ArrayList(length);
for (int i = 0; i < length; i++) {
if (this.affectedChildren[i].getKind() == type) {
children.add(this.affectedChildren[i]);
}
}
IJavaElementDelta[] childrenOfType = new IJavaElementDelta[children.size()];
children.toArray(childrenOfType);
return childrenOfType;
}
/**
* Returns the delta for a given element. Only looks below this
* delta.
*/
protected JavaElementDelta getDeltaFor(IJavaElement element) {
return find(element);
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElement getElement() {
return this.changedElement;
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElement getMovedFromElement() {
return this.movedFromHandle;
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElement getMovedToElement() {
return this.movedToHandle;
}
/**
* @see IJavaElementDelta
*/
@Override
public IJavaElementDelta[] getRemovedChildren() {
return getChildrenOfType(REMOVED);
}
/**
* Return the collection of resource deltas. Return null if none.
*/
@Override
public IResourceDelta[] getResourceDeltas() {
if (this.resourceDeltas == null) return null;
if (this.resourceDeltas.length != this.resourceDeltasCounter) {
System.arraycopy(this.resourceDeltas, 0, this.resourceDeltas = new IResourceDelta[this.resourceDeltasCounter], 0, this.resourceDeltasCounter);
}
return this.resourceDeltas;
}
/**
* Adds the new element to a new array that contains all of the elements of the old array.
* Returns the new array.
*/
protected IJavaElementDelta[] growAndAddToArray(IJavaElementDelta[] array, IJavaElementDelta addition) {
IJavaElementDelta[] old = array;
array = new IJavaElementDelta[old.length + 1];
System.arraycopy(old, 0, array, 0, old.length);
array[old.length] = addition;
return array;
}
/**
* Creates the delta tree for the given element and delta, and then
* inserts the tree as an affected child of this node.
*/
protected void insertDeltaTree(IJavaElement element, JavaElementDelta delta) {
JavaElementDelta childDelta= createDeltaTree(element, delta);
if (!equalsAndSameParent(element, getElement())) { // handle case of two jars that can be equals but not in the same project
addAffectedChild(childDelta);
}
}
/**
* Creates the nested deltas resulting from an move operation.
* Convenience method for creating the "move from" delta.
* The constructor should be used to create the root delta
* and then the move operation should call this method.
*/
public void movedFrom(IJavaElement movedFromElement, IJavaElement movedToElement) {
JavaElementDelta removedDelta = new JavaElementDelta(movedFromElement);
removedDelta.kind = REMOVED;
removedDelta.changeFlags |= F_MOVED_TO;
removedDelta.movedToHandle = movedToElement;
insertDeltaTree(movedFromElement, removedDelta);
}
/**
* Creates the nested deltas resulting from an move operation.
* Convenience method for creating the "move to" delta.
* The constructor should be used to create the root delta
* and then the move operation should call this method.
*/
public void movedTo(IJavaElement movedToElement, IJavaElement movedFromElement) {
JavaElementDelta addedDelta = new JavaElementDelta(movedToElement);
addedDelta.kind = ADDED;
addedDelta.changeFlags |= F_MOVED_FROM;
addedDelta.movedFromHandle = movedFromElement;
insertDeltaTree(movedToElement, addedDelta);
}
/**
* Creates the nested deltas for an opened element.
*/
public void opened(IJavaElement element) {
JavaElementDelta delta = new JavaElementDelta(element);
delta.changed(F_OPENED);
insertDeltaTree(element, delta);
}
/**
* Removes the child delta from the collection of affected children.
*/
protected void removeAffectedChild(JavaElementDelta child) {
if (this.affectedChildren.length == 0)
return;
Key childKey = new Key(child.getElement());
Integer exisingChildIndex = getChildIndex(childKey);
if (exisingChildIndex != null) {
removeExistingChild(childKey, exisingChildIndex);
}
}
/**
* Removes the element from the array.
* Returns the a new array which has shrunk.
*/
protected IJavaElementDelta[] removeAndShrinkArray(IJavaElementDelta[] old, int index) {
IJavaElementDelta[] array = new IJavaElementDelta[old.length - 1];
if (index > 0)
System.arraycopy(old, 0, array, 0, index);
int rest = old.length - index - 1;
if (rest > 0)
System.arraycopy(old, index + 1, array, index, rest);
return array;
}
/**
* Creates the nested deltas resulting from an delete operation.
* Convenience method for creating removed deltas.
* The constructor should be used to create the root delta
* and then the delete operation should call this method.
*/
public void removed(IJavaElement element) {
removed(element, 0);
}
public void removed(IJavaElement element, int flags) {
JavaElementDelta removedDelta= new JavaElementDelta(element);
insertDeltaTree(element, removedDelta);
JavaElementDelta actualDelta = getDeltaFor(element);
if (actualDelta != null) {
actualDelta.removed();
actualDelta.changeFlags |= flags;
actualDelta.clearAffectedChildren();
}
}
/**
* Removes the existing child delta from the collection of affected children.
*/
protected void removeExistingChild(Key key, int index) {
this.affectedChildren = removeAndShrinkArray(this.affectedChildren, index);
if (this.childIndex != null) {
int length = this.affectedChildren.length;
if (length < NEED_CHILD_INDEX)
this.childIndex = null;
else {
this.childIndex.remove(key);
for (int i = index; i < length; i++) {
this.childIndex.put(new Key(this.affectedChildren[i].getElement()), i);
}
}
}
}
/**
* Creates the nested deltas resulting from a change operation.
* Convenience method for creating change deltas.
* The constructor should be used to create the root delta
* and then a change operation should call this method.
*/
public void sourceAttached(IJavaElement element) {
JavaElementDelta attachedDelta = new JavaElementDelta(element);
attachedDelta.changed(F_SOURCEATTACHED);
insertDeltaTree(element, attachedDelta);
}
/**
* Creates the nested deltas resulting from a change operation.
* Convenience method for creating change deltas.
* The constructor should be used to create the root delta
* and then a change operation should call this method.
*/
public void sourceDetached(IJavaElement element) {
JavaElementDelta detachedDelta = new JavaElementDelta(element);
detachedDelta.changed(F_SOURCEDETACHED);
insertDeltaTree(element, detachedDelta);
}
/**
* Returns a string representation of this delta's
* structure suitable for debug purposes.
*
* @see #toString()
*/
public String toDebugString(int depth) {
StringBuilder buffer = new StringBuilder();
for (int i= 0; i < depth; i++) {
buffer.append('\t');
}
buffer.append(((JavaElement)getElement()).toDebugString());
toDebugString(buffer);
IJavaElementDelta[] children = getAffectedChildren();
if (children != null) {
for (int i = 0; i < children.length; ++i) {
buffer.append("\n"); //$NON-NLS-1$
buffer.append(((JavaElementDelta) children[i]).toDebugString(depth + 1));
}
}
for (int i = 0; i < this.resourceDeltasCounter; i++) {
buffer.append("\n");//$NON-NLS-1$
for (int j = 0; j < depth+1; j++) {
buffer.append('\t');
}
IResourceDelta resourceDelta = this.resourceDeltas[i];
buffer.append(resourceDelta.toString());
buffer.append("["); //$NON-NLS-1$
switch (resourceDelta.getKind()) {
case IResourceDelta.ADDED :
buffer.append('+');
break;
case IResourceDelta.REMOVED :
buffer.append('-');
break;
case IResourceDelta.CHANGED :
buffer.append('*');
break;
default :
buffer.append('?');
break;
}
buffer.append("]"); //$NON-NLS-1$
}
IJavaElementDelta[] annotations = getAnnotationDeltas();
if (annotations != null) {
for (int i = 0; i < annotations.length; ++i) {
buffer.append("\n"); //$NON-NLS-1$
buffer.append(((JavaElementDelta) annotations[i]).toDebugString(depth + 1));
}
}
IClasspathAttributeDelta[] attributes = getClasspathAttributeDeltas();
for (IClasspathAttributeDelta delta : attributes) {
buffer.append("\n");//$NON-NLS-1$
for (int j = 0; j < depth+1; j++) {
buffer.append('\t');
}
buffer.append(delta.toString());
}
return buffer.toString();
}
@Override
protected boolean toDebugString(StringBuilder buffer, int flags) {
boolean prev = super.toDebugString(buffer, flags);
if ((flags & IJavaElementDelta.F_CHILDREN) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CHILDREN"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_CONTENT) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CONTENT"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_MOVED_FROM) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("MOVED_FROM(" + ((JavaElement)getMovedFromElement()).toStringWithAncestors() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
prev = true;
}
if ((flags & IJavaElementDelta.F_MOVED_TO) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("MOVED_TO(" + ((JavaElement)getMovedToElement()).toStringWithAncestors() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
prev = true;
}
if ((flags & IJavaElementDelta.F_ADDED_TO_CLASSPATH) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("ADDED TO CLASSPATH"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("REMOVED FROM CLASSPATH"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_REORDER) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("REORDERED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("ARCHIVE CONTENT CHANGED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_SOURCEATTACHED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("SOURCE ATTACHED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_SOURCEDETACHED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("SOURCE DETACHED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_FINE_GRAINED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("FINE GRAINED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_PRIMARY_WORKING_COPY) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("PRIMARY WORKING COPY"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("RAW CLASSPATH CHANGED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("RESOLVED CLASSPATH CHANGED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_PRIMARY_RESOURCE) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("PRIMARY RESOURCE"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_OPENED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("OPENED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_CLOSED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CLOSED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_AST_AFFECTED) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("AST AFFECTED"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_CATEGORIES) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CATEGORIES"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_ANNOTATIONS) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("ANNOTATIONS"); //$NON-NLS-1$
prev = true;
}
if ((flags & IJavaElementDelta.F_CLASSPATH_ATTRIBUTES) != 0) {
if (prev)
buffer.append(" | "); //$NON-NLS-1$
buffer.append("CLASSPATH ATTRIBUTES"); //$NON-NLS-1$
prev = true;
}
return prev;
}
/**
* Returns a string representation of this delta's
* structure suitable for debug purposes.
*/
@Override
public String toString() {
return toDebugString(0);
}
void addAttributeDelta(IClasspathAttributeDelta attributeDelta) {
if (this.attributeDeltas == null) {
this.attributeDeltas = new ArrayList<>();
}
this.attributeDeltas.add(attributeDelta);
}
@Override
public IClasspathAttributeDelta[] getClasspathAttributeDeltas() {
if (this.attributeDeltas == null) {
return new IClasspathAttributeDelta[] {};
}
return this.attributeDeltas.toArray(IClasspathAttributeDelta[]::new);
}
}