[clang] f21c704 - clang-format: Add ControlStatementsExceptForEachMacros option to SpaceBeforeParens
Author: Daan De Meyer Date: 2020-05-06T20:59:24+02:00 New Revision: f21c704553a8af7012eaf1ab777e2aa1a55cc86d URL: https://github.com/llvm/llvm-project/commit/f21c704553a8af7012eaf1ab777e2aa1a55cc86d DIFF: https://github.com/llvm/llvm-project/commit/f21c704553a8af7012eaf1ab777e2aa1a55cc86d.diff LOG: clang-format: Add ControlStatementsExceptForEachMacros option to SpaceBeforeParens Summary: systemd recently added a clang-format file. One issue I encountered in using clang-format on systemd is that systemd does not add a space before the parens of their foreach macros but clang-format always adds a space. This does not seem to be configurable in clang-format. This revision adds the ControlStatementsExceptForEachMacros option to SpaceBeforeParens which puts a space before all control statement parens except ForEach macros. This drastically reduces the amount of changes when running clang-format on systemd's source code. Reviewers: MyDeveloperDay, krasimir, mitchell-stellar Reviewed By: MyDeveloperDay Subscribers: cfe-commits Tags: #clang-format, #clang Differential Revision: https://reviews.llvm.org/D78869 Added: Modified: clang/docs/ClangFormatStyleOptions.rst clang/include/clang/Format/Format.h clang/lib/Format/Format.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTest.cpp Removed: diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index ce26b06bf171..3ea503a592ac 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2336,6 +2336,19 @@ the configuration (without a prefix: ``Auto``). } } + * ``SBPO_ControlStatementsExceptForEachMacros`` (in configuration: ``ControlStatementsExceptForEachMacros``) +Same as ``SBPO_ControlStatements`` except this option doesn't apply to +ForEach macros. This is useful in projects where ForEach macros are +treated as function calls instead of control statements. + +.. code-block:: c++ + + void f() { + Q_FOREACH(...) { + f(); + } + } + * ``SBPO_NonEmptyParentheses`` (in configuration: ``NonEmptyParentheses``) Put a space before opening parentheses only if the parentheses are not empty i.e. '()' diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 011cf599d526..f8f2903dde57 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1983,6 +1983,17 @@ struct FormatStyle { ///} /// \endcode SBPO_ControlStatements, +/// Same as ``SBPO_ControlStatements`` except this option doesn't apply to +/// ForEach macros. This is useful in projects where ForEach macros are +/// treated as function calls instead of control statements. +/// \code +///void f() { +/// Q_FOREACH(...) { +///f(); +/// } +///} +/// \endcode +SBPO_ControlStatementsExceptForEachMacros, /// Put a space before opening parentheses only if the parentheses are not /// empty i.e. '()' /// \code diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 961cb92ebd40..1fd7d613f9fb 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -329,6 +329,8 @@ struct ScalarEnumerationTraits { IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); IO.enumCase(Value, "ControlStatements", FormatStyle::SBPO_ControlStatements); +IO.enumCase(Value, "ControlStatementsExceptForEachMacros", +FormatStyle::SBPO_ControlStatementsExceptForEachMacros); IO.enumCase(Value, "NonEmptyParentheses", FormatStyle::SBPO_NonEmptyParentheses); IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 734dbdc1b6f3..408f68e35418 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2900,6 +2900,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return true; +if (Style.SpaceBeforeParens == +FormatStyle::SBPO_ControlStatementsExceptForEachMacros && +Left.is(TT_ForEachMacro)) + return false; return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 9fdf2e728472..aba209b4252d 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -972,6 +972,17 @@
[clang] 7dd42ec - clang: Exclude efi_main from -Wmissing-prototypes
Author: Daan De Meyer Date: 2021-02-20T20:00:50Z New Revision: 7dd42ecfa2a29bac89c965544c14b32805c8f02b URL: https://github.com/llvm/llvm-project/commit/7dd42ecfa2a29bac89c965544c14b32805c8f02b DIFF: https://github.com/llvm/llvm-project/commit/7dd42ecfa2a29bac89c965544c14b32805c8f02b.diff LOG: clang: Exclude efi_main from -Wmissing-prototypes When compiling UEFI applications, the main function is named efi_main() instead of main(). Let's exclude efi_main() from -Wmissing-prototypes as well to avoid warnings when working on UEFI applications. Differential Revision: https://reviews.llvm.org/D95746 Added: Modified: clang/lib/Sema/SemaDecl.cpp clang/test/Sema/no-warn-missing-prototype.c Removed: diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index cee107096947..0f5b5332364a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13873,7 +13873,7 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, // Don't warn about 'main'. if (isa(FD->getDeclContext()->getRedeclContext())) if (IdentifierInfo *II = FD->getIdentifier()) - if (II->isStr("main")) + if (II->isStr("main") || II->isStr("efi_main")) return false; // Don't warn about inline functions. diff --git a/clang/test/Sema/no-warn-missing-prototype.c b/clang/test/Sema/no-warn-missing-prototype.c index 4dbc25755922..6059b6aa0f14 100644 --- a/clang/test/Sema/no-warn-missing-prototype.c +++ b/clang/test/Sema/no-warn-missing-prototype.c @@ -4,3 +4,7 @@ int main() { return 0; } + +int efi_main() { + return 0; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 5a6dac6 - LiteralSupport: Don't assert() on invalid input
Author: Daan De Meyer Date: 2021-11-17T23:51:30Z New Revision: 5a6dac66db67225e2443f4e61dfe9d2f96780611 URL: https://github.com/llvm/llvm-project/commit/5a6dac66db67225e2443f4e61dfe9d2f96780611 DIFF: https://github.com/llvm/llvm-project/commit/5a6dac66db67225e2443f4e61dfe9d2f96780611.diff LOG: LiteralSupport: Don't assert() on invalid input When using clangd, it's possible to trigger assertions in NumericLiteralParser and CharLiteralParser when switching git branches. This commit removes the initial asserts on invalid input and replaces those asserts with the error handling mechanism from those respective classes instead. This allows clangd to gracefully recover without crashing. See https://github.com/clangd/clangd/issues/888 for more information on the clangd crashes. Added: Modified: clang/include/clang/Basic/DiagnosticLexKinds.td clang/lib/Lex/LiteralSupport.cpp Removed: diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 805dcab2e0084..a4436208799f9 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -269,7 +269,9 @@ def err_bad_character_encoding : Error< def warn_bad_character_encoding : ExtWarn< "illegal character encoding in character literal">, InGroup; -def err_lexing_string : Error<"failure when lexing a string">; +def err_lexing_string : Error<"failure when lexing a string literal">; +def err_lexing_char : Error<"failure when lexing a character literal">; +def err_lexing_numeric : Error<"failure when lexing a numeric literal">; def err_placeholder_in_source : Error<"editor placeholder in source file">; //===--===// diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index a8022812a3636..76c8b324671d7 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -693,12 +693,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, : SM(SM), LangOpts(LangOpts), Diags(Diags), ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) { - // This routine assumes that the range begin/end matches the regex for integer - // and FP constants (specifically, the 'pp-number' regex), and assumes that - // the byte at "*end" is both valid and not part of the regex. Because of - // this, it doesn't have to check for 'overscan' in various places. - assert(!isPreprocessingNumberBody(*ThisTokEnd) && "didn't maximally munch?"); - s = DigitsBegin = ThisTokBegin; saw_exponent = false; saw_period = false; @@ -718,6 +712,16 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isAccum = false; hadError = false; + // This routine assumes that the range begin/end matches the regex for integer + // and FP constants (specifically, the 'pp-number' regex), and assumes that + // the byte at "*end" is both valid and not part of the regex. Because of + // this, it doesn't have to check for 'overscan' in various places. + if (isPreprocessingNumberBody(*ThisTokEnd)) { +Diags.Report(TokLoc, diag::err_lexing_numeric); +hadError = true; +return; + } + if (*s == '0') { // parse radix ParseNumberStartingWithZero(TokLoc); if (hadError) @@ -1432,7 +1436,12 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, ++begin; // Skip over the entry quote. - assert(begin[0] == '\'' && "Invalid token lexed"); + if (begin[0] != '\'') { +PP.Diag(Loc, diag::err_lexing_char); +HadError = true; +return; + } + ++begin; // Remove an optional ud-suffix. ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From 00f2edbda351d0790f4f71aabaf59342cd6ce424 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst | 2 ++ .../disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp| 13 +++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..0ad5948e0a448 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -58,6 +58,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. Verilog: .sv .svh .v .vh --cursor=- The position of the cursor when invoking clang-format from an editor integration +--disable-format - If set, only sort includes if include sorting + is enabled --dry-run - If set, do not actually make the formatting changes --dump-config - Dump configuration options to stdout and exit. Can be used with -style option. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..62acf4ab71fbd --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -style=LLVM -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..9d40b6db4329a 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -214,6 +214,12 @@ static cl::opt ListIgnored("list-ignored", cl::desc("List ignored files."), cl::cat(ClangFormatCategory), cl::Hidden); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + namespace clang { namespace format { @@ -506,8 +512,11 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) { +FormatChanges = +reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + } Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] include-cleaner: Report function decls from __cleanup__ as used (PR #138669)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/138669 None Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer edited https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer edited https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 4edcb6e0a0d4272a72a272ae97b32439f597ebf3 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IncludeSortKey option Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting by stem instead of full path by introducing a new option IncludeSortKey with two values "Path" and "Stem". --- clang/docs/ClangFormatStyleOptions.rst| 13 + clang/include/clang/Format/Format.h | 1 + .../clang/Tooling/Inclusions/IncludeStyle.h | 17 clang/lib/Format/Format.cpp | 27 +-- clang/lib/Tooling/Inclusions/IncludeStyle.cpp | 6 + clang/unittests/Format/SortIncludesTest.cpp | 16 +++ 6 files changed, 72 insertions(+), 8 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 3f8a5f49313b2..248d489b1a878 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4226,6 +4226,19 @@ the configuration (without a prefix: ``Auto``). ``ClassImpl.hpp`` would not have the main include file put on top before any other include. +.. _IncludeSortKey: + +**IncludeSortKey** (``IncludeSortKeyDiscriminator``) :versionbadge:`clang-format 20` :ref:`¶ ` + When sorting includes in each block, sort by the specified sort key + + Possible values: + + * ``ISK_Path`` (in configuration: ``Path``) +Includes are sorted by their full path (the default). + + * ``ISK_Stem`` (in configuration: ``AngleBracket``) +Includes are sorted by their full path without the file extension. + .. _IndentAccessModifiers: **IndentAccessModifiers** (``Boolean``) :versionbadge:`clang-format 13` :ref:`¶ ` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index f6ceef08b46da..23ce34b560198 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5368,6 +5368,7 @@ struct FormatStyle { IncludeStyle.IncludeIsMainSourceRegex == R.IncludeStyle.IncludeIsMainSourceRegex && IncludeStyle.MainIncludeChar == R.IncludeStyle.MainIncludeChar && + IncludeStyle.IncludeSortKey == R.IncludeStyle.IncludeSortKey && IndentAccessModifiers == R.IndentAccessModifiers && IndentCaseBlocks == R.IndentCaseBlocks && IndentCaseLabels == R.IndentCaseLabels && diff --git a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h index fba90d8c51a66..8df8f54e7ee0e 100644 --- a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h +++ b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h @@ -166,6 +166,15 @@ struct IncludeStyle { /// directives that use the specified character are considered. /// \version 19 MainIncludeCharDiscriminator MainIncludeChar; + + enum IncludeSortKeyDiscriminator : int8_t { +/// Includes are sorted alphabetically by their full path. +ISK_Path, +/// Includes are sorted alphabetically by their full path without file extension. +ISK_Stem, + }; + + IncludeSortKeyDiscriminator IncludeSortKey; }; } // namespace tooling @@ -197,6 +206,14 @@ struct ScalarEnumerationTraits< clang::tooling::IncludeStyle::MainIncludeCharDiscriminator &Value); }; +template <> +struct ScalarEnumerationTraits< +clang::tooling::IncludeStyle::IncludeSortKeyDiscriminator> { + static void enumeration( + IO &IO, + clang::tooling::IncludeStyle::IncludeSortKeyDiscriminator &Value); +}; + } // namespace yaml } // namespace llvm diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 5a1c3f556b331..12abc753d9058 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1062,6 +1062,7 @@ template <> struct MappingTraits { IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); +IO.mapOptional("IncludeSortKey", Style.IncludeStyle.IncludeSortKey); IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); @@ -3219,17 +3220,27 @@ static void sortCppIncludes(const FormatStyle &Style
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer edited https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
DaanDeMeyer wrote: @HazardyKnusperkeks @owenca Updated PR to introduce a new option `IncludeSortKey`, PTAL! https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 73a18a033e0d978d1662a391fedf731dbad7de27 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IncludeSortKey option Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting by stem instead of full path by introducing a new option IncludeSortKey with two values "Path" and "Stem". --- clang/docs/ClangFormatStyleOptions.rst| 13 + clang/include/clang/Format/Format.h | 1 + .../clang/Tooling/Inclusions/IncludeStyle.h | 18 clang/lib/Format/Format.cpp | 29 ++- clang/lib/Tooling/Inclusions/IncludeStyle.cpp | 6 clang/unittests/Format/SortIncludesTest.cpp | 16 ++ 6 files changed, 75 insertions(+), 8 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 3f8a5f49313b2..248d489b1a878 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4226,6 +4226,19 @@ the configuration (without a prefix: ``Auto``). ``ClassImpl.hpp`` would not have the main include file put on top before any other include. +.. _IncludeSortKey: + +**IncludeSortKey** (``IncludeSortKeyDiscriminator``) :versionbadge:`clang-format 20` :ref:`¶ ` + When sorting includes in each block, sort by the specified sort key + + Possible values: + + * ``ISK_Path`` (in configuration: ``Path``) +Includes are sorted by their full path (the default). + + * ``ISK_Stem`` (in configuration: ``AngleBracket``) +Includes are sorted by their full path without the file extension. + .. _IndentAccessModifiers: **IndentAccessModifiers** (``Boolean``) :versionbadge:`clang-format 13` :ref:`¶ ` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index f6ceef08b46da..23ce34b560198 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5368,6 +5368,7 @@ struct FormatStyle { IncludeStyle.IncludeIsMainSourceRegex == R.IncludeStyle.IncludeIsMainSourceRegex && IncludeStyle.MainIncludeChar == R.IncludeStyle.MainIncludeChar && + IncludeStyle.IncludeSortKey == R.IncludeStyle.IncludeSortKey && IndentAccessModifiers == R.IndentAccessModifiers && IndentCaseBlocks == R.IndentCaseBlocks && IndentCaseLabels == R.IndentCaseLabels && diff --git a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h index fba90d8c51a66..6699a667c6daa 100644 --- a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h +++ b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h @@ -166,6 +166,16 @@ struct IncludeStyle { /// directives that use the specified character are considered. /// \version 19 MainIncludeCharDiscriminator MainIncludeChar; + + enum IncludeSortKeyDiscriminator : int8_t { +/// Includes are sorted alphabetically by their full path. +ISK_Path, +/// Includes are sorted alphabetically by their full path without file +/// extension. +ISK_Stem, + }; + + IncludeSortKeyDiscriminator IncludeSortKey; }; } // namespace tooling @@ -197,6 +207,14 @@ struct ScalarEnumerationTraits< clang::tooling::IncludeStyle::MainIncludeCharDiscriminator &Value); }; +template <> +struct ScalarEnumerationTraits< +clang::tooling::IncludeStyle::IncludeSortKeyDiscriminator> { + static void + enumeration(IO &IO, + clang::tooling::IncludeStyle::IncludeSortKeyDiscriminator &Value); +}; + } // namespace yaml } // namespace llvm diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 5a1c3f556b331..c2aa44e4d1f25 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1062,6 +1062,7 @@ template <> struct MappingTraits { IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); +IO.mapOptional("IncludeSortKey", Style.IncludeStyle.IncludeSortKey); IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); @@ -3219,17 +3220,29 @@ static void sortCppIncludes(const FormatSt
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From e4d8ac466061f098f399c9a662420da4acb5bb8b Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst | 2 ++ .../disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp| 13 +++-- 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..62acf4ab71fbd --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -style=LLVM -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..d7cc37e799c9e 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,11 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) { +FormatChanges = +reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + } Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From b023d2698915ea7d269a9afe8f11de162a39e53d Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst| 2 ++ .../Format/disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp | 11 +-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..595309d478a1e --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..c23d3dda4b444 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,9 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + // if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) + FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From 10e997e7707f0d04b7c66da8ab4d85435dc2f8ba Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst| 2 ++ .../Format/disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp | 11 +-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..595309d478a1e --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..da3d7edf2649f 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,9 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) +FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From 5a2912abe37c04e1ad15e282867e16f010ec1fe6 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst| 2 ++ .../Format/disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp | 11 +-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..62acf4ab71fbd --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -style=LLVM -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..da3d7edf2649f 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,9 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) +FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From c7b25ee74e78a6ff6f0fc1fdf2cf0ea24381be89 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst| 2 ++ .../Format/disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp | 11 +-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..d2cbca0d3eb50 --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -disable-format | FileCheck %s + +#include +#include + +int *a ; +// CHECK: +// CHECK-NEXT: +// CHECK: int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..da3d7edf2649f 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,9 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) +FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From 55b9af0981da56e777e10fd959edcc91c31f03f6 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst| 2 ++ .../Format/disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp | 11 +-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..595309d478a1e --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..da3d7edf2649f 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,9 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) +FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/137617 When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. >From f81803b7b81634871a1a8d96a599e85196979eef Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst | 2 ++ clang/tools/clang-format/ClangFormat.cpp | 11 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..a0de662b5c93b 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -95,6 +95,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. determined by the QualifierAlignment style flag --sort-includes- If set, overrides the include sorting behavior determined by the SortIncludes style flag +--disable-format - If set, only sort includes if include sorting + is enabled --style= - Set coding style. can be: 1. A preset: LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit. diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..da3d7edf2649f 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -120,6 +120,12 @@ static cl::opt "determined by the SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + static cl::opt QualifierAlignment( "qualifier-alignment", cl::desc("If set, overrides the qualifier alignment style\n" @@ -506,8 +512,9 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) +FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
DaanDeMeyer wrote: > Can't you just run the `llvm-include-order` clang-tidy check instead? Does that take `IncludeBlocks` and `IncludeCategories` from `.clang-format` into account? https://github.com/llvm/llvm-project/pull/137617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
DaanDeMeyer wrote: I don't mind the exact interface too much tbh, I would just like to be able to run clang-format again to only sort includes without doing any other formatting. Happy to implement whatever makes folks happy. https://github.com/llvm/llvm-project/pull/137617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137617 >From ab0fe63baf2044a4768835c359f7068dfba7d81d Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 28 Apr 2025 13:07:50 +0200 Subject: [PATCH] clang-format: Add -disable-format option When https://github.com/llvm/llvm-project/issues/27416 was fixed it became impossible to only use clang-format for include sorting. Let's introduce an option -disable-format to make it possible again to only sort includes with clang-format without doing any other formatting. --- clang/docs/ClangFormat.rst| 2 ++ .../disable-format-enable-include-sorting.cpp | 9 + clang/tools/clang-format/ClangFormat.cpp | 15 --- 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 clang/test/Format/disable-format-enable-include-sorting.cpp diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 92af06e5083d6..0ad5948e0a448 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -58,6 +58,8 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. Verilog: .sv .svh .v .vh --cursor=- The position of the cursor when invoking clang-format from an editor integration +--disable-format - If set, only sort includes if include sorting + is enabled --dry-run - If set, do not actually make the formatting changes --dump-config - Dump configuration options to stdout and exit. Can be used with -style option. diff --git a/clang/test/Format/disable-format-enable-include-sorting.cpp b/clang/test/Format/disable-format-enable-include-sorting.cpp new file mode 100644 index 0..62acf4ab71fbd --- /dev/null +++ b/clang/test/Format/disable-format-enable-include-sorting.cpp @@ -0,0 +1,9 @@ +// RUN: clang-format %s -sort-includes -style=LLVM -disable-format | FileCheck %s + +#include +#include +// CHECK: +// CHECK-NEXT: + +// CHECK: int *a ; +int *a ; diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index c45e3a2c28327..ed5b4fdd87293 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -214,6 +214,12 @@ static cl::opt ListIgnored("list-ignored", cl::desc("List ignored files."), cl::cat(ClangFormatCategory), cl::Hidden); +static cl::opt +DisableFormat("disable-format", + cl::desc("If set, only sort includes if include sorting\n" + "is enabled"), + cl::cat(ClangFormatCategory)); + namespace clang { namespace format { @@ -506,9 +512,12 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = - reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); - Replaces = Replaces.merge(FormatChanges); + Replacements FormatChanges; + if (DisableFormat.getNumOccurrences() == 0 || !DisableFormat) { +FormatChanges = +reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); +Replaces = Replaces.merge(FormatChanges); + } if (DryRun) { return Replaces.size() > (IsJson ? 1u : 0u) && emitReplacementWarnings(Replaces, AssumedFileName, Code); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
DaanDeMeyer wrote: > You definitely need some tests. And I'm not sure if everyone would like that, > of if it should be an option. I was hoping to get some feedback on whether it should be an option or not before adding tests. https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/137840 Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ We'll now get """ /#include "analyze.h" /#include "analyze-blame.h" """ >From 33b26cd645f814c83d2cc3b621c34526d0be1d29 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Sort includes by stem rather than full filename Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ We'll now get """ /#include "analyze.h" /#include "analyze-blame.h" """ --- clang/lib/Format/Format.cpp | 18 ++ 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 5a1c3f556b331..bc1e681c9be78 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3219,17 +3219,19 @@ static void sortCppIncludes(const FormatStyle &Style, if (Style.SortIncludes == FormatStyle::SI_CaseInsensitive) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); + const auto LHSStem = llvm::sys::path::stem(Includes[LHSI].Filename); + const auto RHSStem = llvm::sys::path::stem(Includes[RHSI].Filename); + const auto LHSStemLower = LHSStem.lower(); + const auto RHSStemLower = RHSStem.lower(); + return std::tie(Includes[LHSI].Priority, LHSStemLower, LHSStem) < + std::tie(Includes[RHSI].Priority, RHSStemLower, RHSStem); }); } else { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); + const auto LHSStem = llvm::sys::path::stem(Includes[LHSI].Filename); + const auto RHSStem = llvm::sys::path::stem(Includes[RHSI].Filename); + return std::tie(Includes[LHSI].Priority, LHSStem) < + std::tie(Includes[RHSI].Priority, RHSStem); }); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer edited https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer edited https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 4747e31443d9dc273f875782f32e2e47ca9c2cbf Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Sort includes by stem rather than full filename Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ We'll now get """ /#include "analyze.h" /#include "analyze-blame.h" """ --- clang/lib/Format/Format.cpp | 22 ++ 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 5a1c3f556b331..3dc663e6fa872 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3219,17 +3219,23 @@ static void sortCppIncludes(const FormatStyle &Style, if (Style.SortIncludes == FormatStyle::SI_CaseInsensitive) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); + SmallString<128> LHSStem = Includes[LHSI].Filename; + SmallString<128> RHSStem = Includes[RHSI].Filename; + llvm::sys::path::replace_extension(LHSStem, ""); + llvm::sys::path::replace_extension(RHSStem, ""); + const auto LHSStemLower = LHSStem.str().lower(); + const auto RHSStemLower = RHSStem.str().lower(); + return std::tie(Includes[LHSI].Priority, LHSStemLower, LHSStem) < + std::tie(Includes[RHSI].Priority, RHSStemLower, RHSStem); }); } else { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); + SmallString<128> LHSStem = Includes[LHSI].Filename; + SmallString<128> RHSStem = Includes[RHSI].Filename; + llvm::sys::path::replace_extension(LHSStem, ""); + llvm::sys::path::replace_extension(RHSStem, ""); + return std::tie(Includes[LHSI].Priority, LHSStem) < + std::tie(Includes[RHSI].Priority, RHSStem); }); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Sort includes by stem rather than full filename (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From ce0cb8586871f30f7e0883209f4bd30bf63471c5 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Sort includes by stem rather than full filename Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ We'll now get """ /#include "analyze.h" /#include "analyze-blame.h" """ --- clang/lib/Format/Format.cpp | 22 + clang/unittests/Format/SortIncludesTest.cpp | 8 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 5a1c3f556b331..3dc663e6fa872 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3219,17 +3219,23 @@ static void sortCppIncludes(const FormatStyle &Style, if (Style.SortIncludes == FormatStyle::SI_CaseInsensitive) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); + SmallString<128> LHSStem = Includes[LHSI].Filename; + SmallString<128> RHSStem = Includes[RHSI].Filename; + llvm::sys::path::replace_extension(LHSStem, ""); + llvm::sys::path::replace_extension(RHSStem, ""); + const auto LHSStemLower = LHSStem.str().lower(); + const auto RHSStemLower = RHSStem.str().lower(); + return std::tie(Includes[LHSI].Priority, LHSStemLower, LHSStem) < + std::tie(Includes[RHSI].Priority, RHSStemLower, RHSStem); }); } else { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); + SmallString<128> LHSStem = Includes[LHSI].Filename; + SmallString<128> RHSStem = Includes[RHSI].Filename; + llvm::sys::path::replace_extension(LHSStem, ""); + llvm::sys::path::replace_extension(RHSStem, ""); + return std::tie(Includes[LHSI].Priority, LHSStem) < + std::tie(Includes[RHSI].Priority, RHSStem); }); } diff --git a/clang/unittests/Format/SortIncludesTest.cpp b/clang/unittests/Format/SortIncludesTest.cpp index f20862f5f7461..030e328bd3c68 100644 --- a/clang/unittests/Format/SortIncludesTest.cpp +++ b/clang/unittests/Format/SortIncludesTest.cpp @@ -1485,6 +1485,14 @@ TEST_F(SortIncludesTest, BlockCommentedOutIncludes) { verifyFormat(Code, sort(Code, "input.cpp", 0)); } +TEST_F(SortIncludesTest, SortViaStem) { + verifyFormat("#include \n" + "#include ", + sort("#include \n" +"#include ", +"input.h", 1)); +} + } // end namespace } // end namespace format } // end namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
@@ -4226,6 +4226,19 @@ the configuration (without a prefix: ``Auto``). ``ClassImpl.hpp`` would not have the main include file put on top before any other include. +.. _IncludeSortKey: + +**IncludeSortKey** (``IncludeSortKeyDiscriminator``) :versionbadge:`clang-format 20` :ref:`¶ ` + When sorting includes in each block, sort by the specified sort key + + Possible values: + + * ``ISK_Path`` (in configuration: ``Path``) DaanDeMeyer wrote: I think the comment is sufficient explanation of what `stem` means in this case? https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 7e2463f6fb9a3d64b1be25f2ea6ea91de2d4e982 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IncludeSortKey option Sorting by stem gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting by stem instead of full path by introducing a new option IncludeSortKey with two values "Path" and "Stem". --- clang/docs/ClangFormatStyleOptions.rst| 16 ++ clang/include/clang/Format/Format.h | 1 + .../clang/Tooling/Inclusions/IncludeStyle.h | 21 + clang/lib/Format/Format.cpp | 30 ++- clang/lib/Tooling/Inclusions/IncludeStyle.cpp | 6 clang/unittests/Format/SortIncludesTest.cpp | 16 ++ 6 files changed, 82 insertions(+), 8 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 3f8a5f49313b2..dbde3b5af 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4226,6 +4226,22 @@ the configuration (without a prefix: ``Auto``). ``ClassImpl.hpp`` would not have the main include file put on top before any other include. +.. _IncludeSortKey: + +**IncludeSortKey** (``IncludeSortKeyDiscriminator``) :versionbadge:`clang-format 21` :ref:`¶ ` + When sorting includes in each block, sort by the specified sort key. + + Possible values: + + * ``ISK_Path`` (in configuration: ``Path``) +Includes are sorted alphabetically by their full path. + + * ``ISK_Stem`` (in configuration: ``Stem``) +Includes are sorted alphabetically by their full path without the +file extension. + + + .. _IndentAccessModifiers: **IndentAccessModifiers** (``Boolean``) :versionbadge:`clang-format 13` :ref:`¶ ` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index f6ceef08b46da..23ce34b560198 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5368,6 +5368,7 @@ struct FormatStyle { IncludeStyle.IncludeIsMainSourceRegex == R.IncludeStyle.IncludeIsMainSourceRegex && IncludeStyle.MainIncludeChar == R.IncludeStyle.MainIncludeChar && + IncludeStyle.IncludeSortKey == R.IncludeStyle.IncludeSortKey && IndentAccessModifiers == R.IndentAccessModifiers && IndentCaseBlocks == R.IndentCaseBlocks && IndentCaseLabels == R.IndentCaseLabels && diff --git a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h index fba90d8c51a66..8145616757b2b 100644 --- a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h +++ b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h @@ -152,6 +152,19 @@ struct IncludeStyle { /// \version 10 std::string IncludeIsMainSourceRegex; + /// Available sort keys that can be used to sort includes in each block. + enum IncludeSortKeyDiscriminator : int8_t { +/// Includes are sorted alphabetically by their full path. +ISK_Path, +/// Includes are sorted alphabetically by their full path without the +/// file extension. +ISK_Stem, + }; + + /// When sorting includes in each block, sort by the specified sort key. + /// \version 21 + IncludeSortKeyDiscriminator IncludeSortKey; + /// Character to consider in the include directives for the main header. enum MainIncludeCharDiscriminator : int8_t { /// Main include uses quotes: ``#include "foo.hpp"`` (the default). @@ -197,6 +210,14 @@ struct ScalarEnumerationTraits< clang::tooling::IncludeStyle::MainIncludeCharDiscriminator &Value); }; +template <> +struct ScalarEnumerationTraits< +clang::tooling::IncludeStyle::IncludeSortKeyDiscriminator> { + static void + enumeration(IO &IO, + clang::tooling::IncludeStyle::IncludeSortKeyDiscriminator &Value); +}; + } // namespace yaml } // namespace llvm diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 5a1c3f556b331..6423166fc3c44 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1062,6 +1062,7 @@ template <> struct MappingTraits { IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); IO.mapOptional("IncludeIsMainSourceRegex", Style.IncludeStyle.IncludeIsMainSourceRegex); +IO.mapOptional("IncludeSortKey", Style.IncludeStyle
[clang] clang-format: Add IncludeSortKey option (PR #137840)
DaanDeMeyer wrote: Ping @owenca @HazardyKnusperkeks https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] include-cleaner: Report function decls from __cleanup__ as used (PR #138669)
DaanDeMeyer wrote: Ping @llvm/pr-subscribers-clangd @kadircet https://github.com/llvm/llvm-project/pull/138669 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
DaanDeMeyer wrote: > I would expect that file extensions be sorted regardless. For example: > > ``` > #include "a.h" > #include "a.inc" > #include "a-util.def" > #include "a-util.h" > ``` Addressed https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] include-cleaner: Report function decls from __cleanup__ as used (PR #138669)
DaanDeMeyer wrote: @kadircet Can you merge this for me? I got rid of my contributor access as I don't contribute enough to justify having it. https://github.com/llvm/llvm-project/pull/138669 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/140233 Instead of reporting the location of the attribute, let's report the location of the function reference that's passed to the cleanup attribute as the first argument. This is required as the attribute might be coming from a macro which means clang-include-cleaner skips the use as it gets attributed to the header file declaringt the macro and not to the main file. To make this work, we have to add a fake argument to the CleanupAttr constructor so we can pass in the original Expr alongside the function declaration. Fixes #140212 >From e430624ff48b4f64d110dcadae321a69e1ecc039 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 16 May 2025 12:08:47 +0200 Subject: [PATCH] [clang-include-cleaner] Make cleanup attr report expr location Instead of reporting the location of the attribute, let's report the location of the function reference that's passed to the cleanup attribute as the first argument. This is required as the attribute might be coming from a macro which means clang-include-cleaner skips the use as it gets attributed to the header file declaringt the macro and not to the main file. To make this work, we have to add a fake argument to the CleanupAttr constructor so we can pass in the original Expr alongside the function declaration. Fixes #140212 --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp | 2 +- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp | 2 +- clang/include/clang/Basic/Attr.td | 6 -- clang/lib/Sema/SemaDeclAttr.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index ba6eff49e9c98..a6f2559dd8e93 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -322,7 +322,7 @@ class ASTWalker : public RecursiveASTVisitor { } bool VisitCleanupAttr(CleanupAttr *attr) { -report(attr->getLocation(), attr->getFunctionDecl()); +report(attr->getExpr()->getExprLoc(), attr->getFunctionDecl()); return true; } diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 19695a34bd63e..0de0b77f33daf 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -573,7 +573,7 @@ TEST(WalkAST, OperatorNewDelete) { TEST(WalkAST, CleanupAttr) { testWalk("void* $explicit^freep(void *p);", - "void foo() { __attribute__((^__cleanup__(freep))) char* x = 0; }"); + "void foo() { __attribute__((__cleanup__(^freep))) char* x = 0; }"); } } // namespace diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ccd13a4cca4dd..e90d18d8435bf 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -226,7 +226,8 @@ class BoolArgument : Argument : Argument; class IntArgument : Argument; class StringArgument : Argument; -class ExprArgument : Argument; +class ExprArgument : Argument; class DeclArgument : Argument { DeclNode Kind = kind; @@ -1351,7 +1352,8 @@ def OSConsumesThis : InheritableAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; - let Args = [DeclArgument]; + let Args = [DeclArgument, + ExprArgument<"Expr", /*fake=*/1>]; let Subjects = SubjectList<[LocalVar]>; let Documentation = [CleanupDocs]; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 377595639bef1..6b1a42bcc392f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3620,7 +3620,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); + D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD, E)); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
DaanDeMeyer wrote: @kadircet Can you land this one as well? (Feel free to give me back the commit bit if that's in your power if you want me to land stuff myself after review) https://github.com/llvm/llvm-project/pull/140600 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140600 >From 0e6f4f49197748d470c8839e6c3117fad35adbfa Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 77 +++ .../clang-tidy/misc/IncludeCleanerCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 7 +- .../checks/misc/include-cleaner.rst | 11 +++ .../clang-tidy/IncludeCleanerTest.cpp | 58 ++ 5 files changed, 124 insertions(+), 33 deletions(-) diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..52a94f3c040aa 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -68,12 +70,19 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, HeaderSuffix += "$"; IgnoreHeadersRegex.emplace_back(HeaderSuffix); } + + if (UnusedIncludes == false && MissingIncludes == false) +this->configurationDiag("The check 'misc-include-cleaner' will not " +"perform any analysis because 'UnusedIncludes' and " +"'MissingIncludes' are both false."); } void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +209,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); - if (areDiagsSelfContained() || - InsertedHeaders.insert(Replacement->getReplacementText()).second) { -DB << FixItHint::CreateInsertion( -
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140600 >From 900e6b24fb244d9034cdf81f337dd457a451b915 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 77 +++ .../clang-tidy/misc/IncludeCleanerCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 7 +- .../checks/misc/include-cleaner.rst | 11 +++ .../misc/include-cleaner-wrong-config.cpp | 13 .../clang-tidy/IncludeCleanerTest.cpp | 58 ++ 6 files changed, 137 insertions(+), 33 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/include-cleaner-wrong-config.cpp diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..52a94f3c040aa 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -68,12 +70,19 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, HeaderSuffix += "$"; IgnoreHeadersRegex.emplace_back(HeaderSuffix); } + + if (UnusedIncludes == false && MissingIncludes == false) +this->configurationDiag("The check 'misc-include-cleaner' will not " +"perform any analysis because 'UnusedIncludes' and " +"'MissingIncludes' are both false."); } void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +209,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); -
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140600 >From 5f4601e6cfa185a6eacb044a9cfbd88008df60ea Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 77 +++ .../clang-tidy/misc/IncludeCleanerCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 7 +- .../checks/misc/include-cleaner.rst | 11 +++ .../clang-tidy/IncludeCleanerTest.cpp | 58 ++ 5 files changed, 124 insertions(+), 33 deletions(-) diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..52a94f3c040aa 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -68,12 +70,19 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, HeaderSuffix += "$"; IgnoreHeadersRegex.emplace_back(HeaderSuffix); } + + if (UnusedIncludes == false && MissingIncludes == false) +this->configurationDiag("The check 'misc-include-cleaner' will not " +"perform any analysis because 'UnusedIncludes' and " +"'MissingIncludes' are both false."); } void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +209,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); - if (areDiagsSelfContained() || - InsertedHeaders.insert(Replacement->getReplacementText()).second) { -DB << FixItHint::CreateInsertion( -
[clang-tools-extra] [clang-tools-extra] Add include mappings for getopt.h (PR #140726)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/140726 None >From 6345651bcbcee651922b04121662763e4cec48a3 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 20 May 2025 15:05:21 +0200 Subject: [PATCH] [clang-tools-extra] Add include mappings for getopt.h --- .../find-all-symbols/STLPostfixHeaderMap.cpp | 3 +++ clang-tools-extra/clangd/index/CanonicalIncludes.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp index 469323f0ee9d7..5b6919d446304 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp @@ -606,6 +606,9 @@ const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() { {"sys/xattr.h$", ""}, {"bits/epoll.h$", ""}, {"bits/eventfd.h$", ""}, + {"bits/getopt_core.h$", ""}, + {"bits/getopt_ext.h$", ""}, + {"bits/getopt_posix.h$", ""}, {"bits/inotify.h$", ""}, {"bits/ipc.h$", ""}, {"bits/ipctypes.h$", ""}, diff --git a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp index 785ec4086ea76..e3518e9beb6d2 100644 --- a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp +++ b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp @@ -621,6 +621,9 @@ const std::pair IncludeMappings[] = { {"sys/xattr.h", ""}, {"bits/epoll.h", ""}, {"bits/eventfd.h", ""}, +{"bits/getopt_core.h", ""}, +{"bits/getopt_ext.h", ""}, +{"bits/getopt_posix.h", ""}, {"bits/inotify.h", ""}, {"bits/ipc.h", ""}, {"bits/ipctypes.h", ""}, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tools-extra] Add include mappings for getopt.h (PR #140726)
DaanDeMeyer wrote: @kadircet Do you know if either of these two mappings get used by clang-include-cleaner? I couldn't find out where it does the mapping from glibc internal headers to public ones. https://github.com/llvm/llvm-project/pull/140726 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tools-extra] Add include mappings for (PR #140755)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/140755 None >From 2f84d866f97d5bb378327e102105e214803cec56 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 20 May 2025 18:16:36 +0200 Subject: [PATCH] [clang-tools-extra] Add include mappings for --- .../clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp | 1 + clang-tools-extra/clangd/index/CanonicalIncludes.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp index 469323f0ee9d7..81db67d965754 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp @@ -654,6 +654,7 @@ const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() { {"bits/syscall.h$", ""}, {"bits/syslog-path.h$", ""}, {"bits/termios.h$", ""}, + {"bits/timex.h$", ""}, {"bits/types.h$", ""}, {"bits/typesizes.h$", ""}, {"bits/uio.h$", ""}, diff --git a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp index 785ec4086ea76..d0a351df2a2ee 100644 --- a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp +++ b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp @@ -669,6 +669,7 @@ const std::pair IncludeMappings[] = { {"bits/syscall.h", ""}, {"bits/syslog-path.h", ""}, {"bits/termios.h", ""}, +{"bits/timex.h", ""}, {"bits/types.h", ""}, {"bits/types/siginfo_t.h", ""}, {"bits/types/struct_itimerspec.h", ""}, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140600 >From e68b81b128fd1c8a6fb7a462d0e610c4a7dcfa6a Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 78 +++ .../clang-tidy/misc/IncludeCleanerCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/misc/include-cleaner.rst | 13 +++- .../clang-tidy/IncludeCleanerTest.cpp | 58 ++ 5 files changed, 125 insertions(+), 33 deletions(-) diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..b59b15e4617eb 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -68,12 +70,20 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, HeaderSuffix += "$"; IgnoreHeadersRegex.emplace_back(HeaderSuffix); } + + if (UnusedIncludes == false && MissingIncludes == false) +this->configurationDiag( + "The check 'misc-include-cleaner' will not " + "perform any analysis because 'UnusedIncludes' and " + "'MissingIncludes' are both false."); } void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +210,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); - if (areDiagsSelfContained() || - InsertedHeaders.insert(Replacement->getReplacementText()).second) { -DB << FixItHint::CreateInsertion( -SM->getComposedLoc(SM->getMai
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 3cf3ada4cfe78d943815e59f8df9ea74212e76e3 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IgnoreExtension option to SortIncludesOptions Sorting without taking the file extension into account gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting without taking the file extension into account unless two headers otherwise compare equal by introducing a new boolean option IgnoreExtension for SortIncludesOptions. --- clang/docs/ClangFormatStyleOptions.rst | 10 ++ clang/include/clang/Format/Format.h | 12 ++- clang/lib/Format/Format.cpp | 35 clang/unittests/Format/SortIncludesTest.cpp | 36 + 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..ba17558173e3e 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6010,6 +6010,16 @@ the configuration (without a prefix: ``Auto``). #include "B/A.h" #include "B/a.h" #include "B/a.h" #include "a/b.h" + * ``bool IgnoreExtension`` When sorting includes in each block, Only take file extensions into +account if two includes compare equal otherwise. + +.. code-block:: c++ + + true: false: + # include "A.h" vs.# include "A-util.h" + # include "A.inc" # include "A.h" + # include "A-util.h" # include "A.inc" + .. _SortJavaStaticImport: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..667ada10802e1 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4382,8 +4382,18 @@ struct FormatStyle { ///#include "B/a.h" #include "a/b.h" /// \endcode bool IgnoreCase; +/// When sorting includes in each block, Only take file extensions into +/// account if two includes compare equal otherwise. +/// \code +///true: false: +///# include "A.h" vs.# include "A-util.h" +///# include "A.inc" # include "A.h" +///# include "A-util.h" # include "A.inc" +/// \endcode +bool IgnoreExtension; bool operator==(const SortIncludesOptions &R) const { - return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase; + return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && + IgnoreExtension == R.IgnoreExtension; } bool operator!=(const SortIncludesOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b41a98ecb5be1..c5f69e6349d71 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1647,7 +1647,8 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, +/*IgnoreExtension=*/false}; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; @@ -3230,19 +3231,27 @@ static void sortCppIncludes(const FormatStyle &Style, SmallVector Indices = llvm::to_vector<16>(llvm::seq(0, Includes.size())); - if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) { + if (Style.SortIncludes.Enabled) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); -}); - } else { -stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, In
[clang-tools-extra] [clang-tools-extra] Add include mappings for (PR #140755)
https://github.com/DaanDeMeyer closed https://github.com/llvm/llvm-project/pull/140755 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140600 >From 371cbcd352d1fc7031a4f30f40eb5f515dc03e50 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 77 +++ .../clang-tidy/misc/IncludeCleanerCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/misc/include-cleaner.rst | 13 +++- .../clang-tidy/IncludeCleanerTest.cpp | 58 ++ 5 files changed, 124 insertions(+), 33 deletions(-) diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..52a94f3c040aa 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -68,12 +70,19 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, HeaderSuffix += "$"; IgnoreHeadersRegex.emplace_back(HeaderSuffix); } + + if (UnusedIncludes == false && MissingIncludes == false) +this->configurationDiag("The check 'misc-include-cleaner' will not " +"perform any analysis because 'UnusedIncludes' and " +"'MissingIncludes' are both false."); } void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +209,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); - if (areDiagsSelfContained() || - InsertedHeaders.insert(Replacement->getReplacementText()).second) { -DB << FixItHint::CreateInsertion( -
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140600 >From e8916f61952e3d6f041e3682acaee1e266ea1ee4 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 77 +++ .../clang-tidy/misc/IncludeCleanerCheck.h | 4 + clang-tools-extra/docs/ReleaseNotes.rst | 7 +- .../checks/misc/include-cleaner.rst | 11 +++ .../misc/include-cleaner-wrong-config.cpp | 10 +++ .../clang-tidy/IncludeCleanerTest.cpp | 58 ++ 6 files changed, 134 insertions(+), 33 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/include-cleaner-wrong-config.cpp diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..52a94f3c040aa 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -68,12 +70,19 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, HeaderSuffix += "$"; IgnoreHeadersRegex.emplace_back(HeaderSuffix); } + + if (UnusedIncludes == false && MissingIncludes == false) +this->configurationDiag("The check 'misc-include-cleaner' will not " +"perform any analysis because 'UnusedIncludes' and " +"'MissingIncludes' are both false."); } void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +209,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); - i
[clang-tools-extra] [clang-tools-extra] Add include mappings for getopt.h (PR #140726)
DaanDeMeyer wrote: > unfortunately neither is used by include-cleaner. we only support mappings > for c++ STL, through > https://github.com/llvm/llvm-project/blob/main/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc > and friends. > > we didn't want to add any system specific libraries, especially based on file > path mappings, because some of these are platform-specific and dependent on > the version of the library. Hence we were worried about accuracy. > > you can use `-ignore-headers` to prevent analysis for such headers (e.g. > `-ignore-headers=/usr/lib/.*`), or we might actually be more clever in > include-cleaner and try to disable these based on system-headerness of a > header, but that's also a losing battle since people can have various include > search paths in their command line. > > (still happy to land this once you ack the message though, as it should be an > improvement for other tools) Sure, makes sense to me, but yeah, this will still be useful for other tools, so feel free to land. https://github.com/llvm/llvm-project/pull/140726 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-format][NFC] Upgrade SortIncludes option to a struct (PR #140497)
https://github.com/DaanDeMeyer approved this pull request. Thank you! FWIW, I went over the changes and they all look sensible to me https://github.com/llvm/llvm-project/pull/140497 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From ab2206d22a9d71df807753f193f4110b191ab77b Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IgnoreExtension option to SortIncludesOptions Sorting without taking the file extension into account gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting without taking the file extension into account unless two headers otherwise compare equal by introducing a new boolean option IgnoreExtension for SortIncludesOptions. --- clang/docs/ClangFormatStyleOptions.rst | 3 ++ clang/include/clang/Format/Format.h | 11 ++- clang/lib/Format/Format.cpp | 34 + clang/unittests/Format/SortIncludesTest.cpp | 20 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..18095cc09afbe 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6010,6 +6010,9 @@ the configuration (without a prefix: ``Auto``). #include "B/A.h" #include "B/a.h" #include "B/a.h" #include "a/b.h" + * ``bool IgnoreExtension`` :versionbadge:`clang-format 21` + When sorting includes in each block, ignore file extensions. + .. _SortJavaStaticImport: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..18e314426c1ae 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4382,8 +4382,17 @@ struct FormatStyle { ///#include "B/a.h" #include "a/b.h" /// \endcode bool IgnoreCase; +/// When sorting includes in each block, Only take file extensions into +/// account if two includes compare equal otherwise. +/// \code +///true: false: +///# include "A.h" # include "A-util.h" +///# include "A.inc" # include "A.h" +///# include "A-util.h"# include "A.inc" +/// \version 21 +bool IgnoreExtension; bool operator==(const SortIncludesOptions &R) const { - return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase; + return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && IgnoreExtension == R.IgnoreExtension; } bool operator!=(const SortIncludesOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b41a98ecb5be1..6bf951ff61bf0 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; @@ -3230,19 +3230,27 @@ static void sortCppIncludes(const FormatStyle &Style, SmallVector Indices = llvm::to_vector<16>(llvm::seq(0, Includes.size())); - if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) { + if (Style.SortIncludes.Enabled) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); -}); - } else { -stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename); + SmallString<128> LHSStem, RHSStem; + if (Style.SortIncludes.IgnoreExtension) { +LHSStem = Includes[LHSI].Filename; +RHSStem = Includes[RHSI].Filename; +llvm::sys::path::replace_extension(LHSStem, ""); +llvm::sys::path::replace_extension(R
[clang] clang-format: Add IncludeSortKey option (PR #137840)
DaanDeMeyer wrote: @owenca @HazardyKnusperkeks Rebased onto latest main to take advantage of @owenca's rework and addressed comments. https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
@@ -152,6 +152,10 @@ struct IncludeStyle { /// \version 10 std::string IncludeIsMainSourceRegex; + /// When sorting includes in each block, ignore file extensions. DaanDeMeyer wrote: I added more explanation and added an example https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 33f84b217caab01a5ebbf93e4e5ac2182810c8db Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IgnoreExtension option to SortIncludesOptions Sorting without taking the file extension into account gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting without taking the file extension into account unless two headers otherwise compare equal by introducing a new boolean option IgnoreExtension for SortIncludesOptions. --- clang/docs/ClangFormatStyleOptions.rst | 11 +++ clang/include/clang/Format/Format.h | 11 ++- clang/lib/Format/Format.cpp | 34 + clang/unittests/Format/SortIncludesTest.cpp | 20 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..8ec658ef4b855 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6010,6 +6010,17 @@ the configuration (without a prefix: ``Auto``). #include "B/A.h" #include "B/a.h" #include "B/a.h" #include "a/b.h" + * ``bool IgnoreExtension`` :versionbadge:`clang-format 21` + When sorting includes in each block, Only take file extensions into +account if two includes compare equal otherwise. + +.. code-block:: c++ + + true: false: + # include "A.h" # include "A-util.h" + # include "A.inc" # include "A.h" + # include "A-util.h"# include "A.inc" + .. _SortJavaStaticImport: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..18e314426c1ae 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4382,8 +4382,17 @@ struct FormatStyle { ///#include "B/a.h" #include "a/b.h" /// \endcode bool IgnoreCase; +/// When sorting includes in each block, Only take file extensions into +/// account if two includes compare equal otherwise. +/// \code +///true: false: +///# include "A.h" # include "A-util.h" +///# include "A.inc" # include "A.h" +///# include "A-util.h"# include "A.inc" +/// \version 21 +bool IgnoreExtension; bool operator==(const SortIncludesOptions &R) const { - return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase; + return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && IgnoreExtension == R.IgnoreExtension; } bool operator!=(const SortIncludesOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b41a98ecb5be1..6bf951ff61bf0 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; @@ -3230,19 +3230,27 @@ static void sortCppIncludes(const FormatStyle &Style, SmallVector Indices = llvm::to_vector<16>(llvm::seq(0, Includes.size())); - if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) { + if (Style.SortIncludes.Enabled) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); -}); - } else { -stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, Include
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From beab0ecdeda1454de56cf1851dc03dda6d02673e Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IgnoreExtension option to SortIncludesOptions Sorting without taking the file extension into account gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting without taking the file extension into account unless two headers otherwise compare equal by introducing a new boolean option IgnoreExtension for SortIncludesOptions. --- clang/docs/ClangFormatStyleOptions.rst | 11 +++ clang/include/clang/Format/Format.h | 12 +++- clang/lib/Format/Format.cpp | 34 + clang/unittests/Format/SortIncludesTest.cpp | 20 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..8ec658ef4b855 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6010,6 +6010,17 @@ the configuration (without a prefix: ``Auto``). #include "B/A.h" #include "B/a.h" #include "B/a.h" #include "a/b.h" + * ``bool IgnoreExtension`` :versionbadge:`clang-format 21` + When sorting includes in each block, Only take file extensions into +account if two includes compare equal otherwise. + +.. code-block:: c++ + + true: false: + # include "A.h" # include "A-util.h" + # include "A.inc" # include "A.h" + # include "A-util.h"# include "A.inc" + .. _SortJavaStaticImport: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..fba16897b133a 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4382,8 +4382,18 @@ struct FormatStyle { ///#include "B/a.h" #include "a/b.h" /// \endcode bool IgnoreCase; +/// When sorting includes in each block, Only take file extensions into +/// account if two includes compare equal otherwise. +/// \code +///true: false: +///# include "A.h" # include "A-util.h" +///# include "A.inc" # include "A.h" +///# include "A-util.h"# include "A.inc" +/// \endcode +/// \version 21 +bool IgnoreExtension; bool operator==(const SortIncludesOptions &R) const { - return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase; + return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && IgnoreExtension == R.IgnoreExtension; } bool operator!=(const SortIncludesOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b41a98ecb5be1..6bf951ff61bf0 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; @@ -3230,19 +3230,27 @@ static void sortCppIncludes(const FormatStyle &Style, SmallVector Indices = llvm::to_vector<16>(llvm::seq(0, Includes.size())); - if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) { + if (Style.SortIncludes.Enabled) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); -}); - } else { -stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Includes[RHSI
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140233 >From 75b6d33d0b46a4d3eaf794afc9224bcef9434cb9 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 16 May 2025 12:08:47 +0200 Subject: [PATCH] [clang-include-cleaner] Make cleanup attr report expr location Instead of reporting the location of the attribute, let's report the location of the function reference that's passed to the cleanup attribute as the first argument. This is required as the attribute might be coming from a macro which means clang-include-cleaner skips the use as it gets attributed to the header file declaringt the macro and not to the main file. To make this work, we have to add a fake argument to the CleanupAttr constructor so we can pass in the original Expr alongside the function declaration. Fixes #140212 --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp | 2 +- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp | 2 +- clang/include/clang/Basic/Attr.td | 6 -- clang/lib/Sema/SemaDeclAttr.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index ba6eff49e9c98..a6f2559dd8e93 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -322,7 +322,7 @@ class ASTWalker : public RecursiveASTVisitor { } bool VisitCleanupAttr(CleanupAttr *attr) { -report(attr->getLocation(), attr->getFunctionDecl()); +report(attr->getExpr()->getExprLoc(), attr->getFunctionDecl()); return true; } diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 19695a34bd63e..0de0b77f33daf 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -573,7 +573,7 @@ TEST(WalkAST, OperatorNewDelete) { TEST(WalkAST, CleanupAttr) { testWalk("void* $explicit^freep(void *p);", - "void foo() { __attribute__((^__cleanup__(freep))) char* x = 0; }"); + "void foo() { __attribute__((__cleanup__(^freep))) char* x = 0; }"); } } // namespace diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index a6a7482a94a29..96a88089a47a2 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -226,7 +226,8 @@ class BoolArgument : Argument : Argument; class IntArgument : Argument; class StringArgument : Argument; -class ExprArgument : Argument; +class ExprArgument : Argument; class DeclArgument : Argument { DeclNode Kind = kind; @@ -1351,7 +1352,8 @@ def OSConsumesThis : InheritableAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; - let Args = [DeclArgument]; + let Args = [DeclArgument, + ExprArgument<"Expr", /*opt=*/0, /*fake=*/1>]; let Subjects = SubjectList<[LocalVar]>; let Documentation = [CleanupDocs]; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4d7f0455444f1..cbd75124478df 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3620,7 +3620,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); + D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD, E)); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140233 >From 736ab4d98adcdc4ec21639f59f5b1307ce678303 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 16 May 2025 12:08:47 +0200 Subject: [PATCH] [clang-include-cleaner] Make cleanup attr report expr location Instead of reporting the location of the attribute, let's report the location of the function reference that's passed to the cleanup attribute as the first argument. This is required as the attribute might be coming from a macro which means clang-include-cleaner skips the use as it gets attributed to the header file declaringt the macro and not to the main file. To make this work, we have to add a fake argument to the CleanupAttr constructor so we can pass in the original Expr alongside the function declaration. Fixes #140212 --- .../include-cleaner/lib/WalkAST.cpp | 2 +- .../include-cleaner/unittests/WalkASTTest.cpp | 2 +- clang/include/clang/Basic/Attr.td | 6 ++-- clang/lib/Sema/SemaDeclAttr.cpp | 2 +- clang/test/AST/ast-dump-attr-json.cpp | 32 ++- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index ba6eff49e9c98..a6f2559dd8e93 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -322,7 +322,7 @@ class ASTWalker : public RecursiveASTVisitor { } bool VisitCleanupAttr(CleanupAttr *attr) { -report(attr->getLocation(), attr->getFunctionDecl()); +report(attr->getExpr()->getExprLoc(), attr->getFunctionDecl()); return true; } diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 19695a34bd63e..0de0b77f33daf 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -573,7 +573,7 @@ TEST(WalkAST, OperatorNewDelete) { TEST(WalkAST, CleanupAttr) { testWalk("void* $explicit^freep(void *p);", - "void foo() { __attribute__((^__cleanup__(freep))) char* x = 0; }"); + "void foo() { __attribute__((__cleanup__(^freep))) char* x = 0; }"); } } // namespace diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index a6a7482a94a29..96a88089a47a2 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -226,7 +226,8 @@ class BoolArgument : Argument : Argument; class IntArgument : Argument; class StringArgument : Argument; -class ExprArgument : Argument; +class ExprArgument : Argument; class DeclArgument : Argument { DeclNode Kind = kind; @@ -1351,7 +1352,8 @@ def OSConsumesThis : InheritableAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; - let Args = [DeclArgument]; + let Args = [DeclArgument, + ExprArgument<"Expr", /*opt=*/0, /*fake=*/1>]; let Subjects = SubjectList<[LocalVar]>; let Documentation = [CleanupDocs]; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4d7f0455444f1..cbd75124478df 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3620,7 +3620,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); + D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD, E)); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, diff --git a/clang/test/AST/ast-dump-attr-json.cpp b/clang/test/AST/ast-dump-attr-json.cpp index 883e584bfedf0..a78e2293af654 100644 --- a/clang/test/AST/ast-dump-attr-json.cpp +++ b/clang/test/AST/ast-dump-attr-json.cpp @@ -149,7 +149,37 @@ __thread __attribute__ ((tls_model ("local-exec"))) int tls_model_var; // CHECK-NEXT: "type": { // CHECK-NEXT: "qualType": "void (int *)" // CHECK-NEXT: } -// CHECK-NEXT:} +// CHECK-NEXT:}, +// CHECK-NEXT:"inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "DeclRefExpr", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 242, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 16 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 242, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 16 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "qualType": "void (int *)" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "lvalue", +// CHECK-NEXT: "referencedDecl": { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "FunctionDecl", +// CHECK-NEXT: "name": "clea
[clang] clang-format: Add IncludeSortKey option (PR #137840)
@@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; DaanDeMeyer wrote: @mydeveloperday The default is false, by default, the extension is not ignored. https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From bb5eb380a0f71cac0c734443b4fbfa4441f441b2 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IgnoreExtension option to SortIncludesOptions Sorting without taking the file extension into account gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting without taking the file extension into account unless two headers otherwise compare equal by introducing a new boolean option IgnoreExtension for SortIncludesOptions. --- clang/docs/ClangFormatStyleOptions.rst | 11 +++ clang/include/clang/Format/Format.h | 12 ++- clang/lib/Format/Format.cpp | 34 +++ clang/unittests/Format/SortIncludesTest.cpp | 36 + 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..8ec658ef4b855 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6010,6 +6010,17 @@ the configuration (without a prefix: ``Auto``). #include "B/A.h" #include "B/a.h" #include "B/a.h" #include "a/b.h" + * ``bool IgnoreExtension`` :versionbadge:`clang-format 21` + When sorting includes in each block, Only take file extensions into +account if two includes compare equal otherwise. + +.. code-block:: c++ + + true: false: + # include "A.h" # include "A-util.h" + # include "A.inc" # include "A.h" + # include "A-util.h"# include "A.inc" + .. _SortJavaStaticImport: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..fba16897b133a 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4382,8 +4382,18 @@ struct FormatStyle { ///#include "B/a.h" #include "a/b.h" /// \endcode bool IgnoreCase; +/// When sorting includes in each block, Only take file extensions into +/// account if two includes compare equal otherwise. +/// \code +///true: false: +///# include "A.h" # include "A-util.h" +///# include "A.inc" # include "A.h" +///# include "A-util.h"# include "A.inc" +/// \endcode +/// \version 21 +bool IgnoreExtension; bool operator==(const SortIncludesOptions &R) const { - return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase; + return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && IgnoreExtension == R.IgnoreExtension; } bool operator!=(const SortIncludesOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b41a98ecb5be1..6bf951ff61bf0 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; @@ -3230,19 +3230,27 @@ static void sortCppIncludes(const FormatStyle &Style, SmallVector Indices = llvm::to_vector<16>(llvm::seq(0, Includes.size())); - if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) { + if (Style.SortIncludes.Enabled) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); -}); - } else { -stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) < - std::tie(Include
[clang] clang-format: Add IncludeSortKey option (PR #137840)
@@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; DaanDeMeyer wrote: @mydeveloperday Huh, I don't see how the length of the basename would affect this. I pushed more tests to verify this is the case. https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
@@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; DaanDeMeyer wrote: ``` #include "A.h" #include "A-util.h" #include "A.inc" ``` I don't see how clang-format would ever return this today without disabling include sorting? `-` sorts before `.` so `A-util.h` will always be put before `A.h` and `A.inc` today if include sorting is enabled. https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
DaanDeMeyer wrote: Right I get a feeling I'll have an easier time getting systemd to fully adapt clang-format than getting this into clang-format so closing https://github.com/llvm/llvm-project/pull/137617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add -disable-format option (PR #137617)
https://github.com/DaanDeMeyer closed https://github.com/llvm/llvm-project/pull/137617 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [include-cleaner] Add --fail-on-changes option (PR #140123)
https://github.com/DaanDeMeyer closed https://github.com/llvm/llvm-project/pull/140123 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [include-cleaner] Add --fail-on-changes option (PR #140123)
DaanDeMeyer wrote: I just found misc-include-cleaner in clang-tidy which is a way better fit for this so let me close this https://github.com/llvm/llvm-project/pull/140123 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
@@ -1351,7 +1352,8 @@ def OSConsumesThis : InheritableAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; - let Args = [DeclArgument]; + let Args = [DeclArgument, + ExprArgument<"Expr", /*opt=*/0, /*fake=*/1>]; DaanDeMeyer wrote: (I am very much a drive by contributor and this discussion is making me very scared of ever getting this landed :p) https://github.com/llvm/llvm-project/pull/140233 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
@@ -1351,7 +1352,8 @@ def OSConsumesThis : InheritableAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; - let Args = [DeclArgument]; + let Args = [DeclArgument, + ExprArgument<"Expr", /*opt=*/0, /*fake=*/1>]; DaanDeMeyer wrote: For 1) in handleCleanupAttr there's code to handle the case where the expr is not a declrefexpr. How does that work with passing in a DeclRefExpr to DeclArgument? https://github.com/llvm/llvm-project/pull/140233 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/140600 These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. >From 16d452394b0b7f92321b224de3daca99e929afad Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 19 May 2025 21:39:32 +0200 Subject: [PATCH] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner These mimick the same options from clangd and allow using the check to only check for unused includes or missing includes. --- .../clang-tidy/misc/IncludeCleanerCheck.cpp | 72 ++- .../clang-tidy/misc/IncludeCleanerCheck.h | 4 ++ .../checks/misc/include-cleaner.rst | 13 +++- .../clang-tidy/IncludeCleanerTest.cpp | 58 +++ 4 files changed, 114 insertions(+), 33 deletions(-) diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp index 7638bbc103d16..67129e87be22a 100644 --- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp @@ -59,7 +59,9 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name, : ClangTidyCheck(Name, Context), IgnoreHeaders( utils::options::parseStringList(Options.get("IgnoreHeaders", ""))), - DeduplicateFindings(Options.get("DeduplicateFindings", true)) { + DeduplicateFindings(Options.get("DeduplicateFindings", true)), + UnusedIncludes(Options.get("UnusedIncludes", true)), + MissingIncludes(Options.get("MissingIncludes", true)) { for (const auto &Header : IgnoreHeaders) { if (!llvm::Regex{Header}.isValid()) configurationDiag("Invalid ignore headers regex '%0'") << Header; @@ -74,6 +76,8 @@ void IncludeCleanerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreHeaders", utils::options::serializeStringList(IgnoreHeaders)); Options.store(Opts, "DeduplicateFindings", DeduplicateFindings); + Options.store(Opts, "UnusedIncludes", UnusedIncludes); + Options.store(Opts, "MissingIncludes", MissingIncludes); } bool IncludeCleanerCheck::isLanguageVersionSupported( @@ -200,39 +204,43 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) { if (!FileStyle) FileStyle = format::getLLVMStyle(); - for (const auto *Inc : Unused) { -diag(Inc->HashLocation, "included header %0 is not used directly") -<< llvm::sys::path::filename(Inc->Spelled, - llvm::sys::path::Style::posix) -<< FixItHint::CreateRemoval(CharSourceRange::getCharRange( - SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), - SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); + if (UnusedIncludes) { +for (const auto *Inc : Unused) { + diag(Inc->HashLocation, "included header %0 is not used directly") + << llvm::sys::path::filename(Inc->Spelled, + llvm::sys::path::Style::posix) + << FixItHint::CreateRemoval(CharSourceRange::getCharRange( + SM->translateLineCol(SM->getMainFileID(), Inc->Line, 1), + SM->translateLineCol(SM->getMainFileID(), Inc->Line + 1, 1))); +} } - tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, - FileStyle->IncludeStyle); - // Deduplicate insertions when running in bulk fix mode. - llvm::StringSet<> InsertedHeaders{}; - for (const auto &Inc : Missing) { -std::string Spelling = include_cleaner::spellHeader( -{Inc.Missing, PP->getHeaderSearchInfo(), MainFile}); -bool Angled = llvm::StringRef{Spelling}.starts_with("<"); -// We might suggest insertion of an existing include in edge cases, e.g., -// include is present in a PP-disabled region, or spelling of the header -// turns out to be the same as one of the unresolved includes in the -// main file. -if (auto Replacement = -HeaderIncludes.insert(llvm::StringRef{Spelling}.trim("\"<>"), - Angled, tooling::IncludeDirective::Include)) { - DiagnosticBuilder DB = - diag(SM->getSpellingLoc(Inc.SymRef.RefLocation), - "no header providing \"%0\" is directly included") - << Inc.SymRef.Target.name(); - if (areDiagsSelfContained() || - InsertedHeaders.insert(Replacement->getReplacementText()).second) { -DB << FixItHint::CreateInsertion( -SM->getComposedLoc(SM->getMainFileID(), Replacement->getOffset()), -Replacement->getReplacementText()); + if (MissingIncludes) { +tooling::HeaderIncludes HeaderIncludes(getCurrentMainFile(), Code, + FileStyle->IncludeStyle); +// Deduplicate insertions when running in bulk fix mode. +llvm
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140233 >From 57687d8eebc1f8e2b59ed131791895d76f88e30a Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 16 May 2025 12:08:47 +0200 Subject: [PATCH] [clang-include-cleaner] Make cleanup attr report expr location Instead of reporting the location of the attribute, let's report the location of the function reference that's passed to the cleanup attribute as the first argument. This is required as the attribute might be coming from a macro which means clang-include-cleaner skips the use as it gets attributed to the header file declaringt the macro and not to the main file. To make this work, we have to add a fake argument to the CleanupAttr constructor so we can pass in the original Expr alongside the function declaration. Fixes #140212 --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp | 2 +- .../include-cleaner/unittests/WalkASTTest.cpp | 2 +- clang/include/clang/Basic/Attr.td | 13 - clang/lib/Sema/SemaDeclAttr.cpp | 4 +++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index ba6eff49e9c98..baff90faa6eae 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -322,7 +322,7 @@ class ASTWalker : public RecursiveASTVisitor { } bool VisitCleanupAttr(CleanupAttr *attr) { -report(attr->getLocation(), attr->getFunctionDecl()); +report(attr->getArgLoc(), attr->getFunctionDecl()); return true; } diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index 19695a34bd63e..0de0b77f33daf 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -573,7 +573,7 @@ TEST(WalkAST, OperatorNewDelete) { TEST(WalkAST, CleanupAttr) { testWalk("void* $explicit^freep(void *p);", - "void foo() { __attribute__((^__cleanup__(freep))) char* x = 0; }"); + "void foo() { __attribute__((__cleanup__(^freep))) char* x = 0; }"); } } // namespace diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index a6a7482a94a29..06462b8a26bc0 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1354,6 +1354,17 @@ def Cleanup : InheritableAttr { let Args = [DeclArgument]; let Subjects = SubjectList<[LocalVar]>; let Documentation = [CleanupDocs]; + // FIXME: DeclArgument should be reworked to also store the + // Expr instead of adding attr specific hacks like the following. + // See the discussion in https://github.com/llvm/llvm-project/pull/14023. + let AdditionalMembers = [{ +private: +SourceLocation ArgLoc; + +public: +void setArgLoc(const SourceLocation &Loc) { ArgLoc = Loc; } +auto getArgLoc() const { return ArgLoc; } + }]; } def CmseNSEntry : InheritableAttr, TargetSpecificAttr { @@ -4815,7 +4826,7 @@ def HLSLResourceBinding: InheritableAttr { void setImplicitBindingOrderID(uint32_t Value) { ImplicitBindingOrderID = Value; } - bool hasImplicitBindingOrderID() const { + bool hasImplicitBindingOrderID() const { return ImplicitBindingOrderID.has_value(); } uint32_t getImplicitBindingOrderID() const { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 4d7f0455444f1..ac77a7c2c58a5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3620,7 +3620,9 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD)); + auto *attr = ::new (S.Context) CleanupAttr(S.Context, AL, FD); + attr->setArgLoc(E->getExprLoc()); + D->addAttr(attr); } static void handleEnumExtensibilityAttr(Sema &S, Decl *D, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] [clang-include-cleaner] Make cleanup attr report expr location (PR #140233)
@@ -1351,7 +1352,8 @@ def OSConsumesThis : InheritableAttr { def Cleanup : InheritableAttr { let Spellings = [GCC<"cleanup">]; - let Args = [DeclArgument]; + let Args = [DeclArgument, + ExprArgument<"Expr", /*opt=*/0, /*fake=*/1>]; DaanDeMeyer wrote: @erichkeane @AaronBallman I reworked this to use 2). I had a look at 1) but given how thinly stretched I already am, I don't have time to make such a change at this time. https://github.com/llvm/llvm-project/pull/140233 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 >From 6a3e7f091fbb8bc7117f5ef1d2803e73b8c6f061 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 29 Apr 2025 18:26:36 +0200 Subject: [PATCH] clang-format: Add IgnoreExtension option to SortIncludesOptions Sorting without taking the file extension into account gives nicer results when various header file names are substrings of other header file names, for example, a CLI application with a main header named analyze.h and a analyze-xxx.h header for each subcommand currently will always put analyze.h last after all the analyze-xxx.h headers, but putting analyze.h first instead of last is arguable nicer to read. TLDR; Instead of """ /#include "analyze-blame.h" /#include "analyze.h" """ You'd get """ /#include "analyze.h" /#include "analyze-blame.h" """ Let's allow sorting without taking the file extension into account unless two headers otherwise compare equal by introducing a new boolean option IgnoreExtension for SortIncludesOptions. --- clang/docs/ClangFormatStyleOptions.rst | 11 +++ clang/include/clang/Format/Format.h | 13 +++- clang/lib/Format/Format.cpp | 35 clang/unittests/Format/SortIncludesTest.cpp | 36 + 4 files changed, 81 insertions(+), 14 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 83716cc049ee3..8ec658ef4b855 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6010,6 +6010,17 @@ the configuration (without a prefix: ``Auto``). #include "B/A.h" #include "B/a.h" #include "B/a.h" #include "a/b.h" + * ``bool IgnoreExtension`` :versionbadge:`clang-format 21` + When sorting includes in each block, Only take file extensions into +account if two includes compare equal otherwise. + +.. code-block:: c++ + + true: false: + # include "A.h" # include "A-util.h" + # include "A.inc" # include "A.h" + # include "A-util.h"# include "A.inc" + .. _SortJavaStaticImport: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 3ac4318824ac0..6ce0d14a12f31 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4382,8 +4382,19 @@ struct FormatStyle { ///#include "B/a.h" #include "a/b.h" /// \endcode bool IgnoreCase; +/// When sorting includes in each block, Only take file extensions into +/// account if two includes compare equal otherwise. +/// \code +///true: false: +///# include "A.h" # include "A-util.h" +///# include "A.inc" # include "A.h" +///# include "A-util.h"# include "A.inc" +/// \endcode +/// \version 21 +bool IgnoreExtension; bool operator==(const SortIncludesOptions &R) const { - return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase; + return Enabled == R.Enabled && IgnoreCase == R.IgnoreCase && + IgnoreExtension == R.IgnoreExtension; } bool operator!=(const SortIncludesOptions &R) const { return !(*this == R); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index b41a98ecb5be1..c5f69e6349d71 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1647,7 +1647,8 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, +/*IgnoreExtension=*/false}; LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before; LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; @@ -3230,19 +3231,27 @@ static void sortCppIncludes(const FormatStyle &Style, SmallVector Indices = llvm::to_vector<16>(llvm::seq(0, Includes.size())); - if (Style.SortIncludes.Enabled && Style.SortIncludes.IgnoreCase) { + if (Style.SortIncludes.Enabled) { stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - const auto LHSFilenameLower = Includes[LHSI].Filename.lower(); - const auto RHSFilenameLower = Includes[RHSI].Filename.lower(); - return std::tie(Includes[LHSI].Priority, LHSFilenameLower, - Includes[LHSI].Filename) < - std::tie(Includes[RHSI].Priority, RHSFilenameLower, - Includes[RHSI].Filename); -}); - } else { -stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) { - return std::tie(Includes[LHSI].Priority, Includes[LHSI]
[clang] clang-format: Add IncludeSortKey option (PR #137840)
DaanDeMeyer wrote: Ping? Would love to get this over the finish line https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
DaanDeMeyer wrote: @owenca Thanks for the detailed review. Changed the name to IncludeSortIgnoreExtension, let me know if you have a better idea for the name. https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/137840 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [include-cleaner] Add --fail-on-changes option (PR #140123)
https://github.com/DaanDeMeyer updated https://github.com/llvm/llvm-project/pull/140123 Rate limit · GitHub body { background-color: #f6f8fa; color: #24292e; font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; font-size: 14px; line-height: 1.5; margin: 0; } .container { margin: 50px auto; max-width: 600px; text-align: center; padding: 0 24px; } a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: underline; } h1 { line-height: 60px; font-size: 48px; font-weight: 300; margin: 0px; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0 40px; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #66; font-weight: 200; font-size: 14px; margin: 0 10px; } Whoa there! You have exceeded a secondary rate limit. Please wait a few minutes before you try again; in some cases this may take up to an hour. https://support.github.com/contact";>Contact Support — https://githubstatus.com";>GitHub Status — https://twitter.com/githubstatus";>@githubstatus ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [include-cleaner] Add --fail-on-changes option (PR #140123)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/140123 When integrating clang-include-cleaner into a test suite, it's useful to have it exit with a nonzero exit status when there are suggested changes to includes so let's add --fail-on-changes to make that possible. >From 6f2a50adf7dc1d559421e83ad9605db96ead6fa6 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Thu, 15 May 2025 21:07:46 +0200 Subject: [PATCH] [include-cleaner] Add --fail-on-changes option When integrating clang-include-cleaner into a test suite, it's useful to have it exit with a nonzero exit status when there are suggested changes to includes so let's add --fail-on-changes to make that possible. --- clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp index 372ab5fa2706e..47e1400d8ccb2 100644 --- a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp +++ b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp @@ -115,6 +115,11 @@ cl::opt DisableRemove{ cl::init(false), cl::cat(IncludeCleaner), }; +cl::opt FailOnChanges{ + "fail-on-changes", + cl::desc("Exit with a non-zero exit code if changes are suggested"), + cl::cat(IncludeCleaner), +}; std::atomic Errors = ATOMIC_VAR_INIT(0); @@ -410,5 +415,5 @@ int main(int argc, const char **argv) { } } } - return ErrorCode || Errors != 0; + return ErrorCode || Errors != 0 || (FailOnChanges && Factory.editedFiles().size() != 0); } ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] clang-format: Add IncludeSortKey option (PR #137840)
@@ -1647,7 +1647,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave; LLVMStyle.ShortNamespaceLines = 1; LLVMStyle.SkipMacroDefinitionBody = false; - LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false}; + LLVMStyle.SortIncludes = {/*Enabled=*/true, /*IgnoreCase=*/false, /*IgnoreExtension=*/false}; DaanDeMeyer wrote: I'm very confused now what the suggestion is that I should apply here to make everyone happy https://github.com/llvm/llvm-project/pull/137840 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tools-extra] Add include mappings for (PR #141216)
https://github.com/DaanDeMeyer created https://github.com/llvm/llvm-project/pull/141216 None >From a6dd3873ef01268f5466bdeebf2bdcc4c314158e Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 20 May 2025 15:46:29 +0200 Subject: [PATCH] [clang-tools-extra] Add include mappings for --- .../clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp | 1 + clang-tools-extra/clangd/index/CanonicalIncludes.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp index 469323f0ee9d7..480dd204482cf 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp @@ -655,6 +655,7 @@ const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() { {"bits/syslog-path.h$", ""}, {"bits/termios.h$", ""}, {"bits/types.h$", ""}, + {"bits/types/struct_iovec.h$", ""}, {"bits/typesizes.h$", ""}, {"bits/uio.h$", ""}, {"bits/ustat.h$", ""}, diff --git a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp index 785ec4086ea76..8ae78eff932fb 100644 --- a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp +++ b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp @@ -671,6 +671,7 @@ const std::pair IncludeMappings[] = { {"bits/termios.h", ""}, {"bits/types.h", ""}, {"bits/types/siginfo_t.h", ""}, +{"bits/types/struct_iovec.h", ""}, {"bits/types/struct_itimerspec.h", ""}, {"bits/types/struct_rusage.h", ""}, {"bits/uio.h", ""}, ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] Add UnusedIncludes/MissingIncludes options to misc-include-cleaner (PR #140600)
DaanDeMeyer wrote: @vbvictor Could you merge this one for me now that CI is green? Thanks! https://github.com/llvm/llvm-project/pull/140600 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits