Test & fix for Bug  313804 -  [dom] [assist] add support for "precedence after" in DOM and quickfix
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index 5a516d2..04ad4fd 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -3619,6 +3619,8 @@
 		for (org.eclipse.jdt.internal.compiler.ast.NameReference nameRef: aPrecedence.bindingNames) {
 			newPrecedence.elements().add(convert(nameRef));			
 		}
+		if (aPrecedence.isAfter)
+			newPrecedence.setAfter(true);
 		return newPrecedence;
 	}
 	
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
index 412ec41..2fb2bc9 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
@@ -2828,7 +2828,8 @@
 		}
 		PrecedenceDeclaration otherPrecedence = (PrecedenceDeclaration) other;
 
-		return safeSubtreeMatch(node.elements(), otherPrecedence.elements());
+		return     node.isAfter() == otherPrecedence.isAfter()
+				&& safeSubtreeMatch(node.elements(), otherPrecedence.elements());
 	}
 	
 	public boolean match(GuardPredicateDeclaration node, Object other) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java
index a5b868e..4efdd48 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java
@@ -36,12 +36,21 @@
 	public static final ChildListPropertyDescriptor ELEMENTS_PROPERTY =
 		new ChildListPropertyDescriptor(PrecedenceDeclaration.class, "elements", Name.class, NO_CYCLE_RISK);
 
+	/**
+	 * The "after" structural property of this node type.
+	 * @since 0.7.0
+	 */
+	@SuppressWarnings("nls")
+	public static final SimplePropertyDescriptor AFTER_PROPERTY = 
+		new SimplePropertyDescriptor(PrecedenceDeclaration.class, "after", boolean.class, MANDATORY); //$NON-NLS-1$
+
 	private static final List PROPERTY_DESCRIPTORS_3_0;
 	
 	static {
-		List propertyList = new ArrayList(2);
+		List propertyList = new ArrayList(3);
 		createPropertyList(PrecedenceDeclaration.class, propertyList);
 		addProperty(ELEMENTS_PROPERTY, propertyList);
+		addProperty(AFTER_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList);
 	}
 	
@@ -54,6 +63,11 @@
 	}
 	
 	ASTNode.NodeList _elements = new ASTNode.NodeList(ELEMENTS_PROPERTY);
+
+	/**
+	 * <code>true</code> for <code>precedence after</code>, else <code>false</code>.
+	 */
+	boolean isAfter = false;
 	
 	PrecedenceDeclaration(AST ast)
 	{
@@ -61,14 +75,28 @@
 	}
 	
      List internalGetChildListProperty(ChildListPropertyDescriptor property)
-    {
-		if (property == ELEMENTS_PROPERTY) {
-			return this._elements;
-		}
-		// allow default implementation to flag the error
-		return super.internalGetChildListProperty(property);
-    }
-     
+     {
+    	 if (property == ELEMENTS_PROPERTY) {
+    		 return this._elements;
+    	 }
+    	 // allow default implementation to flag the error
+    	 return super.internalGetChildListProperty(property);
+     }
+ 
+     @Override
+     boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) {
+    	 if (property == AFTER_PROPERTY) {
+    		 if (get) {
+    			 return isAfter();
+    		 } else {
+    			 setAfter(value);
+    			 return false;
+    		 }
+    	 }
+    	 // allow default implementation to flag the error
+    	 return super.internalGetSetBooleanProperty(property, get, value);
+     }
+
 	@Override
 	void accept0(ASTVisitor visitor) {
 		boolean visitChildren = visitor.visit(this);
@@ -98,6 +126,7 @@
 		PrecedenceDeclaration result = new PrecedenceDeclaration(target);
 		result.setSourceRange(this.getStartPosition(), this.getLength());
 		result.elements().addAll(ASTNode.copySubtrees(target, elements()));
+		result.setAfter(isAfter());
 		return result;
 	}
 
@@ -115,9 +144,25 @@
 		return this._elements;
 	}
 
+	/**
+	 * Mark whether this is a <code>precedence after</code> declaration. 
+	 */
+    public void setAfter(boolean isAfter) {
+		preValueChange(AFTER_PROPERTY);
+		this.isAfter = isAfter;
+		postValueChange(AFTER_PROPERTY);		
+    }
+
+	/**
+	 * Answer whether this is a <code>precedence after</code> declaration. 
+	 */
+    public boolean isAfter() {
+		return this.isAfter;
+    }
+
 	@Override
 	int memSize() {
-		return BASE_NODE_SIZE;
+		return BASE_NODE_SIZE + 1;
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
index 587384a..952692d 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2010 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -2096,7 +2096,27 @@
 		this.buffer.append("}\n");//$NON-NLS-1$
 		return false;
     } 
-//gbr}
+    
+	/*
+	 * @see ASTVisitor#visit(PrecedenceDeclaration)
+	 */
+	@SuppressWarnings("nls")
+	@Override
+	public boolean visit(PrecedenceDeclaration node)
+	{
+		buffer.append("precedence ");
+		if (node.isAfter())
+			buffer.append("after ");
+		for (Iterator iter = node.elements().iterator(); iter.hasNext();)  {
+            Name name = (Name) iter.next();
+			name.accept(this);
+			if (iter.hasNext())
+				buffer.append(", ");
+        }
+		buffer.append(";");
+		return false;
+	}
+//gbr+SH}
 	
 
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
index 20eefea..166a3c2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
@@ -3869,6 +3869,25 @@
 
 	@Override
 	public boolean visit(PrecedenceDeclaration node) {
+		// 'after' keyword:
+        boolean isAfter = ((Boolean) getOriginalValue(node, PrecedenceDeclaration.AFTER_PROPERTY)).booleanValue();
+        boolean invertAfter = isChanged(node, PrecedenceDeclaration.AFTER_PROPERTY);
+        if (invertAfter) {
+        	if (isAfter) {
+	        	try {
+	        		getScanner().readToToken(TerminalTokens.TokenNameafter, node.getStartPosition());
+	                int start= getScanner().getCurrentStartOffset();
+	                int end= getScanner().getCurrentEndOffset();
+	                doTextRemove(start, end-start+1, getEditGroup(node, PrecedenceDeclaration.AFTER_PROPERTY));
+	        	} catch (CoreException e) {
+	        		// ignore
+	        	}
+        	} else {
+        		int pos = node.getStartPosition()+"precedence".length(); //$NON-NLS-1$
+        		doTextInsert(pos, " after", getEditGroup(node, PrecedenceDeclaration.AFTER_PROPERTY)); //$NON-NLS-1$
+        	}
+        }
+        // elements
 		RewriteEvent precedencesEvent = getEvent(node, PrecedenceDeclaration.ELEMENTS_PROPERTY);
 		if (   precedencesEvent == null
 				|| precedencesEvent.getChangeKind() == RewriteEvent.UNCHANGED)
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
index 1f6d9a0..f6de71c 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
@@ -1741,6 +1741,8 @@
 	@Override
 	public boolean visit(PrecedenceDeclaration node) {
 		this.result.append("precedence ");
+		if (node.isAfter())
+			this.result.append("after ");
 		String sep = "";
 		for (Object element: node.elements()) {
 			this.result.append(sep);
diff --git a/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/text/correction/PrecedenceProposalSubProcessor.java b/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/text/correction/PrecedenceProposalSubProcessor.java
index 6d07e92..673b9cd 100644
--- a/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/text/correction/PrecedenceProposalSubProcessor.java
+++ b/plugins/org.eclipse.objectteams.otdt.jdt.ui/src/org/eclipse/objectteams/otdt/internal/ui/text/correction/PrecedenceProposalSubProcessor.java
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.IMethodMappingBinding;
+import org.eclipse.jdt.core.dom.Modifier;
+import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
 import org.eclipse.jdt.core.dom.Name;
 import org.eclipse.jdt.core.dom.PrecedenceDeclaration;
 import org.eclipse.jdt.core.dom.RoleTypeDeclaration;
@@ -181,6 +183,7 @@
 				Messages.format(CorrectionMessages.OTQuickfix_addbindingprecedence_description,
 						new String[]{roleType.getName().getIdentifier()}), 
 				callin1, callin2,
+				Modifier.isAfter(mapping1.getCallinModifier()),
 			 	name1 != null, name2 != null);
 
 		// create new, editable labels (linked to their mentioning within the precedence declaration):
@@ -221,6 +224,7 @@
 							new String[]{teamType.getName().getIdentifier()}), 
 					Signature.getSimpleName(problemArguments[0])+"."+callin1, //$NON-NLS-1$
 					Signature.getSimpleName(problemArguments[2])+"."+callin2, //$NON-NLS-1$
+					ModifierKeyword.AFTER_KEYWORD.toString().equals(problemArguments[4]),
 					false, false /* don't link labels */);
 	}
 
@@ -245,6 +249,7 @@
 							new String[]{teamType.getName().getIdentifier()}), 
 					Signature.getSimpleName(problemArguments[0]), 
 					Signature.getSimpleName(problemArguments[2]),
+					ModifierKeyword.AFTER_KEYWORD.toString().equals(problemArguments[4]),
 					false, false /* don't link labels */);
 	}
 
@@ -268,6 +273,7 @@
 			 									  		   String label,
 			 									  		   String callin1,
 			 									  		   String callin2,
+			 									  		   boolean isAfter,
 			 									  		   boolean linkLabel1,
 			 									  		   boolean linkLabel2) 
 	{
@@ -282,6 +288,8 @@
 		Name element2 = ast.newName(callin2);
 		newPrecedence.elements().add(element1);
 		newPrecedence.elements().add(element2);
+		if (isAfter)
+			newPrecedence.setAfter(true);
 		listRewrite.insertLast(newPrecedence, null);
 		MyLinkedCorrectionProposal proposal = new MyLinkedCorrectionProposal(
 						label,