r322678 - [clang-format] adds enclosing function detection to raw string formatting

Krasimir Georgiev via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 17 08:17:26 PST 2018


Author: krasimir
Date: Wed Jan 17 08:17:26 2018
New Revision: 322678

URL: http://llvm.org/viewvc/llvm-project?rev=322678&view=rev
Log:
[clang-format] adds enclosing function detection to raw string formatting

Summary: This patch adds enclosing function detection to raw string formatting.

Reviewers: bkramer

Reviewed By: bkramer

Subscribers: klimek, cfe-commits

Differential Revision: https://reviews.llvm.org/D42167

Modified:
    cfe/trunk/docs/ClangFormatStyleOptions.rst
    cfe/trunk/include/clang/Format/Format.h
    cfe/trunk/lib/Format/ContinuationIndenter.cpp
    cfe/trunk/lib/Format/ContinuationIndenter.h
    cfe/trunk/lib/Format/Format.cpp
    cfe/trunk/unittests/Format/FormatTest.cpp
    cfe/trunk/unittests/Format/FormatTestRawStrings.cpp

Modified: cfe/trunk/docs/ClangFormatStyleOptions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ClangFormatStyleOptions.rst?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/docs/ClangFormatStyleOptions.rst (original)
+++ cfe/trunk/docs/ClangFormatStyleOptions.rst Wed Jan 17 08:17:26 2018
@@ -994,9 +994,9 @@ the configuration (without a prefix: ``A
 
     .. code-block:: c++
 
-      Constructor()
-          : initializer1(),
-            initializer2()
+    Constructor()
+        : initializer1(),
+          initializer2()
 
   * ``BCIS_BeforeComma`` (in configuration: ``BeforeComma``)
     Break constructor initializers before the colon and commas, and align
@@ -1004,18 +1004,18 @@ the configuration (without a prefix: ``A
 
     .. 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 @@ the configuration (without a prefix: ``A
 
   * ``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,38 @@ the configuration (without a prefix: ``A
 
 
 **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 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. A matching delimiter 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.
+  There should be at most one specification per language and each delimiter
+  and enclosing function should not occur in multiple specifications.
 
   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.

Modified: cfe/trunk/include/clang/Format/Format.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/include/clang/Format/Format.h (original)
+++ cfe/trunk/include/clang/Format/Format.h Wed Jan 17 08:17:26 2018
@@ -1367,12 +1367,15 @@ struct FormatStyle {
     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;
     }
   };
@@ -1380,12 +1383,17 @@ struct FormatStyle {
   /// \brief 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 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.
+  /// A raw string with a matching delimiter or a matching enclosing function
+  /// name will be reformatted assuming the 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. A matching delimiter takes
+  /// precedence over a matching enclosing function name for determining the
+  /// language of the raw string contents.
+  ///
+  /// There should be at most one specification per language and each delimiter
+  /// and enclosing function should not occur in multiple specifications.
   ///
   /// To configure this in the .clang-format file, use:
   /// \code{.yaml}
@@ -1394,6 +1402,8 @@ struct FormatStyle {
   ///         Delimiters:
   ///           - 'pb'
   ///           - 'proto'
+  ///         EnclosingFunctions:
+  ///           - 'PARSE_TEXT_PROTO'
   ///         BasedOnStyle: google
   ///     - Language: Cpp
   ///         Delimiters:

Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Wed Jan 17 08:17:26 2018
@@ -105,32 +105,44 @@ static llvm::Optional<StringRef> getRawS
 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,6 +1449,26 @@ unsigned ContinuationIndenter::handleEnd
   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) {
@@ -1445,7 +1477,10 @@ ContinuationIndenter::getRawStringStyle(
   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);

Modified: cfe/trunk/lib/Format/ContinuationIndenter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.h?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.h (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.h Wed Jan 17 08:17:26 2018
@@ -38,10 +38,14 @@ class WhitespaceManager;
 
 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 {

Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Wed Jan 17 08:17:26 2018
@@ -457,6 +457,7 @@ template <> struct MappingTraits<FormatS
   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 @@ FormatStyle getGoogleStyle(FormatStyle::
           "textproto",
           "TEXTPROTO",
       },
+      /*EnclosingFunctionNames=*/
+       {
+           "EqualsProto",
+           "PARSE_TEXT_PROTO",
+           "ParseTextProto",
+       },
       /*BasedOnStyle=*/"google",
   }};
   GoogleStyle.SpacesBeforeTrailingComments = 2;

Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Wed Jan 17 08:17:26 2018
@@ -10408,8 +10408,18 @@ TEST_F(FormatTest, ParsesConfiguration)
 
   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"
@@ -10417,12 +10427,16 @@ TEST_F(FormatTest, ParsesConfiguration)
               "    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);
 }
 

Modified: cfe/trunk/unittests/Format/FormatTestRawStrings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestRawStrings.cpp?rev=322678&r1=322677&r2=322678&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestRawStrings.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestRawStrings.cpp Wed Jan 17 08:17:26 2018
@@ -65,23 +65,32 @@ protected:
   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 @@ TEST_F(FormatTestRawStrings, UsesConfigu
   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 @@ TEST_F(FormatTestRawStrings, DontFormatN
                    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




More information about the cfe-commits mailing list