krasimir created this revision. Herald added subscribers: cfe-commits, klimek.
This patch adds enclosing function detection to raw string formatting. Repository: rC Clang https://reviews.llvm.org/D42167 Files: docs/ClangFormatStyleOptions.rst include/clang/Format/Format.h lib/Format/ContinuationIndenter.cpp lib/Format/ContinuationIndenter.h lib/Format/Format.cpp unittests/Format/FormatTest.cpp unittests/Format/FormatTestRawStrings.cpp
Index: unittests/Format/FormatTestRawStrings.cpp =================================================================== --- unittests/Format/FormatTestRawStrings.cpp +++ unittests/Format/FormatTestRawStrings.cpp @@ -65,23 +65,32 @@ FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) { FormatStyle Style = getLLVMStyle(); Style.ColumnLimit = ColumnLimit; - Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_TextProto, - /*Delimiters=*/{"pb"}, - /*BasedOnStyle=*/"google"}}; + Style.RawStringFormats = { + {/*Language=*/FormatStyle::LK_TextProto, + /*Delimiters=*/{"pb"}, + /*EnclosingFunctions=*/{}, + /*BasedOnStyle=*/"google"}, + }; return Style; } FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) { FormatStyle Style = getLLVMStyle(); - Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp, - /*Delimiters=*/{"cpp"}, BasedOnStyle}}; + Style.RawStringFormats = { + {/*Language=*/FormatStyle::LK_Cpp, + /*Delimiters=*/{"cpp"}, + /*EnclosingFunctions=*/{}, BasedOnStyle}, + }; return Style; } FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) { FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp); - Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp, - /*Delimiters=*/{"cpp"}, BasedOnStyle}}; + Style.RawStringFormats = { + {/*Language=*/FormatStyle::LK_Cpp, + /*Delimiters=*/{"cpp"}, + /*EnclosingFunctions=*/{}, BasedOnStyle}, + }; return Style; } @@ -122,7 +131,7 @@ EXPECT_EQ(0, parseConfiguration("---\n" "Language: Cpp\n" "BasedOnStyle: Google", &Style).value()); - Style.RawStringFormats = {{FormatStyle::LK_Cpp, {"cpp"}, "llvm"}}; + Style.RawStringFormats = {{FormatStyle::LK_Cpp, {"cpp"}, {}, "llvm"}}; expect_eq(R"test(int* i = R"cpp(int* j = 0;)cpp";)test", format(R"test(int * i = R"cpp(int * j = 0;)cpp";)test", Style)); } @@ -720,6 +729,29 @@ getRawStringPbStyleWithColumns(20))); } +TEST_F(FormatTestRawStrings, FormatsRawStringsWithEnclosingFunctionName) { + FormatStyle Style = getRawStringPbStyleWithColumns(40); + Style.RawStringFormats[0].EnclosingFunctions.push_back( + "PARSE_TEXT_PROTO"); + Style.RawStringFormats[0].EnclosingFunctions.push_back("ParseTextProto"); + expect_eq(R"test(a = PARSE_TEXT_PROTO(R"(key: value)");)test", + format(R"test(a = PARSE_TEXT_PROTO(R"(key:value)");)test", Style)); + + expect_eq(R"test( +a = PARSE_TEXT_PROTO /**/ ( + /**/ R"(key: value)");)test", + format(R"test( +a = PARSE_TEXT_PROTO/**/(/**/R"(key:value)");)test", + Style)); + + expect_eq(R"test( +a = ParseTextProto<ProtoType>( + R"(key: value)");)test", + format(R"test( +a = ParseTextProto<ProtoType>(R"(key:value)");)test", + Style)); +} + } // end namespace } // end namespace format } // end namespace clang Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -10408,21 +10408,35 @@ Style.RawStringFormats.clear(); std::vector<FormatStyle::RawStringFormat> ExpectedRawStringFormats = { - {FormatStyle::LK_TextProto, {"pb", "proto"}, "llvm"}, - {FormatStyle::LK_Cpp, {"cc", "cpp"}, "google"}, + { + FormatStyle::LK_TextProto, + {"pb", "proto"}, + {"PARSE_TEXT_PROTO"}, + "llvm", + }, + { + FormatStyle::LK_Cpp, + {"cc", "cpp"}, + {"C_CODEBLOCK", "CPPEVAL"}, + "", + }, }; CHECK_PARSE("RawStringFormats:\n" " - Language: TextProto\n" " Delimiters:\n" " - 'pb'\n" " - 'proto'\n" + " EnclosingFunctions:\n" + " - 'PARSE_TEXT_PROTO'\n" " BasedOnStyle: llvm\n" " - Language: Cpp\n" " Delimiters:\n" " - 'cc'\n" " - 'cpp'\n" - " BasedOnStyle: google\n", + " EnclosingFunctions:\n" + " - 'C_CODEBLOCK'\n" + " - 'CPPEVAL'\n", RawStringFormats, ExpectedRawStringFormats); } Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -457,6 +457,7 @@ static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { IO.mapOptional("Language", Format.Language); IO.mapOptional("Delimiters", Format.Delimiters); + IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions); IO.mapOptional("BasedOnStyle", Format.BasedOnStyle); } }; @@ -705,6 +706,12 @@ "textproto", "TEXTPROTO", }, + /*EnclosingFunctionNames=*/ + { + "EqualsProto", + "PARSE_TEXT_PROTO", + "ParseTextProto", + }, /*BasedOnStyle=*/"google", }}; GoogleStyle.SpacesBeforeTrailingComments = 2; Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -38,10 +38,14 @@ struct RawStringFormatStyleManager { llvm::StringMap<FormatStyle> DelimiterStyle; + llvm::StringMap<FormatStyle> EnclosingFunctionStyle; RawStringFormatStyleManager(const FormatStyle &CodeStyle); - llvm::Optional<FormatStyle> get(StringRef Delimiter) const; + llvm::Optional<FormatStyle> getDelimiterStyle(StringRef Delimiter) const; + + llvm::Optional<FormatStyle> + getEnclosingFunctionStyle(StringRef EnclosingFunction) const; }; class ContinuationIndenter { Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -105,32 +105,44 @@ RawStringFormatStyleManager::RawStringFormatStyleManager( const FormatStyle &CodeStyle) { for (const auto &RawStringFormat : CodeStyle.RawStringFormats) { - for (StringRef Delimiter : RawStringFormat.Delimiters) { - llvm::Optional<FormatStyle> LanguageStyle = - CodeStyle.GetLanguageStyle(RawStringFormat.Language); - if (!LanguageStyle) { - FormatStyle PredefinedStyle; - if (!getPredefinedStyle(RawStringFormat.BasedOnStyle, - RawStringFormat.Language, &PredefinedStyle)) { - PredefinedStyle = getLLVMStyle(); - PredefinedStyle.Language = RawStringFormat.Language; - } - LanguageStyle = PredefinedStyle; + llvm::Optional<FormatStyle> LanguageStyle = + CodeStyle.GetLanguageStyle(RawStringFormat.Language); + if (!LanguageStyle) { + FormatStyle PredefinedStyle; + if (!getPredefinedStyle(RawStringFormat.BasedOnStyle, + RawStringFormat.Language, &PredefinedStyle)) { + PredefinedStyle = getLLVMStyle(); + PredefinedStyle.Language = RawStringFormat.Language; } - LanguageStyle->ColumnLimit = CodeStyle.ColumnLimit; + LanguageStyle = PredefinedStyle; + } + LanguageStyle->ColumnLimit = CodeStyle.ColumnLimit; + for (StringRef Delimiter : RawStringFormat.Delimiters) { DelimiterStyle.insert({Delimiter, *LanguageStyle}); } + for (StringRef EnclosingFunction : RawStringFormat.EnclosingFunctions) { + EnclosingFunctionStyle.insert({EnclosingFunction, *LanguageStyle}); + } } } llvm::Optional<FormatStyle> -RawStringFormatStyleManager::get(StringRef Delimiter) const { +RawStringFormatStyleManager::getDelimiterStyle(StringRef Delimiter) const { auto It = DelimiterStyle.find(Delimiter); if (It == DelimiterStyle.end()) return None; return It->second; } +llvm::Optional<FormatStyle> +RawStringFormatStyleManager::getEnclosingFunctionStyle( + StringRef EnclosingFunction) const { + auto It = EnclosingFunctionStyle.find(EnclosingFunction); + if (It == EnclosingFunctionStyle.end()) + return None; + return It->second; +} + ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SourceManager &SourceMgr, @@ -1437,15 +1449,35 @@ return Penalty; } +// Returns the enclosing function name of a token, or the empty string if not +// found. +static StringRef getEnclosingFunctionName(const FormatToken& Current) { + // Look for: 'function(' or 'function<templates>(' before Current. + auto Tok = Current.getPreviousNonComment(); + if (!Tok || !Tok->is(tok::l_paren)) return ""; + Tok = Tok->getPreviousNonComment(); + if (!Tok) return ""; + if (Tok->is(TT_TemplateCloser)) { + Tok = Tok->MatchingParen; + if (Tok) + Tok = Tok->getPreviousNonComment(); + } + if (!Tok || !Tok->is(tok::identifier)) return ""; + return Tok->TokenText; +} + llvm::Optional<FormatStyle> ContinuationIndenter::getRawStringStyle(const FormatToken &Current, const LineState &State) { if (!Current.isStringLiteral()) return None; auto Delimiter = getRawStringDelimiter(Current.TokenText); if (!Delimiter) return None; - auto RawStringStyle = RawStringFormats.get(*Delimiter); + auto RawStringStyle = RawStringFormats.getDelimiterStyle(*Delimiter); + if (!RawStringStyle) + RawStringStyle = RawStringFormats.getEnclosingFunctionStyle( + getEnclosingFunctionName(Current)); if (!RawStringStyle) return None; RawStringStyle->ColumnLimit = getColumnLimit(State); Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1367,12 +1367,15 @@ LanguageKind Language; /// \brief A list of raw string delimiters that match this language. std::vector<std::string> Delimiters; + /// \brief A list of enclosing function names that match this language. + std::vector<std::string> EnclosingFunctions; /// \brief The style name on which this raw string format is based on. /// If not specified, the raw string format is based on the style that this /// format is based on. std::string BasedOnStyle; bool operator==(const RawStringFormat &Other) const { return Language == Other.Language && Delimiters == Other.Delimiters && + EnclosingFunctions == Other.EnclosingFunctions && BasedOnStyle == Other.BasedOnStyle; } }; @@ -1394,6 +1397,8 @@ /// Delimiters: /// - 'pb' /// - 'proto' + /// EnclosingFunctions: + /// - 'PARSE_TEXT_PROTO' /// BasedOnStyle: google /// - Language: Cpp /// Delimiters: Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -994,28 +994,28 @@ .. code-block:: c++ - Constructor() - : initializer1(), - initializer2() + Constructor() + : initializer1(), + initializer2() * ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``) Break constructor initializers before the colon and commas, and align the commas with the colon. .. code-block:: c++ - Constructor() - : initializer1() - , initializer2() + Constructor() + : initializer1() + , initializer2() * ``BCIS_AfterColon`` (in configuration: ``AfterColon``) Break constructor initializers after the colon and commas. .. code-block:: c++ - Constructor() : - initializer1(), - initializer2() + Constructor() : + initializer1(), + initializer2() @@ -1201,7 +1201,8 @@ * ``IBS_Regroup`` (in configuration: ``Regroup``) Merge multiple ``#include`` blocks together and sort as one. - Then split into groups based on category priority. See ``IncludeCategories``. + Then split into groups based on category priority. See + ``IncludeCategories``. .. code-block:: c++ @@ -1577,24 +1578,33 @@ **RawStringFormats** (``std::vector<RawStringFormat>``) - Raw string delimiters denoting that the raw string contents are - code in a particular language and can be reformatted. + Defines hints for detecting supported languages code blocks in raw + strings. A raw string with a matching delimiter will be reformatted assuming the - specified language based on a predefined style given by 'BasedOnStyle'. - If 'BasedOnStyle' is not found, the formatting is based on llvm style. + specified language based on the style for that language defined in the + .clang-format file. If no style has been defined in the .clang-format file + for the specific language, a predefined style given by 'BasedOnStyle' is + used. If 'BasedOnStyle' is not found, the formatting is based on llvm + style. To configure this in the .clang-format file, use: .. code-block:: yaml RawStringFormats: - - Delimiter: 'pb' - Language: TextProto - BasedOnStyle: llvm - - Delimiter: 'proto' - Language: TextProto - BasedOnStyle: google + - Language: TextProto + Delimiters: + - 'pb' + - 'proto' + EnclosingFunctions: + - 'PARSE_TEXT_PROTO' + BasedOnStyle: google + - Language: Cpp + Delimiters: + - 'cc' + - 'cpp' + BasedOnStyle: llvm **ReflowComments** (``bool``) If ``true``, clang-format will attempt to re-flow comments.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits