-
Notifications
You must be signed in to change notification settings - Fork 15.6k
[clang-format] Option to ignore macro definitions #70338
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
228301b to
1233f75
Compare
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
#67911 is a pull request, not an issue, i'm not sure what you're referring to |
owenca
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please refer to the policy for adding new options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let not leave TODO's lets just do it..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code path for when the statement is preceded by a comment seems different. It's not 100% unclear to me where to look to support that. Any hints would be appriciated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always comment every other check out, and run only this test case in a debugger to look where the change is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually tests with a (line and block) comment after the #define would be interesting too, should they be wrapped? Or the space after // added?
|
@tomekpaszek do you plan to finish this PR? we have been testing it internally on our code and would really like this to land in upstream LLVM. |
|
Yes, I just couldn't find time for it. I'll try to look into it within the next few days. Great to hear you there is interest in using it! |
851a28a to
4ef0518
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always comment every other check out, and run only this test case in a debugger to look where the change is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually tests with a (line and block) comment after the #define would be interesting too, should they be wrapped? Or the space after // added?
4ef0518 to
c5da2c4
Compare
|
@llvm/pr-subscribers-clang Author: Tomek (tomekpaszek) ChangesSometimes macro definitions contain a layout we don't want to change in any context. This PR adds a new style option This PR addresses issue #67991 Full diff: https://github.com/llvm/llvm-project/pull/70338.diff 7 Files Affected:
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 21342e1b89ea866..80565620d8f24bf 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3160,6 +3160,11 @@ the configuration (without a prefix: ``Auto``).
For example: `KJ_IF_MAYBE
<https://github.com/capnproto/capnproto/blob/master/kjdoc/tour.md#maybes>`_
+.. _IgnorePPDefinitions:
+
+**IgnorePPDefinitions** (``Boolean``) :versionbadge:`clang-format 18` :ref:`¶ <IgnorePPDefinitions>`
+ Ignore formatting in preprocessor definitions.
+
.. _IncludeBlocks:
**IncludeBlocks** (``IncludeBlocksStyle``) :versionbadge:`clang-format 6` :ref:`¶ <IncludeBlocks>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 3e9d1915badd87f..3af7241441c8b13 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2442,6 +2442,10 @@ struct FormatStyle {
/// <https://github.com/capnproto/capnproto/blob/master/kjdoc/tour.md#maybes>`_
/// \version 13
std::vector<std::string> IfMacros;
+
+ /// Ignore formatting in preprocessor definitions.
+ /// \version 18
+ bool IgnorePPDefinitions;
/// Specify whether access modifiers should have their own indentation level.
///
@@ -4719,6 +4723,7 @@ struct FormatStyle {
R.IncludeStyle.IncludeIsMainRegex &&
IncludeStyle.IncludeIsMainSourceRegex ==
R.IncludeStyle.IncludeIsMainSourceRegex &&
+ IgnorePPDefinitions == R.IgnorePPDefinitions &&
IndentAccessModifiers == R.IndentAccessModifiers &&
IndentCaseBlocks == R.IndentCaseBlocks &&
IndentCaseLabels == R.IndentCaseLabels &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index edb33f4af4defef..6e5ec754dfdcdd9 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1000,6 +1000,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
IO.mapOptional("ForEachMacros", Style.ForEachMacros);
IO.mapOptional("IfMacros", Style.IfMacros);
+ IO.mapOptional("IgnorePPDefinitions", Style.IgnorePPDefinitions);
IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks);
IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories);
IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex);
@@ -1504,6 +1505,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IfMacros.push_back("KJ_IF_MAYBE");
+ LLVMStyle.IgnorePPDefinitions = false;
LLVMStyle.IncludeStyle.IncludeCategories = {
{"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0, false},
{"^(<|\"(gtest|gmock|isl|json)/)", 3, 0, false},
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 280485d9a90d1bf..bbf6383ff7673f6 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -1355,6 +1355,8 @@ unsigned UnwrappedLineFormatter::format(
bool FixIndentation = (FixBadIndentation || ContinueFormatting) &&
Indent != TheLine.First->OriginalColumn;
bool ShouldFormat = TheLine.Affected || FixIndentation;
+ if (Style.IgnorePPDefinitions && TheLine.Type == LT_PreprocessorDirective)
+ ShouldFormat = false;
// We cannot format this line; if the reason is that the line had a
// parsing error, remember that.
if (ShouldFormat && TheLine.Type == LT_Invalid && Status) {
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 488d8dc07b1eae3..07cf966a08ff5e5 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1134,6 +1134,14 @@ void UnwrappedLineParser::parsePPDefine() {
return;
}
+ if (Style.IgnorePPDefinitions) {
+ do {
+ nextToken();
+ } while (!eof());
+ addUnwrappedLine();
+ return;
+ }
+
if (IncludeGuard == IG_IfNdefed &&
IncludeGuardToken->TokenText == FormatTok->TokenText) {
IncludeGuard = IG_Defined;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index f90ed178d99c286..7ce9ae26b36fbb9 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -166,6 +166,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(DerivePointerAlignment);
CHECK_PARSE_BOOL_FIELD(DerivePointerAlignment, "DerivePointerBinding");
CHECK_PARSE_BOOL(DisableFormat);
+ CHECK_PARSE_BOOL(IgnorePPDefinitions);
CHECK_PARSE_BOOL(IndentAccessModifiers);
CHECK_PARSE_BOOL(IndentCaseLabels);
CHECK_PARSE_BOOL(IndentCaseBlocks);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index b2d84f2ee389551..19cf521107c604b 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -24153,6 +24153,53 @@ TEST_F(FormatTest, WhitespaceSensitiveMacros) {
verifyNoChange("FOO(String-ized&Messy+But: :Still=Intentional);", Style);
}
+TEST_F(FormatTest, IgnorePPDefinitions) {
+ FormatStyle Style = getLLVMStyle();
+ Style.IgnorePPDefinitions = true;
+
+ verifyNoChange("#define A", Style);
+ verifyNoChange("#define A b", Style);
+ verifyNoChange("#define A ( args )", Style);
+ verifyNoChange("#define A ( args ) = func ( args )", Style);
+
+ verifyNoChange("#define A x:", Style);
+ verifyNoChange("#define A a. b", Style);
+
+ // Surrounded with formatted code
+ verifyFormat("int a;\n"
+ "#define A a\n"
+ "int a;",
+ "int a ;\n"
+ "#define A a\n"
+ "int a ;",
+ Style);
+
+ // Columns are not broken when a limit is set
+ Style.ColumnLimit = 10;
+ verifyNoChange("#define A a a a a", Style);
+ Style.ColumnLimit = 0;
+
+ // Multiline definition
+ verifyNoChange("#define A \\\n"
+ "Line one with spaces . \\\n"
+ " Line two.",
+ Style);
+ verifyNoChange("#define A \\\n"
+ "a a \\\n"
+ "a \\\na",
+ Style);
+ Style.AlignEscapedNewlines = FormatStyle::ENAS_Left;
+ verifyNoChange("#define A \\\n"
+ "a a \\\n"
+ "a \\\na",
+ Style);
+ Style.AlignEscapedNewlines = FormatStyle::ENAS_Right;
+ verifyNoChange("#define A \\\n"
+ "a a \\\n"
+ "a \\\na",
+ Style);
+}
+
TEST_F(FormatTest, VeryLongNamespaceCommentSplit) {
// These tests are not in NamespaceEndCommentsFixerTest because that doesn't
// test its interaction with line wrapping
|
mydeveloperday
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something here doesn't feel right
tomekpaszek
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something here doesn't feel right
Could you be more specific?
HazardyKnusperkeks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but wait for either of @owenca or @mydeveloperday .
owenca
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update ReleaseNotes.rst.
clang/include/clang/Format/Format.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename it to SkipMacroDefinition or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (Style.IgnorePPDefinitions && LineContainsPPDefinition(TheLine)) | |
| if (Style.IgnorePPDefinitions && TheLine.startsWith(tok::hash, tok::pp_define)) |
clang/include/clang/Format/Format.h
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// Ignore formatting in preprocessor definitions. | |
| /// Do not format macro definitions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| FormatStyle Style = getLLVMStyle(); | |
| auto Style = getLLVMStyle(); |
|
After giving more thoughts to this, I think what we really want is To the following: That is, only the body (except comments) of a macro definition is not formatted. |
I understand that:
|
We want to format e.g.
We don't want to change line splicing (if any) within the body. |
f91b383 to
72acbae
Compare
72acbae to
75ae623
Compare
| if (Style.SkipMacroDefinitionBody) { | ||
| do { | ||
| nextToken(); | ||
| } while (!eof()); | ||
| } else { | ||
| nextToken(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead, we can simply mark the tokens Finalized (after Line->InMacroBody is set to true below) so that the continuation indenter can be left alone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi!
Maybe it's a little late, but I wanted to let you know that I've tried that but it didn't give the expected results. Didn't have time to dig into this approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Np!
|
@tomekpaszek Hi Tomek, do you think you will have time to work on this soon? Otherwise, I can probably finish it off for you since we also want this feature. |
Hi tru, |
|
@owenca What's the things that still needs to be addressed for this to land? |
Closes #67991. See also: #70338 Co-authored-by: @tomekpaszek
Sometimes macro definitions contain a layout we don't want to change in any context. This PR adds a new style option
IgnorePPDefinitionsthat prevents clang-format from touching macro definitions.This PR addresses issue #67991