-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[clang-format] Add OneLineFormatOffRegex option #137577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-format Author: Owen Pan (owenca) ChangesClose #54334 Full diff: https://github.com/llvm/llvm-project/pull/137577.diff 7 Files Affected:
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 3f8a5f49313b2..e3fe4a7529559 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -5195,6 +5195,28 @@ the configuration (without a prefix: ``Auto``).
Add a space in front of an Objective-C protocol list, i.e. use
``Foo <Protocol>`` instead of ``Foo<Protocol>``.
+.. _OneLineFormatOffRegex:
+
+**OneLineFormatOffRegex** (``String``) :versionbadge:`clang-format 21` :ref:`¶ <OneLineFormatOffRegex>`
+ A regular expression that describes markers for turning formatting off for
+ one line. If it matches a line comment that is the first/only token of a
+ line, clang-format skips the next line. Otherwise, clang-format skips the
+ line that contains a matched token.
+
+ .. code-block:: c++
+
+ // OneLineFormatOffRegex: ^(// NOLINT|logger$)
+ // results in the output below:
+ int a;
+ int b ; // NOLINT
+ int c;
+ // NOLINTNEXTLINE
+ int d ;
+ int e;
+ logger() ;
+ logger2();
+ my_logger();
+
.. _PPIndentWidth:
**PPIndentWidth** (``Integer``) :versionbadge:`clang-format 13` :ref:`¶ <PPIndentWidth>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3724c8cbc70fe..b22b3f13659ce 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -692,6 +692,7 @@ clang-format
top of the file.
- Add ``EnumTrailingComma`` option for inserting/removing commas at the end of
``enum`` enumerator lists.
+- Add ``OneLineFormatOffRegex`` option for turning formatting off for one line.
libclang
--------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index f6ceef08b46da..ce9a05f40be61 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3654,6 +3654,26 @@ struct FormatStyle {
/// \version 3.7
bool ObjCSpaceBeforeProtocolList;
+ /// A regular expression that describes markers for turning formatting off for
+ /// one line. If it matches a line comment that is the first/only token of a
+ /// line, clang-format skips the next line. Otherwise, clang-format skips the
+ /// line that contains a matched token.
+ /// \code
+ /// // OneLineFormatOffRegex: ^(// NOLINT|logger$)
+ /// // results in the output below:
+ /// int a;
+ /// int b ; // NOLINT
+ /// int c;
+ /// // NOLINTNEXTLINE
+ /// int d ;
+ /// int e;
+ /// logger() ;
+ /// logger2();
+ /// my_logger();
+ /// \endcode
+ /// \version 21
+ std::string OneLineFormatOffRegex;
+
/// Different ways to try to fit all constructor initializers on a line.
enum PackConstructorInitializersStyle : int8_t {
/// Always put each constructor initializer on its own line.
@@ -5399,6 +5419,7 @@ struct FormatStyle {
ObjCPropertyAttributeOrder == R.ObjCPropertyAttributeOrder &&
ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty &&
ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
+ OneLineFormatOffRegex == R.OneLineFormatOffRegex &&
PackConstructorInitializers == R.PackConstructorInitializers &&
PenaltyBreakAssignment == R.PenaltyBreakAssignment &&
PenaltyBreakBeforeFirstCallParameter ==
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 5a1c3f556b331..2f4b64ef4f5fe 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1100,6 +1100,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
+ IO.mapOptional("OneLineFormatOffRegex", Style.OneLineFormatOffRegex);
IO.mapOptional("PackConstructorInitializers",
Style.PackConstructorInitializers);
IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index a4c94ac411fe0..58991f9681c97 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -83,8 +83,42 @@ FormatTokenLexer::FormatTokenLexer(
ArrayRef<FormatToken *> FormatTokenLexer::lex() {
assert(Tokens.empty());
assert(FirstInLineIndex == 0);
+ const llvm::Regex FormatOffRegex(Style.OneLineFormatOffRegex);
+ enum { FO_None, FO_CurrentLine, FO_NextLine } FormatOff = FO_None;
do {
Tokens.push_back(getNextToken());
+ auto &Tok = *Tokens.back();
+ const auto NewlinesBefore = Tok.NewlinesBefore;
+ switch (FormatOff) {
+ case FO_CurrentLine:
+ if (NewlinesBefore == 0)
+ Tok.Finalized = true;
+ else
+ FormatOff = FO_None;
+ break;
+ case FO_NextLine:
+ if (NewlinesBefore == 1) {
+ FormatOff = FO_CurrentLine;
+ Tok.Finalized = true;
+ } else {
+ FormatOff = FO_None;
+ }
+ break;
+ default:
+ if (!FormattingDisabled && FormatOffRegex.match(Tok.TokenText)) {
+ if (Tok.TokenText.starts_with("//") &&
+ (NewlinesBefore > 0 || &Tok == Tokens.front())) {
+ FormatOff = FO_NextLine;
+ } else {
+ FormatOff = FO_CurrentLine;
+ for (auto *Token : reverse(Tokens)) {
+ Token->Finalized = true;
+ if (Token->NewlinesBefore > 0)
+ break;
+ }
+ }
+ }
+ }
if (Style.isJavaScript()) {
tryParseJSRegexLiteral();
handleTemplateStrings();
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 2b08b794792e9..f7ab5546c7193 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -295,6 +295,7 @@ TEST(ConfigParseTest, ParsesConfiguration) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_Cpp;
CHECK_PARSE("CommentPragmas: '// abc$'", CommentPragmas, "// abc$");
+ CHECK_PARSE("OneLineFormatOffRegex: // ab$", OneLineFormatOffRegex, "// ab$");
Style.QualifierAlignment = FormatStyle::QAS_Right;
CHECK_PARSE("QualifierAlignment: Leave", QualifierAlignment,
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 333d40d481025..3b07fc8e189c6 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -24954,6 +24954,82 @@ TEST_F(FormatTest, DisableRegions) {
"// clang-format on");
}
+TEST_F(FormatTest, OneLineFormatOffRegex) {
+ auto Style = getLLVMStyle();
+ Style.OneLineFormatOffRegex = "// format off$";
+
+ verifyFormat("// format off\n"
+ "int i ;\n"
+ "int j;",
+ " // format off\n"
+ "int i ;\n"
+ "int j ;",
+ Style);
+ verifyFormat("// format off?\n"
+ "int i;",
+ "// format off?\n"
+ "int i ;",
+ Style);
+ verifyFormat("f(\"// format off\");", "f(\"// format off\") ;", Style);
+
+ verifyFormat("int i;\n"
+ "// format off\n"
+ "int j ;\n"
+ "int k;",
+ "int i ;\n"
+ " // format off\n"
+ "int j ;\n"
+ "int k ;",
+ Style);
+
+ verifyFormat("int i;\n"
+ "int j ; // format off\n"
+ "int k;",
+ "int i ;\n"
+ "int j ; // format off\n"
+ "int k ;",
+ Style);
+
+ verifyFormat("// clang-format off\n"
+ "int i ;\n"
+ "int j ; // format off\n"
+ "int k ;\n"
+ "// clang-format on\n"
+ "f();",
+ "// clang-format off\n"
+ "int i ;\n"
+ "int j ; // format off\n"
+ "int k ;\n"
+ "// clang-format on\n"
+ "f() ;",
+ Style);
+
+ Style.OneLineFormatOffRegex = "^/\\* format off \\*/";
+ verifyFormat("int i;\n"
+ " /* format off */ int j ;\n"
+ "int k;",
+ "int i ;\n"
+ " /* format off */ int j ;\n"
+ "int k ;",
+ Style);
+ verifyFormat("f(\"/* format off */\");", "f(\"/* format off */\") ;", Style);
+
+ Style.ColumnLimit = 50;
+ Style.OneLineFormatOffRegex = "^LogErrorPrint$";
+ verifyFormat("myproject::LogErrorPrint(logger, \"Don't split me!\");\n"
+ "myproject::MyLogErrorPrinter(myLogger,\n"
+ " \"Split me!\");",
+ "myproject::LogErrorPrint(logger, \"Don't split me!\");\n"
+ "myproject::MyLogErrorPrinter(myLogger, \"Split me!\");",
+ Style);
+
+ Style.OneLineFormatOffRegex = "//(< clang-format off| NO_TRANSLATION)$";
+ verifyNoChange(
+ "int i ; //< clang-format off\n"
+ "msg = sprintf(\"Long string with placeholders.\"); // NO_TRANSLATION",
+ Style);
+}
+
TEST_F(FormatTest, DoNotCrashOnInvalidInput) {
format("? ) =");
verifyNoCrash("#define a\\\n /**/}");
|
@owenca your change seems to be causing a unit test failure in CodeGenTest.TestNonAlterTest which is impacting quite a few bots. Can you take a look and revert if you need time to investigate? |
It seems several of the listed failing bots did:
|
This reverts commit b8bb1cc which triggered an assertion failure in CodeGenTest.TestNonAlterTest.
Similar to the failure you reported in #134196 (comment), |
This reverts commit b8bb1cc which triggered an assertion failure in CodeGenTest.TestNonAlterTest.
This reverts commit b8bb1cc which triggered an assertion failure in CodeGenTest.TestNonAlterTest.
This reverts commit b8bb1cc which triggered an assertion failure in CodeGenTest.TestNonAlterTest.
This reverts commit b8bb1cc which triggered an assertion failure in CodeGenTest.TestNonAlterTest.
Close #54334