Bug 562723 - Added support for noexcept in the formatter

Change-Id: I021934657842868c196320f4e126217ab799c07c
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
index 08f8b00..f7f0294 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java
@@ -129,6 +129,7 @@
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
@@ -340,12 +341,16 @@
 				token = peekNextToken();
 				needSpace = true;
 			}
-			if (token == Token.t_throw || token == Token.tIDENTIFIER) {
+			if (token == Token.t_noexcept || token == Token.t_throw || token == Token.tIDENTIFIER) {
 				if (node instanceof ICPPASTFunctionDeclarator) {
 					final IASTTypeId[] exceptionSpecification = ((ICPPASTFunctionDeclarator) node)
 							.getExceptionSpecification();
 					if (exceptionSpecification != null && token == Token.t_throw)
 						formatExceptionSpecification(exceptionSpecification);
+					final ICPPASTExpression noexceptExpression = ((ICPPASTFunctionDeclarator) node)
+							.getNoexceptExpression();
+					if (noexceptExpression != null && token == Token.t_noexcept)
+						formatExceptionSpecification(noexceptExpression);
 				}
 				if (peekNextToken() == Token.tIDENTIFIER) {
 					Alignment alignment = scribe.createAlignment(Alignment.TRAILING_TEXT, Alignment.M_COMPACT_SPLIT, 1,
@@ -1672,6 +1677,38 @@
 		}
 	}
 
+	private void formatExceptionSpecification(final ICPPASTExpression noexceptSpecification) {
+		if (noexceptSpecification != null && noexceptSpecification != ICPPASTFunctionDeclarator.NOEXCEPT_DEFAULT) {
+			Alignment alignment = scribe.createAlignment(Alignment.EXCEPTION_SPECIFICATION,
+					preferences.alignment_for_throws_clause_in_method_declaration, 1, getCurrentPosition());
+
+			scribe.enterAlignment(alignment);
+			boolean ok = false;
+			do {
+				try {
+					scribe.alignFragment(alignment, 0);
+					scribe.printNextToken(Token.t_noexcept, true);
+					scribe.printNextToken(Token.tLPAREN,
+							preferences.insert_space_before_opening_paren_in_exception_specification);
+					if (preferences.insert_space_after_opening_paren_in_exception_specification) {
+						scribe.space();
+					}
+					noexceptSpecification.accept(this);
+					if (peekNextToken() == Token.tRPAREN) {
+						scribe.printNextToken(Token.tRPAREN,
+								preferences.insert_space_before_closing_paren_in_exception_specification);
+					}
+					ok = true;
+				} catch (AlignmentException e) {
+					scribe.redoAlignment(e);
+				}
+			} while (!ok);
+			scribe.exitAlignment(alignment, true);
+		} else {
+			scribe.printNextToken(Token.t_noexcept, true);
+		}
+	}
+
 	private boolean skipConstVolatileRestrict(boolean spaceBefore) {
 		return skipTokenWhile(token -> token == Token.t_const || token == Token.t_volatile || token == Token.t_restrict,
 				spaceBefore);
@@ -3106,6 +3143,15 @@
 				operand.accept(this);
 			}
 			break;
+		case IASTUnaryExpression.op_noexcept:
+			scribe.printNextToken(Token.t_noexcept, scribe.printComment());
+			if (operand != null) {
+				if (peekNextToken() != Token.tLPAREN) {
+					scribe.space();
+				}
+				operand.accept(this);
+			}
+			break;
 		case IASTUnaryExpression.op_typeid:
 			scribe.printNextToken(Token.t_typeid, scribe.printComment());
 			if (peekNextToken() != Token.tLPAREN) {
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/SimpleScanner.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/SimpleScanner.java
index f04a4cd..fa140ed 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/SimpleScanner.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/SimpleScanner.java
@@ -947,6 +947,7 @@
 		fgKeywords.put("while", Integer.valueOf(Token.t_while)); //$NON-NLS-1$
 		fgKeywords.put("xor", Integer.valueOf(Token.t_xor)); //$NON-NLS-1$
 		fgKeywords.put("xor_eq", Integer.valueOf(Token.t_xor_eq)); //$NON-NLS-1$
+		fgKeywords.put("noexcept", Integer.valueOf(Token.t_noexcept)); //$NON-NLS-1$
 
 		// additional java keywords
 		fgKeywords.put("abstract", Integer.valueOf(Token.t_abstract)); //$NON-NLS-1$
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/Token.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/Token.java
index e77cf85..d40fa16 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/Token.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/scanner/Token.java
@@ -510,4 +510,5 @@
 	static public final int t_transient = 215;
 	static public final int t_native = 216;
 	static public final int t_constexpr = 5400;
+	static public final int t_noexcept = 5401;
 }
diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
index c72f0b7..b850037 100644
--- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
+++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java
@@ -4790,4 +4790,28 @@
 				CCorePlugin.INSERT);
 		assertFormatterResult();
 	}
+
+	//class Foo {
+	//public:
+	//	void bar() noexcept
+	//	{
+	//	}
+	//	void baz() noexcept(false){
+	//	}
+	//	void biz() noexcept(noexcept(false)){
+	//	}
+	//};
+
+	//class Foo {
+	//public:
+	//	void bar() noexcept {
+	//	}
+	//	void baz() noexcept (false) {
+	//	}
+	//	void biz() noexcept (noexcept(false)) {
+	//	}
+	//};
+	public void testNoexcept_Bug562723() throws Exception {
+		assertFormatterResult();
+	}
 }