krasimir updated this revision to Diff 125927.
krasimir added a comment.

- Updated documentation


Repository:
  rC Clang

https://reviews.llvm.org/D40909

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,39 @@
   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<FormatStyle>(
+            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<FormatStyle>(BasedOnStyle);
+    Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp,
+                               /*Delimiters=*/{"cpp"},
+                               /*EnclosingFunctionNames=*/{},
+                               /*CanonicalDelimiter=*/""}};
     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<FormatStyle>(BasedOnStyle);
+    Style.RawStringFormats = {{/*Language=*/FormatStyle::LK_Cpp,
+                               /*Delimiters=*/{"cpp"},
+                               /*EnclosingFunctionNames=*/{},
+                               /*CanonicalDelimiter=*/""}};
     return Style;
   }
 
@@ -96,17 +112,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 +139,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 +205,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 +510,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 +636,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 +721,41 @@
                    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<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
@@ -10402,16 +10402,27 @@
 
   Style.RawStringFormats.clear();
   std::vector<FormatStyle::RawStringFormat> 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: 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 <algorithm>
-#include <memory>
 #include <string>
 
 #define DEBUG_TYPE "format-formatter"
@@ -455,9 +454,10 @@
 
 template <> struct MappingTraits<FormatStyle::RawStringFormat> {
   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,6 @@
   LLVMStyle.SpacesBeforeTrailingComments = 1;
   LLVMStyle.Standard = FormatStyle::LS_Cpp11;
   LLVMStyle.UseTab = FormatStyle::UT_Never;
-  LLVMStyle.RawStringFormats = {{"pb", FormatStyle::LK_TextProto, "google"}};
   LLVMStyle.ReflowComments = true;
   LLVMStyle.SpacesInParentheses = false;
   LLVMStyle.SpacesInSquareBrackets = false;
@@ -695,6 +694,25 @@
   GoogleStyle.ObjCSpaceAfterProperty = false;
   GoogleStyle.ObjCSpaceBeforeProtocolList = false;
   GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
+  GoogleStyle.RawStringFormats = {
+      {FormatStyle::LK_TextProto,
+       /*Delimiters=*/
+       {
+           "pb",
+           "PB",
+           "proto",
+           "PROTO",
+           "textproto",
+           "TEXTPROTO",
+       },
+       /*EnclosingFunctionNames=*/
+       {
+           "EqualsProto",
+           "PARSE_TEXT_PROTO",
+           "ParseTextProto",
+       },
+       /*CanonicalDelimiter=*/""},
+  };
   GoogleStyle.SpacesBeforeTrailingComments = 2;
   GoogleStyle.Standard = FormatStyle::LS_Auto;
 
@@ -888,13 +906,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<FormatStyle::LanguageKind>(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: lib/Format/ContinuationIndenter.h
===================================================================
--- lib/Format/ContinuationIndenter.h
+++ lib/Format/ContinuationIndenter.h
@@ -37,11 +37,15 @@
 class WhitespaceManager;
 
 struct RawStringFormatStyleManager {
-  llvm::StringMap<FormatStyle> DelimiterStyle;
+  llvm::StringMap<const FormatStyle*> DelimiterStyle;
+  llvm::StringMap<const FormatStyle*> EnclosingFunctionNameStyle;
 
   RawStringFormatStyleManager(const FormatStyle &CodeStyle);
 
-  llvm::Optional<FormatStyle> 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
@@ -102,25 +102,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<FormatStyle>
-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 +1312,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;
+  }
 
-  // The first start column is the column the raw text starts.
-  unsigned FirstStartColumn = StartColumn + PrefixSize;
+  unsigned NewPrefixSize = 3 + NewDelimiter.size();
+  unsigned NewSuffixSize = 2 + NewDelimiter.size();
+
+  // 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 +1346,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 +1360,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<tooling::Replacements, unsigned> Fixes = internal::reformat(
       RawStringStyle, RawText, {tooling::Range(0, RawText.size())},
       FirstStartColumn, NextStartColumn, LastStartColumn, "<stdin>",
@@ -1341,8 +1375,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 +1414,7 @@
   }
   unsigned RawLastLineEndColumn = getLastLineEndColumn(
       *NewCode, FirstStartColumn, Style.TabWidth, Encoding);
-  State.Column = RawLastLineEndColumn + SuffixSize;
+  State.Column = RawLastLineEndColumn + NewSuffixSize;
   return Fixes.second;
 }
 
@@ -1428,19 +1487,39 @@
   return Penalty;
 }
 
+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.getEnclosingFunctionNameStyle(
+        getEnclosingFunctionName(Current));
   if (!RawStringStyle)
     return None;
-  RawStringStyle->ColumnLimit = getColumnLimit(State);
-  return RawStringStyle;
+
+  FormatStyle ResultStyle = *RawStringStyle;
+  ResultStyle.ColumnLimit = getColumnLimit(State);
+  return ResultStyle;
 }
 
 std::unique_ptr<BreakableToken> ContinuationIndenter::createBreakableToken(
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -18,6 +18,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "clang/Tooling/Core/Replacement.h"
 #include "llvm/ADT/ArrayRef.h"
+#include <array>
 #include <system_error>
 
 namespace clang {
@@ -1211,7 +1212,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,36 +1366,53 @@
 
   /// 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.
+    /// \brief The language of this raw string format.
     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;
+    /// \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> EnclosingFunctionNames;
+    /// \brief The canonical delimiter for this language.
+    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;
     }
   };
 
-  /// \brief Raw string delimiters denoting that the raw string contents are
-  /// code in a particular language and can be reformatted.
+  /// \brief Defines hints for detecting supported languages code blocks in
+  /// raw strings.
+  ///
+  /// A raw string with a matching delimiter or a matching enclosing function
+  /// name will be reformatted assuming the specified language based on a
+  /// predefined style for that language defined in the .clang-format file.
+  ///
+  /// A matching delimiter of a raw string takes precedence over a matching
+  /// enclosing function name for determining the language of the raw string
+  /// contents.
   ///
-  /// 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.
+  /// If a canonical delimiter is specified, occurences of other delimiters for
+  /// the same language will be updated to the canonical if possible.
+  ///
+  /// For a particular supported language at most one specification should
+  /// exist.
   ///
   /// To configure this in the .clang-format file, use:
   /// \code{.yaml}
   ///   RawStringFormats:
-  ///     - Delimiter: 'pb'
-  ///       Language:  TextProto
-  ///       BasedOnStyle: llvm
-  ///     - Delimiter: 'proto'
-  ///       Language:  TextProto
-  ///       BasedOnStyle: google
+  ///     - Language: TextProto
+  ///         Delimiters:
+  ///           - 'pb'
+  ///           - 'proto'
+  ///         EnclosingFunctionNames:
+  ///           - 'PARSE_TEXT_PROTO'
+  ///     - Language: Cpp
+  ///         Delimiters:
+  ///           - 'cc'
+  ///           - 'cpp'
+  ///         CanonicalDelimiter: 'cc'
   /// \endcode
   std::vector<RawStringFormat> RawStringFormats;
 
@@ -1685,8 +1705,12 @@
            Standard == R.Standard && TabWidth == R.TabWidth &&
            UseTab == R.UseTab;
   }
-};
 
+  // A mapping from FormatStyle::LanguageKind to a format style to use for
+  // code blocks in that language.
+  std::array<std::shared_ptr<FormatStyle>, FormatStyle::LK_End>
+      AdditionalLanguageStyles;
+};
 /// \brief Returns a format style complying with the LLVM coding standards:
 /// http://llvm.org/docs/CodingStandards.html.
 FormatStyle getLLVMStyle();
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++
 
@@ -1416,6 +1417,9 @@
     Should be used for Protocol Buffer messages in text format
     (https://developers.google.com/protocol-buffers/).
 
+  * ``LK_End`` (in configuration: ``End``)
+    Do not use. Keep at last position.
+
 
 
 **MacroBlockBegin** (``std::string``)
@@ -1577,24 +1581,39 @@
 
 
 **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 or a matching enclosing function
+  name will be reformatted assuming the specified language based on a
+  predefined style for that language defined in the .clang-format file.
+
+  A matching delimiter of a raw string takes precedence over a matching
+  enclosing function name for determining the language of the raw string
+  contents.
+
+  If a canonical delimiter is specified, occurences of other delimiters for
+  the same language will be updated to the canonical if possible.
 
-  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.
+  For a particular supported language at most one specification should
+  exist.
 
   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'
+          EnclosingFunctionNames:
+            - 'PARSE_TEXT_PROTO'
+      - Language: Cpp
+          Delimiters:
+            - 'cc'
+            - 'cpp'
+          CanonicalDelimiter: 'cc'
 
 **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

Reply via email to