Fix for Bug 331731 - Formatter fails silently on big Teams
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
index 3f03b6e..f07f838 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
@@ -22,6 +22,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PrecedenceDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TsuperReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.WithinStatement;
 
@@ -513,6 +514,9 @@
 	public void endVisit(BaseCallMessageSend messageSend, BlockScope scope) {
 		// do nothing by default
 	}
+	public void endVisit(PrecedenceDeclaration precedenceDeclaration, BlockScope scope) {
+		// do nothing by default	
+	}
 // SH et al}
 	public boolean visit(
     		AllocationExpression allocationExpression,
@@ -997,5 +1001,8 @@
     {
     	return true; // do nothing by default, keep traversing
     }
+    public boolean visit(PrecedenceDeclaration precedenceDeclaration, BlockScope scope) {
+    	return true; // do nothing by default, keep traversing
+    }
 // SH et al}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
index 3b56e46..df9414a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -97,7 +97,7 @@
     protected boolean _calloutSeen = false;
     protected boolean _callinSeen = false;
     // ... or the "precedence" keyword
-	protected boolean _precedenceSeen = false;
+	public boolean _precedenceSeen = false;
 
     // after a '.' even 'team' can be an identifier:
     private int _dotSeen = 0; // 0: no, 1: previos, 2: this token
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrecedenceDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrecedenceDeclaration.java
index 74b4d35..a4b8926 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrecedenceDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/ast/PrecedenceDeclaration.java
@@ -23,12 +23,14 @@
 import java.util.LinkedList;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
 import org.eclipse.jdt.internal.compiler.ast.NameReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
 import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
 import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
@@ -374,4 +376,15 @@
 		return output;
 	}
 
+	@Override
+	public void traverse(ASTVisitor visitor, BlockScope scope) {
+		if (visitor.visit(this, scope)) {
+			 if (this.bindingNames != null) {
+				 int len = this.bindingNames.length;
+				 for (int i=0; i<len; i++)
+					 this.bindingNames[i].traverse(visitor, scope);
+			 }
+		}
+		visitor.endVisit(this, scope);
+	}
 }
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
index d834f82..21f7e2d 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java
@@ -52,7 +52,6 @@
 import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.ContinueStatement;
-import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.DoStatement;
 import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
 import org.eclipse.jdt.internal.compiler.ast.EmptyStatement;
@@ -77,26 +76,27 @@
 import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
 import org.eclipse.jdt.internal.compiler.ast.MessageSend;
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NameReference;
 import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation;
-import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
-import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
-import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation;
 import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
 import org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression;
 import org.eclipse.jdt.internal.compiler.ast.OperatorIds;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.PostfixExpression;
 import org.eclipse.jdt.internal.compiler.ast.PrefixExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
 import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
 import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.Statement;
 import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
+import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation;
 import org.eclipse.jdt.internal.compiler.ast.SuperReference;
 import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
 import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement;
@@ -108,6 +108,7 @@
 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.ast.UnaryExpression;
+import org.eclipse.jdt.internal.compiler.ast.UnionTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.WhileStatement;
 import org.eclipse.jdt.internal.compiler.ast.Wildcard;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -132,6 +133,7 @@
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping;
+import org.eclipse.objectteams.otdt.internal.core.compiler.ast.PrecedenceDeclaration;
 import org.eclipse.objectteams.otdt.internal.core.compiler.ast.WithinStatement;
 import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer;
 import org.eclipse.text.edits.TextEdit;
@@ -387,12 +389,16 @@
 		TypeDeclaration type = typeCount == 0 ? null : typeDeclaration.memberTypes[typeIndex];
 		int typeStart = type == null ? Integer.MAX_VALUE : type.declarationSourceStart;
 	
-//{ObjectTeams: add AbstractMethodMappingDeclarations
+//{ObjectTeams: add AbstractMethodMappingDeclarations and PrecedenceDeclarations
 		int callinCalloutIndex = 0, callinCalloutCount = (typeDeclaration.callinCallouts == null) ? 0 : typeDeclaration.callinCallouts.length;
 		AbstractMethodMappingDeclaration callinCallout = callinCalloutCount == 0 ? null : typeDeclaration.callinCallouts[callinCalloutIndex];
 		int callinCalloutStart = callinCallout == null ? Integer.MAX_VALUE : callinCallout.sourceStart;
 
-		final int memberLength = fieldCount+methodCount+typeCount+callinCalloutCount;
+		int precedenceIndex = 0, precedenceCount = (typeDeclaration.precedences == null) ? 0 : typeDeclaration.precedences.length;
+		PrecedenceDeclaration precedenceDecl = precedenceCount == 0 ? null : typeDeclaration.precedences[precedenceIndex];
+		int precedenceStart = precedenceDecl == null ? Integer.MAX_VALUE : precedenceDecl.sourceStart;
+	
+		final int memberLength = fieldCount+methodCount+typeCount+callinCalloutCount+precedenceCount;
 /*orig: 
 		final int memberLength = fieldCount+methodCount+typeCount;
  :giro */
@@ -402,11 +408,11 @@
 			int index = 0;
 			int previousFieldStart = -1;
 			do {
-//{ObjectTeams: AbstractMethodMappingDeclarations
+//{ObjectTeams: AbstractMethodMappingDeclarations & PrecedenceDeclaration
 /*orig:	
 				if (fieldStart < methodStart && fieldStart < typeStart) {
  :giro */
-				if (fieldStart < methodStart && fieldStart < typeStart && fieldStart < callinCalloutStart) 
+				if (fieldStart < methodStart && fieldStart < typeStart && fieldStart < callinCalloutStart && fieldStart < precedenceStart) 
 				{
 //jsv}
 					if (field.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
@@ -442,8 +448,8 @@
 					} else {
 						fieldStart = Integer.MAX_VALUE;
 					}
-//{ObjectTeams: include AbstractMethodMappingDeclarations too
-				} else if (methodStart < fieldStart && methodStart < typeStart && methodStart < callinCalloutStart) 
+//{ObjectTeams: include AbstractMethodMappingDeclarations && PrecedenceDeclaration too
+				} else if (methodStart < fieldStart && methodStart < typeStart && methodStart < callinCalloutStart && methodStart < precedenceStart) 
 				{
 /*orig: 	
 				} else if (methodStart < fieldStart && methodStart < typeStart) {
@@ -458,8 +464,8 @@
 					} else {
 						methodStart = Integer.MAX_VALUE;
 					}
-//{ObjectTeams: include AbstractMethodMappingDeclarations, too				
-				} else if (callinCalloutStart < fieldStart && callinCalloutStart < typeStart && callinCalloutStart < methodStart) {
+//{ObjectTeams: include AbstractMethodMappingDeclarations and PrecedenceDeclaration, too
+				} else if (callinCalloutStart < fieldStart && callinCalloutStart < typeStart && callinCalloutStart < methodStart && callinCalloutStart < precedenceStart) {
 					// next member is a CallinMappingDeclaration or a CalloutMappingDeclaration
 					members[index++] = callinCallout;
 					if (++callinCalloutIndex < callinCalloutCount) { // find next callin/callout is any
@@ -467,6 +473,14 @@
 					} else {
 						callinCalloutStart = Integer.MAX_VALUE;
 					}
+				} else if (precedenceStart < fieldStart && precedenceStart < typeStart && precedenceStart < methodStart && precedenceStart < callinCalloutStart) {
+					// next member is a CallinMappingDeclaration or a CalloutMappingDeclaration
+					members[index++] = precedenceDecl;
+					if (++precedenceIndex < precedenceCount) { // find next precedence is any
+						precedenceStart = (precedenceDecl = typeDeclaration.precedences[precedenceIndex]).sourceStart;
+					} else {
+						precedenceStart = Integer.MAX_VALUE;
+					}
 //jsv}					
 				} else {
 					// next member is a type
@@ -484,7 +498,8 @@
 			} while ((fieldIndex < fieldCount) || 
 					(typeIndex < typeCount) || 
 					(methodIndex < methodCount) || 
-					(callinCalloutIndex < callinCalloutCount) );
+					(callinCalloutIndex < callinCalloutCount) ||
+					(precedenceIndex < precedenceCount));
 //jsv}
 
 			if (members.length != index) {
@@ -699,7 +714,44 @@
 		}
 		abstractMethodMappingDeclaration.traverse(this, scope);
 	}
-//jsv}
+
+	private void format(PrecedenceDeclaration precedenceDecl, ClassScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
+		if (isFirstClassBodyDeclaration) {
+			int newLinesBeforeFirstClassBodyDeclaration = this.preferences.blank_lines_before_first_class_body_declaration;
+			if (newLinesBeforeFirstClassBodyDeclaration > 0) {
+				this.scribe.printEmptyLines(newLinesBeforeFirstClassBodyDeclaration);
+			}
+		} else {
+			final int newLineBeforeChunk = isChunkStart ? this.preferences.blank_lines_before_new_chunk : 0;
+			if (newLineBeforeChunk > 0) {
+				this.scribe.printEmptyLines(newLineBeforeChunk);
+			}
+		}
+		final int newLinesBeforeMethod = this.preferences.blank_lines_before_method;
+		if (newLinesBeforeMethod > 0 && !isFirstClassBodyDeclaration) {
+			this.scribe.printEmptyLines(newLinesBeforeMethod);
+		} else if (this.scribe.line != 0 || this.scribe.column != 1) {
+			this.scribe.printNewLine();
+		}
+		this.scribe.printNextToken(TerminalTokens.TokenNameprecedence, true);
+		if (precedenceDecl.isAfter) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameafter, true);
+			this.scribe.space();
+		}
+		boolean firstTime = true;
+		for (NameReference name : precedenceDecl.bindingNames) {
+			if (!firstTime) {
+				this.scribe.printNextToken(TerminalTokens.TokenNameCOMMA, true);
+				this.scribe.printComment(CodeFormatter.K_UNKNOWN, Scribe.BASIC_TRAILING_COMMENT);
+				this.scribe.space();
+			}
+			firstTime = false;
+			name.traverse(this, (BlockScope)null);
+		}		
+		this.scribe.printNextToken(TerminalTokens.TokenNameSEMICOLON, true);
+		this.scribe.printNewLine();
+	}
+//jsv+SH}
 
 	private void format(FieldDeclaration fieldDeclaration, ASTVisitor visitor, MethodScope scope, boolean isChunkStart, boolean isFirstClassBodyDeclaration) {
 		
@@ -2379,11 +2431,15 @@
 						} else if (member instanceof AbstractMethodDeclaration) {
 							isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_METHOD, i, this.scribe.scanner.currentPosition);
 							format((AbstractMethodDeclaration) member, typeDeclaration.scope, isChunkStart, i == 0);
-//{ObjectTeams: format for AbstractMethodMappingDeclaration
+//{ObjectTeams: format for AbstractMethodMappingDeclaration & PrecedenceDeclaration
 						} else if (member instanceof AbstractMethodMappingDeclaration) {
 							// TODO(jsv) use code styles for OT elements (not implemented yet, so we use a similar style)
 							isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_METHOD, i, this.scribe.scanner.currentPosition);
 							format((AbstractMethodMappingDeclaration) member, typeDeclaration.scope, isChunkStart, i == 0);
+						} else if (member instanceof PrecedenceDeclaration) {
+							// TODO(jsv) use code styles for OT elements (not implemented yet, so we use a similar style)
+							isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_METHOD, i, this.scribe.scanner.currentPosition);
+							format((PrecedenceDeclaration) member, typeDeclaration.scope, isChunkStart, i == 0);
 //jsv}
 						} else if (member instanceof TypeDeclaration) {
 							isChunkStart = memberAlignment.checkChunkStart(Alignment.CHUNK_TYPE, i, this.scribe.scanner.currentPosition);
@@ -6026,7 +6082,17 @@
 		
 		this.scribe.printComment();
 		
+		
 		int startLine = this.scribe.line;
+		if (callinMappingDeclaration.hasName()) {
+			this.scribe.printNextToken(TerminalTokens.TokenNameIdentifier, false);
+			this.scribe.printNextToken(TerminalTokens.TokenNameCOLON, true);
+			// FIXME(SH): configurable?
+			this.scribe.printNewLine();
+		}
+		this.scribe.printModifiers(callinMappingDeclaration.annotations, this, ICodeFormatterConstants.ANNOTATION_ON_METHOD);
+		// FIXME(SH): configurable?
+		this.scribe.printNewLine();
         MethodSpec roleMethodSpec = callinMappingDeclaration.roleMethodSpec;
         if (roleMethodSpec != null)
         {
@@ -6082,6 +6148,8 @@
 		
 		this.scribe.printComment();
 		
+		this.scribe.printModifiers(calloutMappingDeclaration.annotations, this, ICodeFormatterConstants.ANNOTATION_ON_METHOD);
+
 		int startLine = this.scribe.line;
 		MethodSpec roleMethodSpec = calloutMappingDeclaration.roleMethodSpec;
         if (roleMethodSpec != null)
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
index 22d8457..839eee9 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java
@@ -4902,8 +4902,14 @@
 	}
 
 	public void printNextToken(int expectedTokenType, boolean considerSpaceIfAny, int emptyLineRules) {
+//{ObjectTeams: save and restore some scanner state that will be killed by printComment:
+		boolean precedenceSeen = this.scanner._precedenceSeen;
+// orig:
 		// Set brace flag, it's useful for the scribe while preserving line breaks
 		printComment(CodeFormatter.K_UNKNOWN, NO_TRAILING_COMMENT, emptyLineRules);
+// :giro
+		this.scanner._precedenceSeen = precedenceSeen;
+// SH}
 		try {
 			this.currentToken = this.scanner.getNextToken();
 			if (expectedTokenType != this.currentToken) {