diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1917,6 +1917,30 @@ +**IndentPragmas** (``bool``) + Indent pragmas + + When ``false``, pragmas are flushed left or follow IndentPPDirectives. + When ``true``, pragmas are indented to the current scope level. + + .. code-block:: c++ + + false: true: + #pragma once vs #pragma once + void foo() { void foo() { + #pragma omp simd #pragma omp simd + for (int i=0;i<10;i++) { for (int i=0;i<10;i++) { + #pragma omp simd #pragma omp simd + for (int i=0;i<10;i++) { for (int i=0;i<10;i++) { + } } + #if 1 #if 1 + #pragma omp simd #pragma omp simd + for (int i=0;i<10;i++) { for (int i=0;i<10;i++) { + } } + #endif #endif + } } + } } + **IndentRequires** (``bool``) Indent the requires clause in a template diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1528,6 +1528,29 @@ /// \endcode bool IndentGotoLabels; + /// Indent pragmas + /// + /// When ``false``, pragmas are flushed left or follow IndentPPDirectives. + /// When ``true``, pragmas are indented to the current scope level. + /// \code + /// false: true: + /// #pragma once vs #pragma once + /// void foo() { void foo() { + /// #pragma omp simd #pragma omp simd + /// for (int i=0;i<10;i++) { for (int i=0;i<10;i++) { + /// #pragma omp simd #pragma omp simd + /// for (int i=0;i<10;i++) { for (int i=0;i<10;i++) { + /// } } + /// #if 1 #if 1 + /// #pragma omp simd #pragma omp simd + /// for (int i=0;i<10;i++) { for (int i=0;i<10;i++) { + /// } } + /// #endif #endif + /// } } + /// } } + /// \endcode + bool IndentPragmas; + /// Options for indenting preprocessor directives. enum PPDirectiveIndentStyle { /// Does not indent any directives. @@ -2494,6 +2517,7 @@ IndentCaseLabels == R.IndentCaseLabels && IndentCaseBlocks == R.IndentCaseBlocks && IndentGotoLabels == R.IndentGotoLabels && + IndentPragmas == R.IndentPragmas && IndentPPDirectives == R.IndentPPDirectives && IndentExternBlock == R.IndentExternBlock && IndentRequires == R.IndentRequires && IndentWidth == R.IndentWidth && diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -589,6 +589,12 @@ State.Line->Type == LT_ImportStatement)) { Spaces += State.FirstIndent; + bool isPragmaLine = + State.Line->First->startsSequence(tok::hash, tok::pp_pragma); + // If indenting pragmas remove the extra space for the #. + if (Style.IndentPragmas && isPragmaLine) + Spaces--; + // For preprocessor indent with tabs, State.Column will be 1 because of the // hash. This causes second-level indents onward to have an extra space // after the tabs. We avoid this misalignment by subtracting 1 from the diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -557,6 +557,7 @@ IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); + IO.mapOptional("IndentPragmas", Style.IndentPragmas); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); IO.mapOptional("IndentExternBlock", Style.IndentExternBlock); IO.mapOptional("IndentRequires", Style.IndentRequires); @@ -924,6 +925,7 @@ LLVMStyle.IndentCaseLabels = false; LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentGotoLabels = true; + LLVMStyle.IndentPragmas = false; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; LLVMStyle.IndentRequires = false; LLVMStyle.IndentWrappedFunctionNames = false; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -1237,10 +1237,21 @@ } // Preprocessor directives get indented before the hash only if specified - if (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && - (Line.Type == LT_PreprocessorDirective || - Line.Type == LT_ImportStatement)) - Indent = 0; + if (Line.Type == LT_PreprocessorDirective || + Line.Type == LT_ImportStatement) { + switch (Style.IndentPPDirectives) { + case FormatStyle::PPDIS_AfterHash: + Indent = 0; + break; + case FormatStyle::PPDIS_None: + case FormatStyle::PPDIS_BeforeHash: { + // If we want to indent pragmas. + bool isPragmaLine = RootToken.startsSequence(tok::hash, tok::pp_pragma); + if (!Style.IndentPragmas && isPragmaLine) + Indent = 0; + } break; + } + } Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent, /*IsAligned=*/false, diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -88,7 +88,7 @@ void parseBlock(bool MustBeDeclaration, bool AddLevel = true, bool MunchSemi = true); void parseChildBlock(); - void parsePPDirective(); + void parsePPDirective(unsigned Level); void parsePPDefine(); void parsePPIf(bool IfDef); void parsePPElIf(); diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -714,7 +714,7 @@ nextToken(); } -void UnwrappedLineParser::parsePPDirective() { +void UnwrappedLineParser::parsePPDirective(unsigned Level) { assert(FormatTok->Tok.is(tok::hash) && "'#' expected"); ScopedMacroState MacroState(*Line, Tokens, FormatTok); @@ -745,6 +745,17 @@ case tok::pp_endif: parsePPEndIf(); break; + case tok::pp_pragma: { + bool IndentPPDirectives = + Style.IndentPPDirectives != FormatStyle::PPDIS_None; + unsigned CurrentLevel = Line->Level; + Line->Level = + Style.IndentPragmas + ? (IndentPPDirectives ? (Level - (PPBranchLevel + 1)) : Level) + : CurrentLevel; + parsePPUnknown(); + Line->Level = CurrentLevel; + } break; default: parsePPUnknown(); break; @@ -3157,7 +3168,7 @@ PPBranchLevel > 0) Line->Level += PPBranchLevel; flushComments(isOnNewLine(*FormatTok)); - parsePPDirective(); + parsePPDirective(Line->Level); } while (FormatTok->getType() == TT_ConflictStart || FormatTok->getType() == TT_ConflictEnd || diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14116,6 +14116,7 @@ CHECK_PARSE_BOOL(IndentCaseLabels); CHECK_PARSE_BOOL(IndentCaseBlocks); CHECK_PARSE_BOOL(IndentGotoLabels); + CHECK_PARSE_BOOL(IndentPragmas); CHECK_PARSE_BOOL(IndentRequires); CHECK_PARSE_BOOL(IndentWrappedFunctionNames); CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks); @@ -17571,6 +17572,129 @@ "struct constant;", Style); } + +TEST_F(FormatTest, IndentPragmas) { + FormatStyle Style = getLLVMStyle(); + Style.IndentPPDirectives = FormatStyle::PPDIS_None; + + Style.IndentPragmas = false; + verifyFormat("#pragma once", Style); + verifyFormat("#pragma omp simd\n" + "for (int i = 0; i < 10; i++) {\n" + "}", + Style); + verifyFormat("void foo() {\n" + "#pragma omp simd\n" + " for (int i = 0; i < 10; i++) {\n" + " }\n" + "}", + Style); + verifyFormat("void foo() {\n" + "// outer loop\n" + "#pragma omp simd\n" + " for (int k = 0; k < 10; k++) {\n" + "// inner loop\n" + "#pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + "// outer loop\n" + "#if 1\n" + "#pragma omp simd\n" + " for (int k = 0; k < 10; k++) {\n" + "// inner loop\n" + "#pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "#endif\n" + "}", + Style); + + Style.IndentPragmas = true; + verifyFormat("#pragma once", Style); + verifyFormat("#pragma omp simd\n" + "for (int i = 0; i < 10; i++) {\n" + "}", + Style); + verifyFormat("void foo() {\n" + " #pragma omp simd\n" + " for (int i = 0; i < 10; i++) {\n" + " }\n" + "}", + Style); + verifyFormat("void foo() {\n" + " #pragma omp simd\n" + " for (int i = 0; i < 10; i++) {\n" + " #pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + " #pragma omp simd\n" + " for (...) {\n" + " #pragma omp simd\n" + " for (...) {\n" + " }\n" + " }\n" + "}", + Style); + + Style.IndentPPDirectives = FormatStyle::PPDIS_AfterHash; + + verifyFormat("void foo() {\n" + "# pragma omp simd\n" + " for (int i = 0; i < 10; i++) {\n" + "# pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "}", + Style); + + verifyFormat("void foo() {\n" + "#if 1\n" + "# pragma omp simd\n" + " for (int k = 0; k < 10; k++) {\n" + "# pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "#endif\n" + "}", + Style); + + Style.IndentPPDirectives = FormatStyle::PPDIS_BeforeHash; + EXPECT_EQ("void foo() {\n" + "#if 1\n" + " #pragma omp simd\n" + " for (int k = 0; k < 10; k++) {\n" + " #pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "#endif\n" + "}", + format("void foo() {\n" + "#if 1\n" + " #pragma omp simd\n" + " for (int k = 0; k < 10; k++) {\n" + " #pragma omp simd\n" + " for (int j = 0; j < 10; j++) {\n" + " }\n" + " }\n" + "#endif\n" + "}", + Style)); +} + } // namespace } // namespace format } // namespace clang