From eff560c583f419d393c3c6d3d8ea2a0c28bd551e Mon Sep 17 00:00:00 2001 From: Marco Stornelli Date: Sat, 16 Mar 2019 15:33:43 +0100 Subject: [PATCH] Bug 299482 - New options to format linkage declarations Change-Id: Ied06beae3fc28255e2c1b6ba8b23fd69591e3d39 Signed-off-by: Marco Stornelli --- .../DefaultCodeFormatterConstants.java | 42 ++++++++++++++++ .../DefaultCodeFormatterOptions.java | 50 +++++++++++++++++++ .../formatter/CodeFormatterVisitor.java | 13 +++-- .../cdt/ui/tests/text/CodeFormatterTest.java | 40 +++++++++++++++ .../preferences/formatter/BracesTabPage.java | 7 ++- .../formatter/FormatterMessages.java | 8 +++ .../formatter/FormatterMessages.properties | 8 +++ .../formatter/IndentationTabPage.java | 9 +++- .../formatter/WhiteSpaceOptions.java | 32 ++++++++++++ .../cdt/internal/ui/text/CIndenter.java | 14 +++++- 10 files changed, 213 insertions(+), 10 deletions(-) diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java index d4bec0effd5..3dc6712fd06 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterConstants.java @@ -532,6 +532,22 @@ public class DefaultCodeFormatterConstants { public static final String FORMATTER_BRACE_POSITION_FOR_NAMESPACE_DECLARATION = CCorePlugin.PLUGIN_ID + ".formatter.brace_position_for_namespace_declaration"; //$NON-NLS-1$ + /** + *
+	 * FORMATTER / Option to position the braces of a linkage declaration
+	 *     - option id:         "org.eclipse.cdt.core.formatter.brace_position_for_linkage_declaration"
+	 *     - possible values:   { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP }
+	 *     - default:           END_OF_LINE
+	 * 
+ * @see #END_OF_LINE + * @see #NEXT_LINE + * @see #NEXT_LINE_SHIFTED + * @see #NEXT_LINE_ON_WRAP + * @since 6.7 + */ + public static final String FORMATTER_BRACE_POSITION_FOR_LINKAGE_DECLARATION = CCorePlugin.PLUGIN_ID + + ".formatter.brace_position_for_linkage_declaration"; //$NON-NLS-1$ + // /** // *
 	//	 * FORMATTER / Option to control whether blank lines are cleared inside comments
@@ -735,6 +751,19 @@ public class DefaultCodeFormatterConstants {
 	 */
 	public static final String FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_NAMESPACE_HEADER = CCorePlugin.PLUGIN_ID
 			+ ".formatter.indent_body_declarations_compare_to_namespace_header"; //$NON-NLS-1$
+	/**
+	 * 
+	 * FORMATTER / Option to indent body declarations compare to its enclosing linkage section
+	 *     - option id:         "org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_linkage"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           TRUE
+	 * 
+ * @see #TRUE + * @see #FALSE + * @since 6.7 + */ + public static final String FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_LINKAGE = CCorePlugin.PLUGIN_ID + + ".formatter.indent_body_declarations_compare_to_linkage"; //$NON-NLS-1$ /** *
 	 * FORMATTER / Option to indent breaks compare to cases
@@ -1999,6 +2028,19 @@ public class DefaultCodeFormatterConstants {
 	 */
 	public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_NAMESPACE_DECLARATION = CCorePlugin.PLUGIN_ID
 			+ ".formatter.insert_space_before_opening_brace_in_namespace_declaration"; //$NON-NLS-1$
+	/**
+	 * 
+	 * FORMATTER / Option to insert a space before the opening brace in a linkage declaration
+	 *     - option id:         "org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_linkage_declaration"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * 
+ * @see CCorePlugin#INSERT + * @see CCorePlugin#DO_NOT_INSERT + * @since 6.7 + */ + public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_LINKAGE_DECLARATION = CCorePlugin.PLUGIN_ID + + ".formatter.insert_space_before_opening_brace_in_linkage_declaration"; //$NON-NLS-1$ /** *
 	 * FORMATTER / Option to insert a space before the opening bracket
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
index 65d4101d39a..cb7b71516c3 100644
--- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/formatter/DefaultCodeFormatterOptions.java
@@ -88,6 +88,10 @@ public class DefaultCodeFormatterOptions {
 	public String brace_position_for_initializer_list;
 	public String brace_position_for_method_declaration;
 	public String brace_position_for_namespace_declaration;
+	/**
+	 * @since 6.7
+	 */
+	public String brace_position_for_linkage_declaration;
 	public String brace_position_for_switch;
 	public String brace_position_for_type_declaration;
 
@@ -122,6 +126,10 @@ public class DefaultCodeFormatterOptions {
 	public boolean indent_access_specifier_compare_to_type_header;
 	public int indent_access_specifier_extra_spaces;
 	public boolean indent_body_declarations_compare_to_namespace_header;
+	/**
+	 * @since 6.7
+	 */
+	public boolean indent_body_declarations_compare_to_linkage;
 	public boolean indent_declaration_compare_to_template_header;
 	public boolean indent_breaks_compare_to_cases;
 	public boolean indent_empty_lines;
@@ -227,6 +235,10 @@ public class DefaultCodeFormatterOptions {
 	public boolean insert_space_before_opening_brace_in_method_declaration;
 	public boolean insert_space_before_opening_brace_in_type_declaration;
 	public boolean insert_space_before_opening_brace_in_namespace_declaration;
+	/**
+	 * @since 6.7
+	 */
+	public boolean insert_space_before_opening_brace_in_linkage_declaration;
 	public boolean insert_space_before_opening_bracket;
 	public boolean insert_space_before_opening_paren_in_catch;
 	public boolean insert_space_before_opening_paren_in_for;
@@ -350,6 +362,8 @@ public class DefaultCodeFormatterOptions {
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_SWITCH, this.brace_position_for_switch);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_NAMESPACE_DECLARATION,
 				this.brace_position_for_namespace_declaration);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_LINKAGE_DECLARATION,
+				this.brace_position_for_linkage_declaration);
 		//		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_CLEAR_BLANK_LINES, this.comment_clear_blank_lines ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		//		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT, this.comment_format ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		//		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_FORMAT_HEADER, this.comment_format_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
@@ -391,6 +405,9 @@ public class DefaultCodeFormatterOptions {
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_NAMESPACE_HEADER,
 				this.indent_body_declarations_compare_to_namespace_header ? DefaultCodeFormatterConstants.TRUE
 						: DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_LINKAGE,
+				this.indent_body_declarations_compare_to_linkage ? DefaultCodeFormatterConstants.TRUE
+						: DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BREAKS_COMPARE_TO_CASES,
 				this.indent_breaks_compare_to_cases ? DefaultCodeFormatterConstants.TRUE
 						: DefaultCodeFormatterConstants.FALSE);
@@ -631,6 +648,9 @@ public class DefaultCodeFormatterOptions {
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_NAMESPACE_DECLARATION,
 				this.insert_space_before_opening_brace_in_namespace_declaration ? CCorePlugin.INSERT
 						: CCorePlugin.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_LINKAGE_DECLARATION,
+				this.insert_space_before_opening_brace_in_linkage_declaration ? CCorePlugin.INSERT
+						: CCorePlugin.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACKET,
 				this.insert_space_before_opening_bracket ? CCorePlugin.INSERT : CCorePlugin.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_CATCH,
@@ -1095,6 +1115,15 @@ public class DefaultCodeFormatterOptions {
 				this.brace_position_for_namespace_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 			}
 		}
+		final Object bracePositionForLinkageDeclarationOption = settings
+				.get(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_LINKAGE_DECLARATION);
+		if (bracePositionForLinkageDeclarationOption != null) {
+			try {
+				this.brace_position_for_linkage_declaration = (String) bracePositionForLinkageDeclarationOption;
+			} catch (ClassCastException e) {
+				this.brace_position_for_linkage_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
+			}
+		}
 		//		final Object commentClearBlankLinesOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_CLEAR_BLANK_LINES);
 		//		if (commentClearBlankLinesOption != null) {
 		//			this.comment_clear_blank_lines = DefaultCodeFormatterConstants.TRUE.equals(commentClearBlankLinesOption);
@@ -1225,6 +1254,12 @@ public class DefaultCodeFormatterOptions {
 			this.indent_body_declarations_compare_to_namespace_header = DefaultCodeFormatterConstants.TRUE
 					.equals(indentBodyDeclarationsCompareToNamespaceHeaderOption);
 		}
+		final Object indentBodyDeclarationsCompareToLinkageOption = settings
+				.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_LINKAGE);
+		if (indentBodyDeclarationsCompareToLinkageOption != null) {
+			this.indent_body_declarations_compare_to_linkage = DefaultCodeFormatterConstants.TRUE
+					.equals(indentBodyDeclarationsCompareToLinkageOption);
+		}
 		final Object indentBreaksCompareToCasesOption = settings
 				.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_BREAKS_COMPARE_TO_CASES);
 		if (indentBreaksCompareToCasesOption != null) {
@@ -1814,6 +1849,12 @@ public class DefaultCodeFormatterOptions {
 			this.insert_space_before_opening_brace_in_namespace_declaration = CCorePlugin.INSERT
 					.equals(insertSpaceBeforeOpeningBraceInNamespaceDeclarationOption);
 		}
+		final Object insertSpaceBeforeOpeningBraceInLinkageDeclarationOption = settings
+				.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_LINKAGE_DECLARATION);
+		if (insertSpaceBeforeOpeningBraceInLinkageDeclarationOption != null) {
+			this.insert_space_before_opening_brace_in_linkage_declaration = CCorePlugin.INSERT
+					.equals(insertSpaceBeforeOpeningBraceInLinkageDeclarationOption);
+		}
 		final Object insertSpaceBeforeOpeningBracketInArrayReferenceOption = settings
 				.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACKET);
 		if (insertSpaceBeforeOpeningBracketInArrayReferenceOption != null) {
@@ -2087,6 +2128,7 @@ public class DefaultCodeFormatterOptions {
 		this.brace_position_for_initializer_list = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_namespace_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_linkage_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_switch = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.comment_min_distance_between_code_and_line_comment = 1;
@@ -2108,6 +2150,7 @@ public class DefaultCodeFormatterOptions {
 		this.indent_statements_compare_to_block = true;
 		this.indent_statements_compare_to_body = true;
 		this.indent_body_declarations_compare_to_namespace_header = false;
+		this.indent_body_declarations_compare_to_linkage = false;
 		//		this.indent_body_declarations_compare_to_enum_declaration_header = true;
 		this.indent_body_declarations_compare_to_access_specifier = true;
 		this.indent_breaks_compare_to_cases = true;
@@ -2209,6 +2252,7 @@ public class DefaultCodeFormatterOptions {
 		this.insert_space_before_opening_brace_in_switch = true;
 		this.insert_space_before_opening_brace_in_type_declaration = true;
 		this.insert_space_before_opening_brace_in_namespace_declaration = true;
+		this.insert_space_before_opening_brace_in_linkage_declaration = true;
 		this.insert_space_before_opening_bracket = false;
 		this.insert_space_before_opening_paren_in_catch = true;
 		this.insert_space_before_opening_paren_in_exception_specification = true;
@@ -2294,11 +2338,13 @@ public class DefaultCodeFormatterOptions {
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
 		this.brace_position_for_namespace_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
+		this.brace_position_for_linkage_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
 		this.brace_position_for_switch = DefaultCodeFormatterConstants.NEXT_LINE;
 
 		this.indent_statements_compare_to_block = true;
 		this.indent_statements_compare_to_body = true;
 		this.indent_body_declarations_compare_to_namespace_header = false;
+		this.indent_body_declarations_compare_to_linkage = false;
 		//		this.indent_body_declarations_compare_to_enum_declaration_header = true;
 		this.indent_breaks_compare_to_cases = true;
 		this.indent_empty_lines = false;
@@ -2357,11 +2403,13 @@ public class DefaultCodeFormatterOptions {
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
 		this.brace_position_for_namespace_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
+		this.brace_position_for_linkage_declaration = DefaultCodeFormatterConstants.NEXT_LINE;
 		this.brace_position_for_switch = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED;
 
 		this.indent_statements_compare_to_block = true;
 		this.indent_statements_compare_to_body = true;
 		this.indent_body_declarations_compare_to_namespace_header = true;
+		this.indent_body_declarations_compare_to_linkage = true;
 		//		this.indent_body_declarations_compare_to_enum_declaration_header = true;
 		this.indent_declaration_compare_to_template_header = true;
 		this.indent_breaks_compare_to_cases = true;
@@ -2433,11 +2481,13 @@ public class DefaultCodeFormatterOptions {
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED;
 		this.brace_position_for_namespace_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED;
+		this.brace_position_for_linkage_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED;
 		this.brace_position_for_switch = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED;
 
 		this.indent_statements_compare_to_block = false;
 		this.indent_statements_compare_to_body = false;
 		this.indent_body_declarations_compare_to_namespace_header = false;
+		this.indent_body_declarations_compare_to_linkage = false;
 		this.indent_breaks_compare_to_cases = true;
 		this.indent_empty_lines = false;
 		this.indent_switchstatements_compare_to_cases = true;
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 7dd2826a6d8..312340d92ba 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
@@ -1170,11 +1170,10 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 			scribe.space();
 			memberDecls[0].accept(this);
 		} else {
-			// TLETODO [formatter] need options for linkage specification
-			formatLeftCurlyBrace(line, preferences.brace_position_for_namespace_declaration);
-			formatOpeningBrace(preferences.brace_position_for_namespace_declaration,
-					preferences.insert_space_before_opening_brace_in_namespace_declaration);
-			if (preferences.indent_body_declarations_compare_to_namespace_header) {
+			formatLeftCurlyBrace(line, preferences.brace_position_for_linkage_declaration);
+			formatOpeningBrace(preferences.brace_position_for_linkage_declaration,
+					preferences.insert_space_before_opening_brace_in_linkage_declaration);
+			if (preferences.indent_body_declarations_compare_to_linkage) {
 				scribe.indent();
 			}
 			scribe.startNewLine();
@@ -1182,10 +1181,10 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
 				declaration.accept(this);
 				scribe.startNewLine();
 			}
-			if (preferences.indent_body_declarations_compare_to_namespace_header) {
+			if (preferences.indent_body_declarations_compare_to_linkage) {
 				scribe.unIndent();
 			}
-			formatClosingBrace(preferences.brace_position_for_namespace_declaration);
+			formatClosingBrace(preferences.brace_position_for_linkage_declaration);
 		}
 		return PROCESS_SKIP;
 	}
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 c56437a0282..10c2d040e84 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
@@ -3850,4 +3850,44 @@ public class CodeFormatterTest extends BaseUITestCase {
 	public void testAttributesWithStructs3_Bug467346() throws Exception {
 		assertFormatterResult();
 	}
+
+	//extern "C" {
+	//void func();
+	//}
+
+	//extern "C" {
+	//	void func();
+	//}
+	public void testLinkage1_Bug299482() throws Exception {
+		fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_LINKAGE,
+				DefaultCodeFormatterConstants.TRUE);
+		assertFormatterResult();
+	}
+
+	//extern "C" {
+	//void func();
+	//}
+
+	//extern "C"{
+	//void func();
+	//}
+	public void testLinkage2_Bug299482() throws Exception {
+		fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_LINKAGE_DECLARATION,
+				DefaultCodeFormatterConstants.FALSE);
+		assertFormatterResult();
+	}
+
+	//extern "C" {
+	//void func();
+	//}
+
+	//extern "C"
+	//{
+	//void func();
+	//}
+	public void testLinkage3_Bug299482() throws Exception {
+		fOptions.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_LINKAGE_DECLARATION,
+				DefaultCodeFormatterConstants.NEXT_LINE);
+		assertFormatterResult();
+	}
 }
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/BracesTabPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/BracesTabPage.java
index 55f3524bb12..366cbcfa842 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/BracesTabPage.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/BracesTabPage.java
@@ -71,7 +71,10 @@ public class BracesTabPage extends FormatterTabPage {
 			"}" + //$NON-NLS-1$
 			"}" + //$NON-NLS-1$
 			"}" + //$NON-NLS-1$
-			"} // end namespace FOO"; //$NON-NLS-1$
+			"} // end namespace FOO\n\n" + //$NON-NLS-1$
+			"extern \"C\" {\n" + //$NON-NLS-1$
+			"void func();\n" + //$NON-NLS-1$
+			"}\n"; //$NON-NLS-1$
 
 	private TranslationUnitPreview fPreview;
 
@@ -108,6 +111,8 @@ public class BracesTabPage extends FormatterTabPage {
 				DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION);
 		createExtendedBracesCombo(group, numColumns, FormatterMessages.BracesTabPage_option_namespace_declaration,
 				DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_NAMESPACE_DECLARATION);
+		createExtendedBracesCombo(group, numColumns, FormatterMessages.BracesTabPage_option_linkage_declaration,
+				DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_LINKAGE_DECLARATION);
 		//		createExtendedBracesCombo(group, numColumns, FormatterMessages.BracesTabPage_option_constructor_declaration, DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION);
 		createExtendedBracesCombo(group, numColumns, FormatterMessages.BracesTabPage_option_function_declaration,
 				DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
index 39eb4f6a6c8..96b5a256e92 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.java
@@ -57,6 +57,10 @@ final class FormatterMessages extends NLS {
 	public static String WhiteSpaceTabPage_expression_list;
 	public static String WhiteSpaceTabPage_expression_list_before_comma;
 	public static String WhiteSpaceTabPage_expression_list_after_comma;
+	public static String WhiteSpaceTabPage_namespace;
+	public static String WhiteSpaceTabPage_namespace_before_brace;
+	public static String WhiteSpaceTabPage_linkage;
+	public static String WhiteSpaceTabPage_linkage_before_brace;
 	public static String WhiteSpaceTabPage_initializer_list;
 	public static String WhiteSpaceTabPage_calls;
 	public static String WhiteSpaceTabPage_calls_before_comma_in_function_args;
@@ -145,6 +149,8 @@ final class FormatterMessages extends NLS {
 	public static String WhiteSpaceOptions_class_decl;
 	public static String WhiteSpaceOptions_initializer_list;
 	public static String WhiteSpaceOptions_block;
+	public static String WhiteSpaceOptions_namespace;
+	public static String WhiteSpaceOptions_linkage;
 	public static String WhiteSpaceOptions_arrays;
 	public static String WhiteSpaceOptions_arguments;
 	public static String WhiteSpaceOptions_parameters;
@@ -291,6 +297,7 @@ final class FormatterMessages extends NLS {
 	public static String BracesTabPage_group_brace_positions_title;
 	public static String BracesTabPage_option_class_declaration;
 	public static String BracesTabPage_option_namespace_declaration;
+	public static String BracesTabPage_option_linkage_declaration;
 	public static String BracesTabPage_option_function_declaration;
 	public static String BracesTabPage_option_blocks;
 	public static String BracesTabPage_option_blocks_in_case;
@@ -362,6 +369,7 @@ final class FormatterMessages extends NLS {
 	public static String IndentationTabPage_switch_group_option_indent_statements_within_case_body;
 	public static String IndentationTabPage_switch_group_option_indent_break_statements;
 	public static String IndentationTabPage_namespace_group_option_indent_declarations_within_namespace;
+	public static String IndentationTabPage_linkage_group_option_indent_declarations_within_linkage;
 	public static String IndentationTabPage_indent_empty_lines;
 	public static String IndentationTabPage_use_tabs_only_for_leading_indentations;
 	public static String ModifyDialog_dialog_title;
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
index c879b3ae186..5ea1c40d74b 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/FormatterMessages.properties
@@ -40,6 +40,10 @@ WhiteSpaceTabPage_functions=Functions
 WhiteSpaceTabPage_declarator_list=Declarator list
 WhiteSpaceTabPage_declarator_list_before_comma=before comma in declarator list
 WhiteSpaceTabPage_declarator_list_after_comma=after comma in declarator list
+WhiteSpaceTabPage_namespace=Namespace
+WhiteSpaceTabPage_namespace_before_brace=before brace in namespace declaration
+WhiteSpaceTabPage_linkage=Linkage
+WhiteSpaceTabPage_linkage_before_brace=before brace in linkage declaration
 WhiteSpaceTabPage_expression_list=Expression list
 WhiteSpaceTabPage_expression_list_before_comma=before comma in expression list
 WhiteSpaceTabPage_expression_list_after_comma=after comma in expression list
@@ -160,6 +164,8 @@ WhiteSpaceOptions_closing_bracket=Closing bracket
 WhiteSpaceOptions_class_decl=Type declaration
 WhiteSpaceOptions_initializer_list=Initializer list
 WhiteSpaceOptions_block=Block
+WhiteSpaceOptions_namespace=Namespace
+WhiteSpaceOptions_linkage=Linkage
 
 WhiteSpaceOptions_arrays=Arrays
 WhiteSpaceOptions_arguments=Arguments
@@ -332,6 +338,7 @@ BracesTabPage_position_next_line_on_wrap=Next line on wrap
 BracesTabPage_group_brace_positions_title=Brace positions
 BracesTabPage_option_class_declaration=&Class declaration:
 BracesTabPage_option_namespace_declaration=&Namespace declaration:
+BracesTabPage_option_linkage_declaration=&Linkage declaration:
 BracesTabPage_option_function_declaration=&Function declaration:
 BracesTabPage_option_blocks=&Blocks:
 BracesTabPage_option_blocks_in_case=Bloc&ks in case statement:
@@ -415,6 +422,7 @@ IndentationTabPage_class_group_option_indent_declarations_compare_to_access_spec
 IndentationTabPage_block_group_option_indent_statements_compare_to_body=Stat&ements within function body
 IndentationTabPage_block_group_option_indent_statements_compare_to_block=Statements within bl&ocks
 IndentationTabPage_namespace_group_option_indent_declarations_within_namespace=Declarations within '&namespace' definition
+IndentationTabPage_linkage_group_option_indent_declarations_within_linkage=Declarations within '&linkage' definition
 IndentationTabPage_indent_empty_lines=Empty lines
 
 IndentationTabPage_switch_group_option_indent_statements_within_switch_body=Statements wit&hin 'switch' body
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/IndentationTabPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/IndentationTabPage.java
index 410a14c6cc6..dc81a9aef77 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/IndentationTabPage.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/IndentationTabPage.java
@@ -74,7 +74,10 @@ public class IndentationTabPage extends FormatterTabPage {
 			"}" + //$NON-NLS-1$
 			"}" + //$NON-NLS-1$
 			"}" + //$NON-NLS-1$
-			"} // end namespace FOO"; //$NON-NLS-1$
+			"} // end namespace FOO\n\n" + //$NON-NLS-1$
+			"extern \"C\" {\n" + //$NON-NLS-1$
+			"void func();\n" + //$NON-NLS-1$
+			"}\n"; //$NON-NLS-1$
 
 	private TranslationUnitPreview fPreview;
 	private String fOldTabChar = null;
@@ -161,6 +164,10 @@ public class IndentationTabPage extends FormatterTabPage {
 				DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_NAMESPACE_HEADER,
 				FALSE_TRUE);
 
+		createCheckboxPref(classGroup, numColumns,
+				FormatterMessages.IndentationTabPage_linkage_group_option_indent_declarations_within_linkage,
+				DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_LINKAGE, FALSE_TRUE);
+
 		createCheckboxPref(classGroup, numColumns, FormatterMessages.IndentationTabPage_indent_empty_lines,
 				DefaultCodeFormatterConstants.FORMATTER_INDENT_EMPTY_LINES, FALSE_TRUE);
 	}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
index a544d85313a..b583e86e506 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/formatter/WhiteSpaceOptions.java
@@ -218,6 +218,12 @@ public final class WhiteSpaceOptions {
 	private final PreviewSnippet BLOCK_PREVIEW = new PreviewSnippet(CodeFormatter.K_STATEMENTS,
 			"if (true) { return 1; } else { return 2; }"); //$NON-NLS-1$
 
+	private final PreviewSnippet NAMESPACE_PREVIEW = new PreviewSnippet(CodeFormatter.K_STATEMENTS,
+			"namespace FOO { int n1; }"); //$NON-NLS-1$
+
+	private final PreviewSnippet LINKAGE_PREVIEW = new PreviewSnippet(CodeFormatter.K_STATEMENTS,
+			"extern \"C\" { void func(); }"); //$NON-NLS-1$
+
 	private final PreviewSnippet PAREN_EXPR_PREVIEW = new PreviewSnippet(CodeFormatter.K_STATEMENTS,
 			"result= (a *( b +  c + d) * (e + f));"); //$NON-NLS-1$
 
@@ -447,6 +453,8 @@ public final class WhiteSpaceOptions {
 				FormatterMessages.WhiteSpaceTabPage_declarations);
 		createClassTree(workingValues, declarations);
 		createDeclaratorListTree(workingValues, declarations);
+		createNamespaceTree(workingValues, declarations);
+		createLinkageTree(workingValues, declarations);
 		//        createConstructorTree(workingValues, declarations);
 		createMethodDeclTree(workingValues, declarations);
 		createExceptionSpecificationTree(workingValues, declarations);
@@ -626,6 +634,12 @@ public final class WhiteSpaceOptions {
 				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_BLOCK, BLOCK_PREVIEW);
 		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_switch,
 				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_SWITCH, SWITCH_PREVIEW);
+		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_namespace,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_NAMESPACE_DECLARATION,
+				NAMESPACE_PREVIEW);
+		createOption(parent, workingValues, FormatterMessages.WhiteSpaceOptions_linkage,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_LINKAGE_DECLARATION,
+				LINKAGE_PREVIEW);
 	}
 
 	private void createBeforeClosingParenTree(Map workingValues, final InnerNode parent) {
@@ -978,6 +992,24 @@ public final class WhiteSpaceOptions {
 		return root;
 	}
 
+	private InnerNode createNamespaceTree(Map workingValues, InnerNode parent) {
+		final InnerNode root = new InnerNode(parent, workingValues, FormatterMessages.WhiteSpaceTabPage_namespace);
+
+		createOption(root, workingValues, FormatterMessages.WhiteSpaceTabPage_namespace_before_brace,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_NAMESPACE_DECLARATION,
+				NAMESPACE_PREVIEW);
+		return root;
+	}
+
+	private InnerNode createLinkageTree(Map workingValues, InnerNode parent) {
+		final InnerNode root = new InnerNode(parent, workingValues, FormatterMessages.WhiteSpaceTabPage_linkage);
+
+		createOption(root, workingValues, FormatterMessages.WhiteSpaceTabPage_linkage_before_brace,
+				DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_LINKAGE_DECLARATION,
+				LINKAGE_PREVIEW);
+		return root;
+	}
+
 	private InnerNode createDeclaratorListTree(Map workingValues, InnerNode parent) {
 		final InnerNode root = new InnerNode(parent, workingValues,
 				FormatterMessages.WhiteSpaceTabPage_declarator_list);
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java
index e6d75db1d0e..177b1954643 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java
@@ -73,6 +73,7 @@ public final class CIndenter {
 		final int prefAccessSpecifierIndent;
 		final int prefAccessSpecifierExtraSpaces;
 		final int prefNamespaceBodyIndent;
+		final int prefLinkageBodyIndent;
 		final boolean prefIndentBracesForBlocks;
 		final boolean prefIndentBracesForArrays;
 		final boolean prefIndentBracesForMethods;
@@ -140,6 +141,7 @@ public final class CIndenter {
 			prefAccessSpecifierIndent = prefAccessSpecifierIndent();
 			prefAccessSpecifierExtraSpaces = prefAccessSpecifierExtraSpaces();
 			prefNamespaceBodyIndent = prefNamespaceBodyIndent();
+			prefLinkageBodyIndent = prefLinkageBodyIndent();
 			prefIndentBracesForArrays = prefIndentBracesForArrays();
 			prefIndentBracesForMethods = prefIndentBracesForMethods();
 			prefIndentBracesForTypes = prefIndentBracesForTypes();
@@ -369,6 +371,14 @@ public final class CIndenter {
 				return 0;
 		}
 
+		private int prefLinkageBodyIndent() {
+			if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(
+					DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_LINKAGE)))
+				return prefBlockIndent();
+			else
+				return 0;
+		}
+
 		private boolean prefIndentBracesForBlocks() {
 			return DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED
 					.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK));
@@ -1902,7 +1912,9 @@ public final class CIndenter {
 					return setFirstElementAlignment(pos, bound);
 				else
 					fIndent = fPrefs.prefArrayIndent;
-			} else if (isNamespace() || isLinkageSpec()) {
+			} else if (isLinkageSpec()) {
+				fIndent = fPrefs.prefLinkageBodyIndent;
+			} else if (isNamespace()) {
 				fIndent = fPrefs.prefNamespaceBodyIndent;
 			} else if (looksLikeEnumDeclaration()) {
 				fIndent = fPrefs.prefTypeIndent;