bersbersbers updated this revision to Diff 506336.
bersbersbers added a comment.

Rebased patch against main branch (previous patch was against 15.0.7 tag)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145435/new/

https://reviews.llvm.org/D145435

Files:
  clang/docs/ClangFormatStyleOptions.rst
  clang/include/clang/Format/Format.h
  clang/lib/Format/BreakableToken.cpp
  clang/lib/Format/BreakableToken.h
  clang/lib/Format/ContinuationIndenter.cpp
  clang/lib/Format/Format.cpp
  clang/lib/Format/UnwrappedLineParser.cpp

Index: clang/lib/Format/UnwrappedLineParser.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -4292,6 +4292,10 @@
   if (CommentPragmasRegex.match(IndentContent))
     return false;
 
+  // If comment is a style comment, treat as separate section.
+  if (IndentContent.ltrim().startswith(clang::format::StyleComment))
+    return false;
+
   // If Line starts with a line comment, then FormatTok continues the comment
   // section if its original column is greater or equal to the original start
   // column of the line.
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -3741,6 +3741,29 @@
   if (!getPredefinedStyle(FallbackStyleName, Style.Language, &FallbackStyle))
     return make_string_error("Invalid fallback style \"" + FallbackStyleName);
 
+  if (StyleName == "file") {
+    // Read style from first style comment at start of line in the code.
+    std::string Prefix{std::string("// ") + StyleComment};
+    size_t PrefixPos = StringRef::npos;
+    while ((PrefixPos = Code.find(Prefix, PrefixPos + 1)) != StringRef::npos) {
+      // For each prefix, locate respective start of line (SoL) and check text
+      // between prefix and start of line for non-whitespace (comments not at
+      // start of line up to whitespace may be quoted, commented out, ...).
+      if (const size_t SoL = Code.substr(0, PrefixPos).find_last_of("\r\n") + 1;
+          !Code.substr(SoL, PrefixPos - SoL).ltrim().empty()) {
+        continue;
+      }
+
+      // Use remainder of line as `StyleName` as if passed by `-style=...`;
+      // if no end of line (EoL) found, use remainder of file.
+      const size_t StylePos = PrefixPos + Prefix.size();
+      const size_t EoL = Code.find_first_of("\r\n", StylePos);
+      const size_t StyleLen = EoL - (EoL == StringRef::npos ? 0 : StylePos);
+      StyleName = Code.substr(StylePos, StyleLen);
+      break;
+    }
+  }
+
   llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 1>
       ChildFormatTextToApply;
 
Index: clang/lib/Format/ContinuationIndenter.cpp
===================================================================
--- clang/lib/Format/ContinuationIndenter.cpp
+++ clang/lib/Format/ContinuationIndenter.cpp
@@ -2192,7 +2192,7 @@
     }();
     if (!Style.ReflowComments ||
         CommentPragmasRegex.match(Current.TokenText.substr(2)) ||
-        switchesFormatting(Current) || !RegularComments) {
+        setsStyle(Current) || switchesFormatting(Current) || !RegularComments) {
       return nullptr;
     }
     return std::make_unique<BreakableLineCommentSection>(
Index: clang/lib/Format/BreakableToken.h
===================================================================
--- clang/lib/Format/BreakableToken.h
+++ clang/lib/Format/BreakableToken.h
@@ -27,6 +27,10 @@
 namespace clang {
 namespace format {
 
+/// Checks if \p Token sets style, basically, // clang-format style=....
+/// \p Token must be a line comment.
+bool setsStyle(const FormatToken &Token);
+
 /// Checks if \p Token switches formatting, like /* clang-format off */.
 /// \p Token must be a comment.
 bool switchesFormatting(const FormatToken &Token);
Index: clang/lib/Format/BreakableToken.cpp
===================================================================
--- clang/lib/Format/BreakableToken.cpp
+++ clang/lib/Format/BreakableToken.cpp
@@ -216,6 +216,12 @@
   return BreakableToken::Split(StringRef::npos, 0);
 }
 
+bool setsStyle(const FormatToken &Token) {
+  assert(Token.is(TT_LineComment) && "style is set by line-comment token");
+  StringRef Content = Token.TokenText.substr(2).ltrim();
+  return Content.startswith(StyleComment);
+}
+
 bool switchesFormatting(const FormatToken &Token) {
   assert((Token.is(TT_BlockComment) || Token.is(TT_LineComment)) &&
          "formatting regions are switched by comment tokens");
@@ -339,7 +345,7 @@
   // Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
   bool hasSpecialMeaningPrefix = false;
   for (StringRef Prefix :
-       {"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
+       {"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* ", StyleComment}) {
     if (Content.startswith(Prefix)) {
       hasSpecialMeaningPrefix = true;
       break;
@@ -743,6 +749,7 @@
     IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
   return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
          mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
+         !setsStyle(tokenAt(LineIndex)) &&
          !switchesFormatting(tokenAt(LineIndex));
 }
 
@@ -834,12 +841,13 @@
 
         assert(Lines[i].size() > IndentPrefix.size());
         const auto FirstNonSpace = Lines[i][IndentPrefix.size()];
+        const bool IsStyleComment = LineTok && setsStyle(*LineTok);
         const bool IsFormatComment = LineTok && switchesFormatting(*LineTok);
         const bool LineRequiresLeadingSpace =
             !NoSpaceBeforeFirstCommentChar() ||
             (FirstNonSpace == '}' && FirstLineSpaceChange != 0);
         const bool AllowsSpaceChange =
-            !IsFormatComment &&
+            !IsStyleComment && !IsFormatComment &&
             (SpacesInPrefix != 0 || LineRequiresLeadingSpace);
 
         if (PrefixSpaceChange[i] > 0 && AllowsSpaceChange) {
@@ -1048,6 +1056,7 @@
   // We do reflow in that case in block comments.
   return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
          mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
+         !setsStyle(tokenAt(LineIndex)) &&
          !switchesFormatting(tokenAt(LineIndex)) &&
          OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1];
 }
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -4651,6 +4651,9 @@
 bool isClangFormatOn(StringRef Comment);
 bool isClangFormatOff(StringRef Comment);
 
+// Contents of style comments to set style within code files.
+constexpr char const *StyleComment{"clang-format style="};
+
 } // end namespace format
 } // end namespace clang
 
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -28,12 +28,16 @@
 Configuring Style with clang-format
 ===================================
 
-:program:`clang-format` supports two ways to provide custom style options:
+:program:`clang-format` supports three ways to provide custom style options:
 directly specify style configuration in the ``-style=`` command line option or
-use ``-style=file`` and put style configuration in the ``.clang-format`` or
+use ``-style=file`` and put style configuration either in a style comment
+(``// clang-format style=``) in each code file or in the ``.clang-format`` or
 ``_clang-format`` file in the project directory.
 
 When using ``-style=file``, :program:`clang-format` for each input file will
+locate the first ``// clang-format style=`` style comment at the start of a line
+(ignoring preceding whitespace), and use the remainder of that line as the
+style for this whole file; only if no such style comment can be found, it will
 try to find the ``.clang-format`` file located in the closest parent directory
 of the input file. When the standard input is used, the search is started from
 the current directory.
@@ -106,6 +110,18 @@
 
   -style='{key1: value1, key2: value2, ...}'
 
+Similar syntax be used within the file, such as
+
+.. code-block:: console
+
+  // clang-format style={key1: value1, key2: value2, ...}
+
+or even
+
+.. code-block:: console
+
+  // clang-format style=file:<format_file_path>
+
 
 Disabling Formatting on a Piece of Code
 =======================================
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to