Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -18,6 +18,9 @@ #include "clang/Basic/LangOptions.h" #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include #include namespace clang { @@ -1211,7 +1214,9 @@ LK_TableGen, /// Should be used for Protocol Buffer messages in text format /// (https://developers.google.com/protocol-buffers/). - LK_TextProto + LK_TextProto, + /// Do not use. Keep at last position. + LK_End, }; bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; } @@ -1363,17 +1368,16 @@ /// See documentation of ``RawStringFormats``. struct RawStringFormat { - /// \brief The delimiter that this raw string format matches. - std::string Delimiter; /// \brief The language of this raw string. LanguageKind Language; - /// \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; + std::vector Delimiters; + std::vector EnclosingFunctionNames; + std::string CanonicalDelimiter; + bool operator==(const RawStringFormat &Other) const { - return Delimiter == Other.Delimiter && Language == Other.Language && - BasedOnStyle == Other.BasedOnStyle; + return Language == Other.Language && Delimiters == Other.Delimiters && + EnclosingFunctionNames == Other.EnclosingFunctionNames && + CanonicalDelimiter == Other.CanonicalDelimiter; } }; @@ -1685,8 +1689,10 @@ Standard == R.Standard && TabWidth == R.TabWidth && UseTab == R.UseTab; } -}; + std::array, FormatStyle::LK_End> + AdditionalLanguageStyles; +}; /// \brief Returns a format style complying with the LLVM coding standards: /// http://llvm.org/docs/CodingStandards.html. FormatStyle getLLVMStyle(); Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -37,11 +37,15 @@ class WhitespaceManager; struct RawStringFormatStyleManager { - llvm::StringMap DelimiterStyle; + llvm::StringMap DelimiterStyle; + llvm::StringMap EnclosingFunctionNameStyle; RawStringFormatStyleManager(const FormatStyle &CodeStyle); - llvm::Optional get(StringRef Delimiter) const; + const FormatStyle *getDelimiterStyle(StringRef Delimiter) const; + + const FormatStyle * + getEnclosingFunctionNameStyle(StringRef EnclosingFunctionName) const; }; class ContinuationIndenter { Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -23,6 +23,11 @@ #define DEBUG_TYPE "format-indenter" +#define DBG(A) DEBUG({ \ + llvm::dbgs() << __LINE__ << ":" << __func__ << ":" \ + << #A << " = " << A << "\n"; \ +}); + namespace clang { namespace format { @@ -102,25 +107,46 @@ return Delimiter; } +static StringRef +getCanonicalRawStringDelimiter(const FormatStyle &Style, + FormatStyle::LanguageKind Language) { + for (const auto &Format : llvm::reverse(Style.RawStringFormats)) { + if (Format.Language == Language) + return StringRef(Format.CanonicalDelimiter); + } + return ""; +} + RawStringFormatStyleManager::RawStringFormatStyleManager( const FormatStyle &CodeStyle) { for (const auto &RawStringFormat : CodeStyle.RawStringFormats) { - FormatStyle Style; - if (!getPredefinedStyle(RawStringFormat.BasedOnStyle, - RawStringFormat.Language, &Style)) { - Style = getLLVMStyle(); - Style.Language = RawStringFormat.Language; + for (StringRef Delimiter : RawStringFormat.Delimiters) { + DelimiterStyle.insert( + {Delimiter, + CodeStyle.AdditionalLanguageStyles[RawStringFormat.Language].get()}); + } + for (StringRef EnclosingFunctionName : + RawStringFormat.EnclosingFunctionNames) { + EnclosingFunctionNameStyle.insert( + {EnclosingFunctionName, + CodeStyle.AdditionalLanguageStyles[RawStringFormat.Language].get()}); } - Style.ColumnLimit = CodeStyle.ColumnLimit; - DelimiterStyle.insert({RawStringFormat.Delimiter, Style}); } } -llvm::Optional -RawStringFormatStyleManager::get(StringRef Delimiter) const { +const FormatStyle * +RawStringFormatStyleManager::getDelimiterStyle(StringRef Delimiter) const { auto It = DelimiterStyle.find(Delimiter); if (It == DelimiterStyle.end()) - return None; + return nullptr; + return It->second; +} + +const FormatStyle *RawStringFormatStyleManager::getEnclosingFunctionNameStyle( + StringRef EnclosingFunctionName) const { + auto It = EnclosingFunctionNameStyle.find(EnclosingFunctionName); + if (It == EnclosingFunctionNameStyle.end()) + return nullptr; return It->second; } @@ -1291,14 +1317,30 @@ const FormatToken &Current, LineState &State, const FormatStyle &RawStringStyle, bool DryRun) { unsigned StartColumn = State.Column - Current.ColumnWidth; - auto Delimiter = *getRawStringDelimiter(Current.TokenText); + StringRef OldDelimiter = *getRawStringDelimiter(Current.TokenText); + StringRef NewDelimiter = + getCanonicalRawStringDelimiter(Style, RawStringStyle.Language); + if (NewDelimiter.empty() || OldDelimiter.empty()) + NewDelimiter = OldDelimiter; // The text of a raw string is between the leading 'R"delimiter(' and the // trailing 'delimiter)"'. - unsigned PrefixSize = 3 + Delimiter.size(); - unsigned SuffixSize = 2 + Delimiter.size(); + unsigned OldPrefixSize = 3 + OldDelimiter.size(); + unsigned OldSuffixSize = 2 + OldDelimiter.size(); + std::string RawText = + Current.TokenText.substr(OldPrefixSize).drop_back(OldSuffixSize); + if (NewDelimiter != OldDelimiter) { + // Don't update to the canonical delimiter 'deli' if ')deli"' occurs in the + // raw string. + std::string CanonicalDelimiterSuffix = (")" + NewDelimiter + "\"").str(); + if (StringRef(RawText).contains(CanonicalDelimiterSuffix)) + NewDelimiter = OldDelimiter; + } + + unsigned NewPrefixSize = 3 + NewDelimiter.size(); + unsigned NewSuffixSize = 2 + NewDelimiter.size(); - // The first start column is the column the raw text starts. - unsigned FirstStartColumn = StartColumn + PrefixSize; + // The first start column is the column the raw text starts after formatting. + unsigned FirstStartColumn = StartColumn + NewPrefixSize; // The next start column is the intended indentation a line break inside // the raw string at level 0. It is determined by the following rules: @@ -1309,7 +1351,7 @@ // These rules have the advantage that the formatted content both does not // violate the rectangle rule and visually flows within the surrounding // source. - bool ContentStartsOnNewline = Current.TokenText[PrefixSize] == '\n'; + bool ContentStartsOnNewline = Current.TokenText[OldPrefixSize] == '\n'; unsigned NextStartColumn = ContentStartsOnNewline ? State.Stack.back().Indent + Style.IndentWidth : FirstStartColumn; @@ -1323,12 +1365,9 @@ // - if the raw string prefix does not start on a newline, it is the current // indent. unsigned LastStartColumn = Current.NewlinesBefore - ? FirstStartColumn - PrefixSize + ? FirstStartColumn - NewPrefixSize : State.Stack.back().Indent; - std::string RawText = - Current.TokenText.substr(PrefixSize).drop_back(SuffixSize); - std::pair Fixes = internal::reformat( RawStringStyle, RawText, {tooling::Range(0, RawText.size())}, FirstStartColumn, NextStartColumn, LastStartColumn, "", @@ -1341,8 +1380,33 @@ return 0; } if (!DryRun) { + if (NewDelimiter != OldDelimiter) { + // In 'R"delimiter(...', the delimiter starts 2 characters after the start + // of the token. + SourceLocation PrefixDelimiterStart = + Current.Tok.getLocation().getLocWithOffset(2); + auto PrefixErr = Whitespaces.addReplacement(tooling::Replacement( + SourceMgr, PrefixDelimiterStart, OldDelimiter.size(), NewDelimiter)); + if (PrefixErr) { + llvm::errs() + << "Failed to update the prefix delimiter of a raw string: " + << llvm::toString(std::move(PrefixErr)) << "\n"; + } + // In 'R"delimiter(...)delimiter"', the suffix delimiter starts at + // position length - 1 - |delimiter|. + SourceLocation SuffixDelimiterStart = + Current.Tok.getLocation().getLocWithOffset(Current.TokenText.size() - + 1 - OldDelimiter.size()); + auto SuffixErr = Whitespaces.addReplacement(tooling::Replacement( + SourceMgr, SuffixDelimiterStart, OldDelimiter.size(), NewDelimiter)); + if (SuffixErr) { + llvm::errs() + << "Failed to update the suffix delimiter of a raw string: " + << llvm::toString(std::move(SuffixErr)) << "\n"; + } + } SourceLocation OriginLoc = - Current.Tok.getLocation().getLocWithOffset(PrefixSize); + Current.Tok.getLocation().getLocWithOffset(OldPrefixSize); for (const tooling::Replacement &Fix : Fixes.first) { auto Err = Whitespaces.addReplacement(tooling::Replacement( SourceMgr, OriginLoc.getLocWithOffset(Fix.getOffset()), @@ -1355,7 +1419,7 @@ } unsigned RawLastLineEndColumn = getLastLineEndColumn( *NewCode, FirstStartColumn, Style.TabWidth, Encoding); - State.Column = RawLastLineEndColumn + SuffixSize; + State.Column = RawLastLineEndColumn + NewSuffixSize; return Fixes.second; } @@ -1382,6 +1446,11 @@ // Compute the raw string style to use in case this is a raw string literal // that can be reformatted. auto RawStringStyle = getRawStringStyle(Current, State); + if (RawStringStyle) { + DBG("YAS"); + } else { + DBG("NAH"); + } if (RawStringStyle) { Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun); } else if (Current.IsMultiline && Current.isNot(TT_BlockComment)) { @@ -1428,6 +1497,23 @@ return Penalty; } +static StringRef getEnclosingFunctionName(const FormatToken& Current) { + // Look for: 'function(' or 'function(' 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; + DBG(Tok); + if (Tok) + Tok = Tok->getPreviousNonComment(); + } + DBG(Tok->TokenText); + if (!Tok || !Tok->is(tok::identifier)) return ""; + return Tok->TokenText; +} + llvm::Optional ContinuationIndenter::getRawStringStyle(const FormatToken &Current, const LineState &State) { @@ -1436,11 +1522,18 @@ auto Delimiter = getRawStringDelimiter(Current.TokenText); if (!Delimiter) return None; - auto RawStringStyle = RawStringFormats.get(*Delimiter); + auto RawStringStyle = RawStringFormats.getDelimiterStyle(*Delimiter); + if (!RawStringStyle) { + StringRef EnclosingFunctionName = getEnclosingFunctionName(Current); + RawStringStyle = + RawStringFormats.getEnclosingFunctionNameStyle(EnclosingFunctionName); + } if (!RawStringStyle) return None; - RawStringStyle->ColumnLimit = getColumnLimit(State); - return RawStringStyle; + + FormatStyle ResultStyle = *RawStringStyle; + ResultStyle.ColumnLimit = getColumnLimit(State); + return ResultStyle; } std::unique_ptr ContinuationIndenter::createBreakableToken( Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -38,7 +38,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/YAMLTraits.h" #include -#include #include #define DEBUG_TYPE "format-formatter" @@ -455,9 +454,10 @@ template <> struct MappingTraits { static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { - IO.mapOptional("Delimiter", Format.Delimiter); IO.mapOptional("Language", Format.Language); - IO.mapOptional("BasedOnStyle", Format.BasedOnStyle); + IO.mapOptional("Delimiters", Format.Delimiters); + IO.mapOptional("EnclosingFunctionNames", Format.EnclosingFunctionNames); + IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter); } }; @@ -641,7 +641,10 @@ LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Cpp11; LLVMStyle.UseTab = FormatStyle::UT_Never; - LLVMStyle.RawStringFormats = {{"pb", FormatStyle::LK_TextProto, "google"}}; + LLVMStyle.RawStringFormats = { + {FormatStyle::LK_TextProto, /*Delimiters=*/{"pb", "PB"}, + /*EnclosingFunctionNames=*/{}, /*CanonicalDelimiter=*/""}, + }; LLVMStyle.ReflowComments = true; LLVMStyle.SpacesInParentheses = false; LLVMStyle.SpacesInSquareBrackets = false; @@ -829,6 +832,8 @@ return NoStyle; } +/// \brief Gets a predefined style for the specified language by name. + bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language, FormatStyle *Style) { if (Name.equals_lower("llvm")) { @@ -888,13 +893,34 @@ // Look for a suitable configuration starting from the end, so we can // find the configuration for the specific language first, and the default // configuration (which can only be at slot 0) after it. + bool LanguageFound = false; for (int i = Styles.size() - 1; i >= 0; --i) { - if (Styles[i].Language == Language || - Styles[i].Language == FormatStyle::LK_None) { + if (!LanguageFound && (Styles[i].Language == Language || + Styles[i].Language == FormatStyle::LK_None)) { *Style = Styles[i]; Style->Language = Language; - return make_error_code(ParseError::Success); + LanguageFound = true; + break; + } + } + if (LanguageFound) { + for (int i = Styles.size() - 1; i >= 0; --i) { + if (Styles[i].Language == FormatStyle::LK_None) { + for (unsigned AdditionalLanguage = 0; + AdditionalLanguage < FormatStyle::LK_End; ++AdditionalLanguage) { + FormatStyle AdditionalLanguageStyle = Styles[i]; + AdditionalLanguageStyle.Language = + static_cast(AdditionalLanguage); + if (!Style->AdditionalLanguageStyles[AdditionalLanguage]) + Style->AdditionalLanguageStyles[AdditionalLanguage].reset( + new FormatStyle(AdditionalLanguageStyle)); + } + continue; + } + Style->AdditionalLanguageStyles[Styles[i].Language].reset( + new FormatStyle(Styles[i])); } + return make_error_code(ParseError::Success); } return make_error_code(ParseError::Unsuitable); } Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -10402,16 +10402,27 @@ Style.RawStringFormats.clear(); std::vector ExpectedRawStringFormats = { - {"pb", FormatStyle::LK_TextProto, "llvm"}, - {"cpp", FormatStyle::LK_Cpp, "google"}}; + {FormatStyle::LK_TextProto, + {"pb", "proto"}, + {"PARSE_TEXT_PROTO"}, + "textproto"}, + {FormatStyle::LK_Cpp, {"cc", "cpp"}, {"C_CODEBLOCK", "CPPEVAL"}, ""}}; CHECK_PARSE("RawStringFormats:\n" - " - Delimiter: 'pb'\n" - " Language: TextProto\n" - " BasedOnStyle: llvm\n" - " - Delimiter: 'cpp'\n" - " Language: Cpp\n" - " BasedOnStyle: google", + " - Language: TextProto\n" + " Delimiters:\n" + " - 'pb'\n" + " - 'proto'\n" + " EnclosingFunctionNames:\n" + " - 'PARSE_TEXT_PROTO'\n" + " CanonicalDelimiter: 'textproto'\n" + " - Language: Cpp\n" + " Delimiters:\n" + " - 'cc'\n" + " - 'cpp'\n" + " EnclosingFunctionNames:\n" + " - 'C_CODEBLOCK'\n" + " - 'CPPEVAL'", RawStringFormats, ExpectedRawStringFormats); } Index: unittests/Format/FormatTestRawStrings.cpp =================================================================== --- unittests/Format/FormatTestRawStrings.cpp +++ unittests/Format/FormatTestRawStrings.cpp @@ -9,6 +9,8 @@ #include "clang/Format/Format.h" +#include + #include "../Tooling/ReplacementTest.h" #include "FormatTestUtils.h" @@ -19,6 +21,12 @@ #define DEBUG_TYPE "format-test" +#define DBG(A) \ + DEBUG({ \ + llvm::dbgs() << __LINE__ << ":" << __func__ << ":" << #A << " = " << A \ + << "\n"; \ + }); + using clang::tooling::ReplacementTest; using clang::tooling::toReplacements; @@ -65,23 +73,40 @@ FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) { FormatStyle Style = getLLVMStyle(); Style.ColumnLimit = ColumnLimit; - Style.RawStringFormats = {{/*Delimiter=*/"pb", - /*Kind=*/FormatStyle::LK_TextProto, - /*BasedOnStyle=*/"google"}}; + Style.AdditionalLanguageStyles[FormatStyle::LK_TextProto] = + std::make_shared( + getGoogleStyle(FormatStyle::LK_TextProto)); + Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_TextProto, + /*Delimiters=*/{"pb"}, + /*EnclosingFunctionNames=*/{}, + /*CanonicalDelimiter=*/""}}; return Style; } - FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) { + FormatStyle getRawStringLLVMCppStyleBasedOn(std::string Name) { FormatStyle Style = getLLVMStyle(); - Style.RawStringFormats = {{/*Delimiter=*/"cpp", - /*Kind=*/FormatStyle::LK_Cpp, BasedOnStyle}}; + FormatStyle BasedOnStyle = getLLVMStyle(); + getPredefinedStyle(Name, FormatStyle::LK_Cpp, &BasedOnStyle); + Style.AdditionalLanguageStyles[FormatStyle::LK_Cpp] = + std::make_shared(BasedOnStyle); + Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp, + /*Delimiters=*/{"cpp"}, + /*EnclosingFunctionNames=*/{}, + /*CanonicalDelimiter=*/""}}; + DBG(BasedOnStyle.PointerAlignment); return Style; } - FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) { + FormatStyle getRawStringGoogleCppStyleBasedOn(std::string Name) { FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp); - Style.RawStringFormats = {{/*Delimiter=*/"cpp", - /*Kind=*/FormatStyle::LK_Cpp, BasedOnStyle}}; + FormatStyle BasedOnStyle = getLLVMStyle(); + getPredefinedStyle(Name, FormatStyle::LK_Cpp, &BasedOnStyle); + Style.AdditionalLanguageStyles[FormatStyle::LK_Cpp] = + std::make_shared(BasedOnStyle); + Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp, + /*Delimiters=*/{"cpp"}, + /*EnclosingFunctionNames=*/{}, + /*CanonicalDelimiter=*/""}}; return Style; } @@ -96,17 +121,19 @@ // llvm style puts '*' on the right. // google style puts '*' on the left. - // Use the llvm style if the raw string style has no BasedOnStyle. - expect_eq(R"test(int *i = R"cpp(int *p = nullptr;)cpp")test", - format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", - getRawStringLLVMCppStyleBasedOn(""))); - - // Use the google style if the raw string style has BasedOnStyle=google. + // Use llvm style outside and the google style inside if the raw string style + // is based on google. expect_eq(R"test(int *i = R"cpp(int* p = nullptr;)cpp")test", format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", getRawStringLLVMCppStyleBasedOn("google"))); - // Use the llvm style if the raw string style has no BasedOnStyle=llvm. + // Use llvm style if the raw string style has no BasedOnStyle. + expect_eq(R"test(int *i = R"cpp(int *p = nullptr;)cpp")test", + format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", + getRawStringLLVMCppStyleBasedOn(""))); + + // Use google style outside and the llvm style inside if the raw string style + // is based on llvm. expect_eq(R"test(int* i = R"cpp(int *p = nullptr;)cpp")test", format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", getRawStringGoogleCppStyleBasedOn("llvm"))); @@ -121,29 +148,6 @@ s = R"PB(item:1)PB"; t = R"pb(item:1)pb";)test", getRawStringPbStyleWithColumns(40))); - - FormatStyle MixedStyle = getLLVMStyle(); - MixedStyle.RawStringFormats = { - {/*Delimiter=*/"cpp", /*Kind=*/FormatStyle::LK_Cpp, - /*BasedOnStyle=*/"llvm"}, - {/*Delimiter=*/"CPP", /*Kind=*/FormatStyle::LK_Cpp, - /*BasedOnStyle=*/"google"}}; - - // Format the 'cpp' raw string with '*' on the right. - // Format the 'CPP' raw string with '*' on the left. - // Do not format the 'Cpp' raw string. - // Do not format non-raw strings. - expect_eq(R"test( -a = R"cpp(int *i = 0;)cpp"; -b = R"CPP(int* j = 0;)CPP"; -c = R"Cpp(int * k = 0;)Cpp"; -d = R"cpp(int * k = 0;)Cpp";)test", - format(R"test( -a = R"cpp(int * i = 0;)cpp"; -b = R"CPP(int * j = 0;)CPP"; -c = R"Cpp(int * k = 0;)Cpp"; -d = R"cpp(int * k = 0;)Cpp";)test", - MixedStyle)); } TEST_F(FormatTestRawStrings, ReformatsShortRawStringsOnSingleLine) { @@ -210,9 +214,9 @@ P p = TP(R"pb(item_1 <1> item_2: <2> item_3 {})pb");)test", - format(R"test( + format(R"test( P p = TP(R"pb(item_1<1> item_2:<2> item_3{ })pb");)test", - getRawStringPbStyleWithColumns(40))); + getRawStringPbStyleWithColumns(40))); expect_eq( R"test( @@ -515,7 +519,6 @@ format(R"test( ASSERT_TRUE(ParseFromString(R"pb(item_1: 1 item_2: 2)pb"), ptr);)test", getRawStringPbStyleWithColumns(40))); - } TEST_F(FormatTestRawStrings, RawStringsInOperands) { @@ -642,7 +645,6 @@ auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2,item_3:3)pb"; )test", getRawStringPbStyleWithColumns(40))); - } TEST_F(FormatTestRawStrings, PrefixAndSuffixAlignment) { @@ -728,6 +730,38 @@ getRawStringPbStyleWithColumns(20))); } +TEST_F(FormatTestRawStrings, UpdatesToCanonicalDelimiters) { + FormatStyle Style = getRawStringPbStyleWithColumns(25); + Style.RawStringFormats[0].CanonicalDelimiter = "proto"; + expect_eq(R"test(a = R"proto(key: value)proto";)test", + format(R"test(a = R"pb(key:value)pb";)test", Style)); + + // Don't update to canonical delimiter if it occurs as a raw string suffix in + // the raw string content. + expect_eq(R"test(a = R"pb(key: ")proto")pb";)test", + format(R"test(a = R"pb(key:")proto")pb";)test", Style)); +} + +TEST_F(FormatTestRawStrings, FormatsRawStringsWithEnclosingFunctionName) { + FormatStyle Style = getRawStringPbStyleWithColumns(40); + Style.RawStringFormats[0].EnclosingFunctionNames.push_back( + "PARSE_TEXT_PROTO"); + Style.RawStringFormats[0].EnclosingFunctionNames.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(R"(key: value)");)test", + format(R"test(a = ParseTextProto(R"(key:value)");)test", + Style)); +} + } // end namespace } // end namespace format } // end namespace clang