/*******************************************************************************
* Copyright (c) 2007, 2008 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKind;
/**
* Represents a list of modifications to an AST node. If there are nested modifications
* to nodes introduced by insertions or replacements, these modifications are collected
* in separate modification maps. I.e. a modification map represents one level of
* modifications.
* @see ASTModificationStore
* @since 5.0
*/
public class ASTModificationMap {
private HashMap<IASTNode, List<ASTModification>> fModifications= new HashMap<IASTNode, List<ASTModification>>();
/**
* Adds a modification to this modification map.
*/
public void addModification(ASTModification mod) {
final IASTNode targetNode = mod.getKind() == ASTModification.ModificationKind.INSERT_BEFORE ?
mod.getTargetNode().getParent() : mod.getTargetNode();
List<ASTModification> mods= fModifications.get(targetNode);
if (mods == null || mods.isEmpty()) {
mods= new ArrayList<ASTModification>();
mods.add(mod);
fModifications.put(targetNode, mods);
} else {
switch (mod.getKind()) {
case REPLACE:
if (mods.get(mods.size() - 1).getKind() != ModificationKind.INSERT_BEFORE) {
throw new IllegalArgumentException("Attempt to replace a node that has been modified"); //$NON-NLS-1$
}
mods.add(mod);
break;
case APPEND_CHILD:
if (mods.get(mods.size() - 1).getKind() == ModificationKind.REPLACE) {
throw new IllegalArgumentException("Attempt to modify a node that has been replaced"); //$NON-NLS-1$
}
mods.add(mod);
break;
case INSERT_BEFORE:
int i;
for (i= mods.size(); --i >= 0;) {
if (mods.get(i).getKind() == ModificationKind.INSERT_BEFORE) {
break;
}
}
mods.add(i + 1, mod);
break;
}
}
}
/**
* Returns the list of modifications for a given node. The list can contain different
* modifications. It is guaranteed that INSERT_BEFORE modifications appear first. Furthermore,
* if there is a REPLACE modification the list will not contain any other REPLACE or
* APPEND_CHILD modifications.
* @return the modification list, which may be empty.
*/
public List<ASTModification> getModificationsForNode(IASTNode node) {
List<ASTModification> modList = fModifications.get(node);
if (modList == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(modList);
}
/**
* Returns the collection of nodes that are modified by this modification map.
*/
public Collection<IASTNode> getModifiedNodes() {
return Collections.unmodifiableCollection(fModifications.keySet());
}
}