[clang-tools-extra] [clangd] Add config option to analyze unused system headers (PR #87208)
https://github.com/vvd170501 created https://github.com/llvm/llvm-project/pull/87208 This PR adds a new `AnalyzeSystemHeaders` option to `Includes` section of clangd config. This option will allow to mark all system headers, not just the ones from standard library, as unused. Why this change is useful? In our codebase all includes from outside of local directory are written with angle brackets. For example, ```cpp // foo.cpp #include "foo.h" // main header #include "foo_utils.h" // From the same directory #include // Other directory, path is relative the repository root #include // Header from standard library ``` I'd like to use the builtin include-cleaner of clangd to detect unused includes, but currently it ignores non-standard system headers I understand that enabling unused include detection for system headers will probably produce some false positives due to lack of support for umbrella headers, but they can be filtered out by `IgnoreHeader`. This is not ideal, but still better than not having unused include detection for system headers at all. >From f222e44f5586297ddd61ac0efff4a7115a766c53 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Mon, 1 Apr 2024 01:12:11 +0300 Subject: [PATCH] Add config option to analyze unused system headers --- clang-tools-extra/clangd/Config.h | 1 + clang-tools-extra/clangd/ConfigCompile.cpp| 56 +++ clang-tools-extra/clangd/ConfigFragment.h | 4 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++ clang-tools-extra/clangd/IncludeCleaner.cpp | 34 +++ clang-tools-extra/clangd/IncludeCleaner.h | 13 + clang-tools-extra/clangd/ParsedAST.cpp| 3 +- .../clangd/unittests/ConfigCompileTests.cpp | 6 ++ .../clangd/unittests/ConfigYAMLTests.cpp | 15 + .../clangd/unittests/IncludeCleanerTests.cpp | 15 + clang-tools-extra/docs/ReleaseNotes.rst | 4 ++ 11 files changed, 110 insertions(+), 45 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c5877..9629854abff31b 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -114,6 +114,7 @@ struct Config { /// these regexes. struct { std::vector> IgnoreHeader; + bool AnalyzeSystemHeaders = false; } Includes; } Diagnostics; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 5bb2eb4a9f803f..570f3cfc3ce2ed 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -572,32 +572,42 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { +// Anchor on the right. +std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; +llvm::Regex CompiledRegex(AnchoredPattern, Flags); +std::string RegexError; +if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), HeaderPattern.Range); + continue; +} +Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } -if (Filters->empty()) +std::optional AnalyzeSystemHeaders; +if (F.AnalyzeSystemHeaders.has_value()) + AnalyzeSystemHeaders = **F.AnalyzeSystemHeaders; +if (!Filters && !AnalyzeSystemHeaders.has_value()) return; -auto Filter = [Filters](llvm::StringRef Path) { - for (auto &Regex : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config &C) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config &C) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto &Regex : *Filters) +if (Regex.match(Path)) + return true; + return false; +
[clang-tools-extra] [clangd] Add config option to analyze unused system headers (PR #87208)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to analyze unused system headers (PR #87208)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to analyze unused system headers (PR #87208)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/87208 >From 3e29095dbc2240b7a61d8d261224501a85753e7d Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Mon, 1 Apr 2024 02:26:14 +0300 Subject: [PATCH] Add config option to analyze unused system headers --- clang-tools-extra/clangd/Config.h | 1 + clang-tools-extra/clangd/ConfigCompile.cpp| 57 +++ clang-tools-extra/clangd/ConfigFragment.h | 4 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++ clang-tools-extra/clangd/IncludeCleaner.cpp | 34 +++ clang-tools-extra/clangd/IncludeCleaner.h | 13 + clang-tools-extra/clangd/ParsedAST.cpp| 3 +- .../clangd/unittests/ConfigCompileTests.cpp | 6 ++ .../clangd/unittests/ConfigYAMLTests.cpp | 15 + .../clangd/unittests/IncludeCleanerTests.cpp | 15 + clang-tools-extra/docs/ReleaseNotes.rst | 4 ++ 11 files changed, 111 insertions(+), 45 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c5877..9629854abff31b 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -114,6 +114,7 @@ struct Config { /// these regexes. struct { std::vector> IgnoreHeader; + bool AnalyzeSystemHeaders = false; } Includes; } Diagnostics; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 5bb2eb4a9f803f..f74c870adfb73d 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -572,32 +572,43 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { +// Anchor on the right. +std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; +llvm::Regex CompiledRegex(AnchoredPattern, Flags); +std::string RegexError; +if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), + HeaderPattern.Range); + continue; +} +Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } -if (Filters->empty()) +std::optional AnalyzeSystemHeaders; +if (F.AnalyzeSystemHeaders.has_value()) + AnalyzeSystemHeaders = **F.AnalyzeSystemHeaders; +if (!Filters && !AnalyzeSystemHeaders.has_value()) return; -auto Filter = [Filters](llvm::StringRef Path) { - for (auto &Regex : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config &C) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config &C) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto &Regex : *Filters) +if (Regex.match(Path)) + return true; + return false; +}; +C.Diagnostics.Includes.IgnoreHeader.emplace_back(std::move(Filter)); + } + if (AnalyzeSystemHeaders.has_value()) +C.Diagnostics.Includes.AnalyzeSystemHeaders = *AnalyzeSystemHeaders; }); } diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 7fa61108c78a05..ac8b88c2454128 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -254,6 +254,10 @@ struct Fragment { /// unused or missing. These can match any suffix of the header file in /// question. std::vector> IgnoreHeader; + + /// If false (default), unused system headers will be ignored. + /// Standard library headers are analyzed regardless of this option. + std::optional> AnalyzeSystemHeaders; }; IncludesBlock Includes; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index ce09af819247ae..7608af42005386 100644 --- a/cla
[clang-tools-extra] [clangd] Add config option to analyze unused system headers (PR #87208)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/87208 >From 35db92dfd0c2b43fc7afde5b093598763c4b8c89 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Mon, 1 Apr 2024 02:26:14 +0300 Subject: [PATCH] Add config option to analyze unused system headers --- clang-tools-extra/clangd/Config.h | 1 + clang-tools-extra/clangd/ConfigCompile.cpp| 57 +++ clang-tools-extra/clangd/ConfigFragment.h | 4 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++ clang-tools-extra/clangd/IncludeCleaner.cpp | 34 +++ clang-tools-extra/clangd/IncludeCleaner.h | 13 + clang-tools-extra/clangd/ParsedAST.cpp| 3 +- .../clangd/unittests/ConfigCompileTests.cpp | 6 ++ .../clangd/unittests/ConfigYAMLTests.cpp | 15 + .../clangd/unittests/IncludeCleanerTests.cpp | 15 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ 11 files changed, 112 insertions(+), 45 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c5877..9629854abff31b 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -114,6 +114,7 @@ struct Config { /// these regexes. struct { std::vector> IgnoreHeader; + bool AnalyzeSystemHeaders = false; } Includes; } Diagnostics; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 5bb2eb4a9f803f..f74c870adfb73d 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -572,32 +572,43 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { +// Anchor on the right. +std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; +llvm::Regex CompiledRegex(AnchoredPattern, Flags); +std::string RegexError; +if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), + HeaderPattern.Range); + continue; +} +Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } -if (Filters->empty()) +std::optional AnalyzeSystemHeaders; +if (F.AnalyzeSystemHeaders.has_value()) + AnalyzeSystemHeaders = **F.AnalyzeSystemHeaders; +if (!Filters && !AnalyzeSystemHeaders.has_value()) return; -auto Filter = [Filters](llvm::StringRef Path) { - for (auto &Regex : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config &C) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config &C) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto &Regex : *Filters) +if (Regex.match(Path)) + return true; + return false; +}; +C.Diagnostics.Includes.IgnoreHeader.emplace_back(std::move(Filter)); + } + if (AnalyzeSystemHeaders.has_value()) +C.Diagnostics.Includes.AnalyzeSystemHeaders = *AnalyzeSystemHeaders; }); } diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 7fa61108c78a05..ac8b88c2454128 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -254,6 +254,10 @@ struct Fragment { /// unused or missing. These can match any suffix of the header file in /// question. std::vector> IgnoreHeader; + + /// If false (default), unused system headers will be ignored. + /// Standard library headers are analyzed regardless of this option. + std::optional> AnalyzeSystemHeaders; }; IncludesBlock Includes; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index ce09af819247ae..7608af42005386 100644 --- a/cla
[clang-tools-extra] [clangd] Add config option to detect unused system headers (PR #87208)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
@@ -62,15 +64,6 @@ issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code, const ThreadsafeFS &TFS, HeaderFilter IgnoreHeader = {}); -/// Affects whether standard library includes should be considered for -/// removal. This is off by default for now due to implementation limitations: -/// - macros are not tracked -/// - symbol names without a unique associated header are not tracked -/// - references to std-namespaced C types are not properly tracked: -/// instead of std::size_t -> we see ::size_t -> -/// FIXME: remove this hack once the implementation is good enough. -void setIncludeCleanerAnalyzesStdlib(bool B); vvd170501 wrote: This function was removed in e289ee99cec4607243aeaa01504f6b3cf65b65fe, but the declaration was left for some reason (overlooked?) https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
@@ -62,15 +64,6 @@ issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code, const ThreadsafeFS &TFS, HeaderFilter IgnoreHeader = {}); -/// Affects whether standard library includes should be considered for -/// removal. This is off by default for now due to implementation limitations: -/// - macros are not tracked -/// - symbol names without a unique associated header are not tracked -/// - references to std-namespaced C types are not properly tracked: -/// instead of std::size_t -> we see ::size_t -> -/// FIXME: remove this hack once the implementation is good enough. -void setIncludeCleanerAnalyzesStdlib(bool B); vvd170501 wrote: At first I considered adding a global flag similar to `--include-cleaner-stdlib`, but then thought that having more fine-grained control would be better. https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
https://github.com/vvd170501 ready_for_review https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 created https://github.com/llvm/llvm-project/pull/81364 Fixes #68933. >From aa48713c9bf23c24bbc0c22dd67f332ca970d2b8 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 10 Feb 2024 02:29:48 +0300 Subject: [PATCH] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 975eca0ad9b642..bda533f77cc56a 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -516,7 +516,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b4dc4feee8e63a..69e197e26b9b45 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6165,6 +6165,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index b6de06464cd6f3..08aa50ebad331f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) || +
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From b7e3ffb25e1a50ac29e50ac8536ea93244f219a1 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 975eca0ad9b642..bda533f77cc56a 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -516,7 +516,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b4dc4feee8e63a..69e197e26b9b45 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6165,6 +6165,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index b6de06464cd6f3..08aa50ebad331f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(Sema
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 ready_for_review https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From 9701011a9c88397cf3bb2c089e7295f62c7e13fe Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH 1/4] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 975eca0ad9b642..bda533f77cc56a 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -516,7 +516,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 83b89d1449f420..bbb46a9d6f3c6a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index b6de06464cd6f3..08aa50ebad331f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
@@ -120,6 +120,10 @@ Non-comprehensive list of changes in this release New Compiler Flags -- +- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-designated-field-initializers``. vvd170501 wrote: Would it be ok to also add this patch to the 18.x release branch? It would be nice to have a way to keep old behavior of the m-f-i check when upgrading from Clang 16/17 to 18. https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From f73060f7f09a747c90fa559641abd8c72f4ee66f Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH 1/4] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e8b4139d7893ce..0791a0002319de 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 91105d4231f06a..8cf58299602ec7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 0fd458837163e5..3227f16dd0c1ce 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
vvd170501 wrote: Ping https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From f73060f7f09a747c90fa559641abd8c72f4ee66f Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH 1/5] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e8b4139d7893ce..0791a0002319de 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 91105d4231f06a..8cf58299602ec7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 0fd458837163e5..3227f16dd0c1ce 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From f73060f7f09a747c90fa559641abd8c72f4ee66f Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH 1/6] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e8b4139d7893ce..0791a0002319de 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 91105d4231f06a..8cf58299602ec7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 0fd458837163e5..3227f16dd0c1ce 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
@@ -2363,8 +2356,11 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { + // This check is disabled for designated initializers in C. + // This matches gcc behaviour. + if (!VerifyOnly && InitializedSomething && !RD->isUnion() && + !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && + !(HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus)) { vvd170501 wrote: Unexpanded condition corresponds to the comment I left a few lines above: > This check is disabled for designated initializers in C. For me personally, it looks a bit less readable in expanded form ("check unused fields if there are no designated initializers or if language is C++") https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
@@ -2363,8 +2356,11 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { + // This check is disabled for designated initializers in C. + // This matches gcc behaviour. + if (!VerifyOnly && InitializedSomething && !RD->isUnion() && + !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && + !(HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus)) { vvd170501 wrote: @erichkeane, I did something like this before 83864610d6b6470a0f229c516821d8344d994562, but this adds another indentation level. It's possible to calculate `DisableCheck` before the `if` statement, but it'll probably be less optimal than the current solution - if `VerifyOnly` is true, `DisableCheck` is not needed. https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
@@ -2363,8 +2356,11 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { + // This check is disabled for designated initializers in C. + // This matches gcc behaviour. + if (!VerifyOnly && InitializedSomething && !RD->isUnion() && + !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && + !(HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus)) { vvd170501 wrote: > I am asking for the list of '!'s to be shorter/grouped into a couple of > 'bools' with descriptive names Like this? Other checks seem unrelated to each other. ```diff + bool IsCDesignatedInitializer = HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus; if (!VerifyOnly && InitializedSomething && !RD->isUnion() && !IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) && - !(HasDesignatedInit && !SemaRef.getLangOpts().CPlusPlus)) { + !IsCDesignatedInitializer) { ``` https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/81364 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From f73060f7f09a747c90fa559641abd8c72f4ee66f Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH 1/7] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e8b4139d7893ce..0791a0002319de 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 91105d4231f06a..8cf58299602ec7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 0fd458837163e5..3227f16dd0c1ce 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(
[clang] [clang] Add -Wmissing-designated-field-initializers (PR #81364)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/81364 >From f73060f7f09a747c90fa559641abd8c72f4ee66f Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:19:52 +0300 Subject: [PATCH 1/8] Add -Wmissing-designated-field-initializers, decide whether to skip m-f-i check only when needed --- clang/include/clang/Basic/DiagnosticGroups.td | 10 +++- .../clang/Basic/DiagnosticSemaKinds.td| 4 ++ clang/lib/Sema/SemaInit.cpp | 50 ++- .../SemaCXX/cxx2a-initializer-aggregates.cpp | 11 ++-- 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index e8b4139d7893ce..0791a0002319de 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -517,7 +517,15 @@ def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; -def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def MissingDesignatedFieldInitializers : DiagGroup<"missing-designated-field-initializers">{ + code Documentation = [{ +Warn about designated initializers with some fields missing (only in C++). + }]; +} +// Default -Wmissing-field-initializers matches gcc behavior, +// but missing-designated-field-initializers can be turned off to match old clang behavior. +def MissingFieldInitializers : DiagGroup<"missing-field-initializers", + [MissingDesignatedFieldInitializers]>; def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 91105d4231f06a..8cf58299602ec7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6167,6 +6167,10 @@ def ext_initializer_string_for_char_array_too_long : ExtWarn< def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; +// The same warning, but another group is needed to disable it separately. +def warn_missing_designated_field_initializers : Warning< + "missing field %0 initializer">, + InGroup, DefaultIgnore; def warn_braces_around_init : Warning< "braces around %select{scalar |}0initializer">, InGroup>; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 0fd458837163e5..3227f16dd0c1ce 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2227,8 +2227,6 @@ void InitListChecker::CheckStructUnionTypes( size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) { return isa(D) || isa(D); }); - bool CheckForMissingFields = -!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()); bool HasDesignatedInit = false; llvm::SmallPtrSet InitializedFields; @@ -2269,11 +2267,6 @@ void InitListChecker::CheckStructUnionTypes( } InitializedSomething = true; - - // Disable check for missing fields when designators are used. - // This matches gcc behaviour. - if (!SemaRef.getLangOpts().CPlusPlus) -CheckForMissingFields = false; continue; } @@ -2285,7 +2278,7 @@ void InitListChecker::CheckStructUnionTypes( // These are okay for randomized structures. [C99 6.7.8p19] // // Also, if there is only one element in the structure, we allow something -// like this, because it's really not randomized in the tranditional sense. +// like this, because it's really not randomized in the traditional sense. // // struct foo h = {bar}; auto IsZeroInitializer = [&](const Expr *I) { @@ -2363,23 +2356,32 @@ void InitListChecker::CheckStructUnionTypes( } // Emit warnings for missing struct field initializers. - if (!VerifyOnly && InitializedSomething && CheckForMissingFields && - !RD->isUnion()) { -// It is possible we have one or more unnamed bitfields remaining. -// Find first (if any) named field and emit warning. -for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin() - : Field, -end = RD->field_end(); - it != end; ++it) { - if (HasDesignatedInit && InitializedFields.count(*it)) -continue; + if (!VerifyOnly && InitializedSomething && !RD->isUnion()) { +// Disable missing fields check for: +// - Zero initializers +// - Designated initializers (only in C). This matches gcc behaviour. +bool DisableCheck = +IList->isIdiomaticZeroInitializer(
[clang-tools-extra] [include-cleaner] don't consider the associated header unused (PR #67228)
@@ -227,6 +230,7 @@ class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler { IncludedHeader = *File; checkForExport(HashFID, HashLine, std::move(IncludedHeader), File); vvd170501 wrote: `std::move` should be removed, because `IncludedHeader` is now also used for `checkForDeducedAssociated`. Current implementation of `clang::include_cleaner::Header` is trivially movable, so `IncludedHeader` is unchanged, but it's safer to not rely on this fact. https://github.com/llvm/llvm-project/pull/67228 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
vvd170501 wrote: Ping https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 created https://github.com/llvm/llvm-project/pull/88636 This PR aims to expand the list of classes that are considered to be "strings" by `readability-string-compare` check. 1. Currently `readability-string-compare` only checks `std::string;:compare`, but `std::string_view` has a similar `compare` method, which also should not be used to check equality of two strings. 2. Some codebases use custom string-like classes that have public interfaces similar to `std::string` or `std::string_view`. Example: [TStringBase](https://github.com/yandex/yatool/blob/main/util/generic/strbase.h#L38), Related to, but does not solve #28396 (only adds support for custom string-like classes, not custom functions) >From eb5279fd83ba114b8eb094099d5993d6bfb003e3 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 75 +-- .../readability/StringCompareCheck.h | 10 ++- .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 41 ++ .../checkers/readability/string-compare.cpp | 14 5 files changed, 125 insertions(+), 25 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..30bde1f8b75b61 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,15 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +23,55 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const StringRef DefaultStringClassNames = "::std::basic_string;" + "::std::basic_string_view"; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringClassNames(optutils::parseStringList( + Options.get("StringClassNames", DefaultStringClassNames))), + // Both std::string and std::string_view are templates, so this check only + // needs to match template classes by default. + // Custom `StringClassNames` may contain non-template classes, and + // it's impossible to tell them apart from templates just by name. + CheckNonTemplateClasses(Options.get("StringClassNames").has_value()) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + if (StringClassNames.empty()) { +return; + } + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), +
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 91eccdd291fa4f0753aa8e9970fa146516823e22 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 73 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 36 + .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 162 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..20218975ec121b 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,52 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTemplateSpecializationDecl(hasAnyName(PossiblyTemp
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From b63dd11ea87cd504c8972de6ed29330d6702abca Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 36 + .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 163 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTemplate
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTemplat
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
@@ -7,42 +7,70 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { vvd170501 wrote: Type of `StringClassMatcher` dependinds on whether the check is used with or without `StringLikeClasses`, so a template lambda is needed. It's possible to use `anyOf` and `cxxRecordDecl` in both cases and remove the lambda, but this will probably slow the check down in default case. https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 ready_for_review https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
@@ -50,5 +52,32 @@ Examples: } The above code examples show the list of if-statements that this check will -give a warning for. All of them uses ``compare`` to check if equality or +give a warning for. All of them use ``compare`` to check equality or inequality of two strings instead of using the correct operators. + +Options +--- + +.. option:: StringLikeClasses + + A string containing comma-separated names of string-like classes. Default is an empty string. + If a class from this list has a ``compare`` method similar to ``std::string``, it will be checked in the same way. + +Example +^^^ + +.. code-block:: c++ + + struct CustomString { + public: +int compare (const CustomString& other) const; + } + + CustomString str1; + CustomString str2; + + // use str1 != str2 instead. + if (str1.compare(str2)) { + } + +If `StringLikeClasses` contains ``CustomString``, the check will suggest replacing ``compare`` with equality operator. vvd170501 wrote: Default value of what? If you mean `StringLikeClasses`, it is empty by default (see line 63) https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH 1/2] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTem
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
@@ -7,42 +7,70 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} vvd170501 wrote: > put StringClasses as default I thought about implementing the option this way, but it seems to me it'd be a bit harder to use than a list of additional classes. if the user wanted to add custom classes, they'd need to also include `std::string` and `std::string_view` in the list to keep the check enabled for these classes. So, I decided to append custom classes to the default list instead of overwriting it. > Or call it like "AdditionalStringLikeClasses" Ok. > but still have common handling Could you elaborate? I'm not sure what you mean by "common handling". Removing the lambda? https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
@@ -7,42 +7,70 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTemplateSpecializationDecl(hasAnyName(PossiblyTemplateClasses)), +cxxRecordDecl(hasAnyName(StringLikeClasses; vvd170501 wrote: But would regex be useful here? - Usually there would be a few (1-2) custom string-like classes, if any, and it shouldn't be hard to just put their names into the list. - The defaults would be less readable (`^::std::string$;^::std::string_view$;` or `^::std::string(_view)?$` vs `::std::string;::std::string_view`) Also, existing checks with a `StringLikeClasses` use `hasAnyName` https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH 1/4] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTem
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH 1/5] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTem
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH 1/6] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTem
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
vvd170501 wrote: @HighCommander4, overall it looks good, but I'd replace "enables include-cleaner checks" with "enables unused include check", because the option doesn't affect missing include check. https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
vvd170501 wrote: @HighCommander4 Ping. Could you review this PR or suggest other reviewers, please? https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
vvd170501 wrote: Ping. @PiotrZSL, I've added the changes you requested (except `matchesAnyListedName`), waiting for your feedback https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH 1/7] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTem
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 0db24a6806e9429b5e7b9cd9d0777315b3e6d87e Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH 1/8] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 74 +-- .../readability/StringCompareCheck.h | 9 ++- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/string-compare.rst | 33 - .../clang-tidy/checkers/Inputs/Headers/string | 10 +++ .../string-compare-custom-string-classes.cpp | 38 ++ .../checkers/readability/string-compare.cpp | 23 ++ 7 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..905e5b156ef864 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,16 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" +#include using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,29 +24,53 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const std::vector StringClasses = { +"::std::basic_string", "::std::basic_string_view"}; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses( + optutils::parseStringList(Options.get("StringLikeClasses", ""))) {} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { - const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), - hasArgument(0, expr().bind("str2")), argumentCountIs(1), - callee(memberExpr().bind("str1"))); - - // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher( - traverse(TK_AsIs, - implicitCastExpr(hasImplicitDestinationType(booleanType()), -has(StrCompare)) - .bind("match1")), - this); - - // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. - Finder->addMatcher( - binaryOperator(hasAnyOperatorName("==", "!="), - hasOperands(StrCompare.bind("compare"), - integerLiteral(equals(0)).bind("zero"))) - .bind("match2"), - this); + const auto RegisterForClasses = [&, this](const auto &StringClassMatcher) { +const auto StrCompare = cxxMemberCallExpr( +callee(cxxMethodDecl(hasName("compare"), ofClass(StringClassMatcher))), +hasArgument(0, expr().bind("str2")), argumentCountIs(1), +callee(memberExpr().bind("str1"))); + +// First and second case: cast str.compare(str) to boolean. +Finder->addMatcher( +traverse(TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), +this); + +// Third and fourth case: str.compare(str) == 0 +// and str.compare(str) != 0. +Finder->addMatcher( +binaryOperator(hasAnyOperatorName("==", "!="), + hasOperands(StrCompare.bind("compare"), + integerLiteral(equals(0)).bind("zero"))) +.bind("match2"), +this); + }; + if (StringLikeClasses.empty()) { +RegisterForClasses( +classTemplateSpecializationDecl(hasAnyName(StringClasses))); + } else { +// StringLikeClasses may or may not be templates, so we need to match both +// template and non-template classes. +std::vector PossiblyTemplateClasses = StringClasses; +PossiblyTemplateClasses.insert(PossiblyTemplateClasses.end(), + StringLikeClasses.begin(), + StringLikeClasses.end()); +RegisterForClasses(anyOf( +classTem
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
@@ -50,5 +52,36 @@ Examples: } The above code examples show the list of if-statements that this check will -give a warning for. All of them uses ``compare`` to check if equality or +give a warning for. All of them use ``compare`` to check equality or inequality of two strings instead of using the correct operators. + +Options +--- + +.. option:: StringLikeClasses + + A string containing semicolon-separated names of string-like classes. + By default contains only ``::std::basic_string`` + and ``::std::basic_string_view``. If a class from this list has + a ``compare`` method similar to that of ``std::string``, it will be checked + in the same way. + +Example +^^^ + +.. code-block:: c++ + + struct CustomString { + public: +int compare (const CustomString& other) const; + } + + CustomString str1; + CustomString str2; + + // use str1 != str2 instead. + if (str1.compare(str2)) { + } + +If `StringLikeClasses` contains ``CustomString``, the check will suggest vvd170501 wrote: Shouldn't `CustomString` be rendered as code here? https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From ab87ad179f385934e2ec17517b47da33d29eb256 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH] readability-string-compare: check std::string_view, allow custom string-like classes --- .../readability/StringCompareCheck.cpp| 27 -- .../readability/StringCompareCheck.h | 10 - clang-tools-extra/docs/ReleaseNotes.rst | 5 +++ .../checks/readability/string-compare.rst | 37 ++- .../clang-tidy/checkers/Inputs/Headers/string | 10 + .../string-compare-custom-string-classes.cpp | 35 ++ .../checkers/readability/string-compare.cpp | 23 7 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..7c0bbef3ca0878 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,15 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,11 +23,27 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const StringRef DefaultStringLikeClasses = "::std::basic_string;" + "::std::basic_string_view"; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses(optutils::parseStringList( + Options.get("StringLikeClasses", DefaultStringLikeClasses))) {} + +void StringCompareCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "StringLikeClasses", +optutils::serializeStringList(StringLikeClasses)); +} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { + if (StringLikeClasses.empty()) { +return; + } const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), + callee(cxxMethodDecl(hasName("compare"), ofClass(cxxRecordDecl(hasAnyName( + StringLikeClasses), hasArgument(0, expr().bind("str2")), argumentCountIs(1), callee(memberExpr().bind("str1"))); diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h index 812736d806b71d..150090901a6e97 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H #include "../ClangTidyCheck.h" +#include namespace clang::tidy::readability { @@ -20,13 +21,18 @@ namespace clang::tidy::readability { /// http://clang.llvm.org/extra/clang-tidy/checks/readability/string-compare.html class StringCompareCheck : public ClangTidyCheck { public: - StringCompareCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + StringCompareCheck(StringRef Name, ClangTidyContext *Context); + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + const std::vector StringLikeClasses; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 5b1feffb89ea06..aa8b4a63b60946 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -314,6 +314,11 @@ Changes in existing checks check by resolving fix-it overlaps in template code by disregarding implicit instances. +-
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/88636 >From 54b68bdb6cdc6bdd81178e2abd78d211b6b7181a Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Sat, 13 Apr 2024 23:36:12 +0300 Subject: [PATCH] readability-string-compare: check std::string_view, allow custom string-like classes Co-authored-by: EugeneZelenko --- .../readability/StringCompareCheck.cpp| 27 -- .../readability/StringCompareCheck.h | 10 - clang-tools-extra/docs/ReleaseNotes.rst | 5 +++ .../checks/readability/string-compare.rst | 37 ++- .../clang-tidy/checkers/Inputs/Headers/string | 10 + .../string-compare-custom-string-classes.cpp | 35 ++ .../checkers/readability/string-compare.cpp | 23 7 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c64719..7c0bbef3ca0878 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,15 @@ //===--===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,11 +23,27 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const StringRef DefaultStringLikeClasses = "::std::basic_string;" + "::std::basic_string_view"; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) +: ClangTidyCheck(Name, Context), + StringLikeClasses(optutils::parseStringList( + Options.get("StringLikeClasses", DefaultStringLikeClasses))) {} + +void StringCompareCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "StringLikeClasses", +optutils::serializeStringList(StringLikeClasses)); +} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { + if (StringLikeClasses.empty()) { +return; + } const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"), + callee(cxxMethodDecl(hasName("compare"), ofClass(cxxRecordDecl(hasAnyName( + StringLikeClasses), hasArgument(0, expr().bind("str2")), argumentCountIs(1), callee(memberExpr().bind("str1"))); diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h index 812736d806b71d..150090901a6e97 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H #include "../ClangTidyCheck.h" +#include namespace clang::tidy::readability { @@ -20,13 +21,18 @@ namespace clang::tidy::readability { /// http://clang.llvm.org/extra/clang-tidy/checks/readability/string-compare.html class StringCompareCheck : public ClangTidyCheck { public: - StringCompareCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + StringCompareCheck(StringRef Name, ClangTidyContext *Context); + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + const std::vector StringLikeClasses; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 5b1feffb89ea06..aa8b4a63b60946 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -314,6 +314,11 @@ Changes in existing checks check by resolving fix-it overlaps in template code by disregardi
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
vvd170501 wrote: @PiotrZSL, can you merge this, please? I've fixed merge conflicts caused by ef5906989ae2004100ff56dc5ab59be2be9d5c99 (changes in the string header for tests), now everything should be ok https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
vvd170501 wrote: Ping. Can anyone review this, please? https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
vvd170501 wrote: Ping https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clang-tidy] check `std::string_view` and custom string-like classes in `readability-string-compare` (PR #88636)
vvd170501 wrote: @EugeneZelenko, can you approve this, please? Or are 2 approves enough to merge? https://github.com/llvm/llvm-project/pull/88636 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
@@ -572,32 +572,43 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { vvd170501 wrote: But then if `F.IgnoreHeader` is empty, we'll be allocating and deallocating an unneeded vector. It's also possible to use `if (Filters->empty() && !AnalyzeSystemHeaders.has_value()) return;` and check `Filters->empty()`again in line 601, but I wanted to remove the unneeded allocation. https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
@@ -572,32 +572,43 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { +// Anchor on the right. +std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; +llvm::Regex CompiledRegex(AnchoredPattern, Flags); +std::string RegexError; +if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), + HeaderPattern.Range); + continue; +} +Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } -if (Filters->empty()) +std::optional AnalyzeSystemHeaders; +if (F.AnalyzeSystemHeaders.has_value()) + AnalyzeSystemHeaders = **F.AnalyzeSystemHeaders; vvd170501 wrote: Yes, it's intentional. `F.AnalyzeSystemHeaders` is a `std::optional>`, but the lambda only needs to capture a `std::optional`. Lines 594-596 are equivalent to the following c++23 code: ```cpp auto AnalyzeSystemHeaders = F.AnalyzeSystemHeaders.transform( [](const auto& LocatedValue) { return *LocatedValue; } ); ``` https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
@@ -135,6 +135,21 @@ TEST(IncludeCleaner, GetUnusedHeaders) { Pointee(writtenInclusion("\"dir/unused.h\""; } +TEST(IncludeCleaner, SystemUnusedHeaders) { + auto TU = TestTU::withCode(R"cpp( +#include +#include +SystemClass x; + )cpp"); + TU.AdditionalFiles["system/system_header.h"] = guard("class SystemClass {};"); + TU.AdditionalFiles["system/system_unused.h"] = guard(""); + TU.ExtraArgs = {"-isystem", testPath("system")}; + auto AST = TU.build(); + IncludeCleanerFindings Findings = computeIncludeCleanerFindings(AST, true); vvd170501 wrote: Isn;t this already covered by the `GetUnusedHeaders` test? There's an unused `` which must not present in `UnusedIncludes`. https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
@@ -135,6 +135,21 @@ TEST(IncludeCleaner, GetUnusedHeaders) { Pointee(writtenInclusion("\"dir/unused.h\""; } +TEST(IncludeCleaner, SystemUnusedHeaders) { + auto TU = TestTU::withCode(R"cpp( +#include +#include +SystemClass x; + )cpp"); + TU.AdditionalFiles["system/system_header.h"] = guard("class SystemClass {};"); + TU.AdditionalFiles["system/system_unused.h"] = guard(""); + TU.ExtraArgs = {"-isystem", testPath("system")}; vvd170501 wrote: I've copied `-isystem` from the `GetUnusedHeaders` test. If `AnalyzeSystemHeaders` / `AnalyzeAngledIncludes` must work for inclusions of any type, then maybe it'd be better to test both `-I` and `-isystem`? https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/87208 >From 35db92dfd0c2b43fc7afde5b093598763c4b8c89 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Mon, 1 Apr 2024 02:26:14 +0300 Subject: [PATCH 1/4] Add config option to analyze unused system headers --- clang-tools-extra/clangd/Config.h | 1 + clang-tools-extra/clangd/ConfigCompile.cpp| 57 +++ clang-tools-extra/clangd/ConfigFragment.h | 4 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++ clang-tools-extra/clangd/IncludeCleaner.cpp | 34 +++ clang-tools-extra/clangd/IncludeCleaner.h | 13 + clang-tools-extra/clangd/ParsedAST.cpp| 3 +- .../clangd/unittests/ConfigCompileTests.cpp | 6 ++ .../clangd/unittests/ConfigYAMLTests.cpp | 15 + .../clangd/unittests/IncludeCleanerTests.cpp | 15 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ 11 files changed, 112 insertions(+), 45 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c587..9629854abff31 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -114,6 +114,7 @@ struct Config { /// these regexes. struct { std::vector> IgnoreHeader; + bool AnalyzeSystemHeaders = false; } Includes; } Diagnostics; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 5bb2eb4a9f803..f74c870adfb73 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -572,32 +572,43 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { +// Anchor on the right. +std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; +llvm::Regex CompiledRegex(AnchoredPattern, Flags); +std::string RegexError; +if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), + HeaderPattern.Range); + continue; +} +Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } -if (Filters->empty()) +std::optional AnalyzeSystemHeaders; +if (F.AnalyzeSystemHeaders.has_value()) + AnalyzeSystemHeaders = **F.AnalyzeSystemHeaders; +if (!Filters && !AnalyzeSystemHeaders.has_value()) return; -auto Filter = [Filters](llvm::StringRef Path) { - for (auto &Regex : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config &C) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config &C) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto &Regex : *Filters) +if (Regex.match(Path)) + return true; + return false; +}; +C.Diagnostics.Includes.IgnoreHeader.emplace_back(std::move(Filter)); + } + if (AnalyzeSystemHeaders.has_value()) +C.Diagnostics.Includes.AnalyzeSystemHeaders = *AnalyzeSystemHeaders; }); } diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 7fa61108c78a0..ac8b88c245412 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -254,6 +254,10 @@ struct Fragment { /// unused or missing. These can match any suffix of the header file in /// question. std::vector> IgnoreHeader; + + /// If false (default), unused system headers will be ignored. + /// Standard library headers are analyzed regardless of this option. + std::optional> AnalyzeSystemHeaders; }; IncludesBlock Includes; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index ce09af819247a..7608af4200538 100644 --- a/clang-t
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/87208 >From 35db92dfd0c2b43fc7afde5b093598763c4b8c89 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Mon, 1 Apr 2024 02:26:14 +0300 Subject: [PATCH 1/6] Add config option to analyze unused system headers --- clang-tools-extra/clangd/Config.h | 1 + clang-tools-extra/clangd/ConfigCompile.cpp| 57 +++ clang-tools-extra/clangd/ConfigFragment.h | 4 ++ clang-tools-extra/clangd/ConfigYAML.cpp | 4 ++ clang-tools-extra/clangd/IncludeCleaner.cpp | 34 +++ clang-tools-extra/clangd/IncludeCleaner.h | 13 + clang-tools-extra/clangd/ParsedAST.cpp| 3 +- .../clangd/unittests/ConfigCompileTests.cpp | 6 ++ .../clangd/unittests/ConfigYAMLTests.cpp | 15 + .../clangd/unittests/IncludeCleanerTests.cpp | 15 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ 11 files changed, 112 insertions(+), 45 deletions(-) diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h index 4371c80a6c587..9629854abff31 100644 --- a/clang-tools-extra/clangd/Config.h +++ b/clang-tools-extra/clangd/Config.h @@ -114,6 +114,7 @@ struct Config { /// these regexes. struct { std::vector> IgnoreHeader; + bool AnalyzeSystemHeaders = false; } Includes; } Diagnostics; diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 5bb2eb4a9f803..f74c870adfb73 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -572,32 +572,43 @@ struct FragmentCompiler { #else static llvm::Regex::RegexFlags Flags = llvm::Regex::NoFlags; #endif -auto Filters = std::make_shared>(); -for (auto &HeaderPattern : F.IgnoreHeader) { - // Anchor on the right. - std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; - llvm::Regex CompiledRegex(AnchoredPattern, Flags); - std::string RegexError; - if (!CompiledRegex.isValid(RegexError)) { -diag(Warning, - llvm::formatv("Invalid regular expression '{0}': {1}", - *HeaderPattern, RegexError) - .str(), - HeaderPattern.Range); -continue; +std::shared_ptr> Filters; +if (!F.IgnoreHeader.empty()) { + Filters = std::make_shared>(); + for (auto &HeaderPattern : F.IgnoreHeader) { +// Anchor on the right. +std::string AnchoredPattern = "(" + *HeaderPattern + ")$"; +llvm::Regex CompiledRegex(AnchoredPattern, Flags); +std::string RegexError; +if (!CompiledRegex.isValid(RegexError)) { + diag(Warning, + llvm::formatv("Invalid regular expression '{0}': {1}", + *HeaderPattern, RegexError) + .str(), + HeaderPattern.Range); + continue; +} +Filters->push_back(std::move(CompiledRegex)); } - Filters->push_back(std::move(CompiledRegex)); } -if (Filters->empty()) +std::optional AnalyzeSystemHeaders; +if (F.AnalyzeSystemHeaders.has_value()) + AnalyzeSystemHeaders = **F.AnalyzeSystemHeaders; +if (!Filters && !AnalyzeSystemHeaders.has_value()) return; -auto Filter = [Filters](llvm::StringRef Path) { - for (auto &Regex : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config &C) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config &C) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto &Regex : *Filters) +if (Regex.match(Path)) + return true; + return false; +}; +C.Diagnostics.Includes.IgnoreHeader.emplace_back(std::move(Filter)); + } + if (AnalyzeSystemHeaders.has_value()) +C.Diagnostics.Includes.AnalyzeSystemHeaders = *AnalyzeSystemHeaders; }); } diff --git a/clang-tools-extra/clangd/ConfigFragment.h b/clang-tools-extra/clangd/ConfigFragment.h index 7fa61108c78a0..ac8b88c245412 100644 --- a/clang-tools-extra/clangd/ConfigFragment.h +++ b/clang-tools-extra/clangd/ConfigFragment.h @@ -254,6 +254,10 @@ struct Fragment { /// unused or missing. These can match any suffix of the header file in /// question. std::vector> IgnoreHeader; + + /// If false (default), unused system headers will be ignored. + /// Standard library headers are analyzed regardless of this option. + std::optional> AnalyzeSystemHeaders; }; IncludesBlock Includes; diff --git a/clang-tools-extra/clangd/ConfigYAML.cpp b/clang-tools-extra/clangd/ConfigYAML.cpp index ce09af819247a..7608af4200538 100644 --- a/clang-t
[clang-tools-extra] [clangd] Add config option to allow detection of unused system headers (PR #87208)
vvd170501 wrote: Ping. @kadircet, can you merge this, please? Or are additional approvals required? https://github.com/llvm/llvm-project/pull/87208 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-tools-extra] Fix OOM in FormatDiagnostic (PR #108187)
@@ -945,50 +959,11 @@ class DiagnosticsEngine : public RefCountedBase { void Report(const StoredDiagnostic &storedDiag); - /// Determine whethere there is already a diagnostic in flight. - bool isDiagnosticInFlight() const { -return CurDiagID != std::numeric_limits::max(); - } - - /// Set the "delayed" diagnostic that will be emitted once - /// the current diagnostic completes. - /// - /// If a diagnostic is already in-flight but the front end must - /// report a problem (e.g., with an inconsistent file system - /// state), this routine sets a "delayed" diagnostic that will be - /// emitted after the current diagnostic completes. This should - /// only be used for fatal errors detected at inconvenient - /// times. If emitting a delayed diagnostic causes a second delayed - /// diagnostic to be introduced, that second delayed diagnostic - /// will be ignored. - /// - /// \param DiagID The ID of the diagnostic being delayed. - /// - /// \param Arg1 A string argument that will be provided to the - /// diagnostic. A copy of this string will be stored in the - /// DiagnosticsEngine object itself. - /// - /// \param Arg2 A string argument that will be provided to the - /// diagnostic. A copy of this string will be stored in the - /// DiagnosticsEngine object itself. - /// - /// \param Arg3 A string argument that will be provided to the - /// diagnostic. A copy of this string will be stored in the - /// DiagnosticsEngine object itself. - void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "", -StringRef Arg2 = "", StringRef Arg3 = ""); - - /// Clear out the current diagnostic. - void Clear() { CurDiagID = std::numeric_limits::max(); } - - /// Return the value associated with this diagnostic flag. - StringRef getFlagValue() const { return FlagValue; } - private: // This is private state used by DiagnosticBuilder. We put it here instead of // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight - // object. This implementation choice means that we can only have one - // diagnostic "in flight" at a time, but this seems to be a reasonable + // object. This implementation choice means that we can only have a few + // diagnostics "in flight" at a time, but this seems to be a reasonable // tradeoff to keep these objects small. Assertions verify that only one // diagnostic is in flight at a time. vvd170501 wrote: "Assertions verify that only one diagnostic is in flight at a time" is now outdated and can be removed. https://github.com/llvm/llvm-project/pull/108187 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (fixes #113494) (PR #113612)
@@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), vvd170501 wrote: This assertion could fail only if entries for a symbol were partially grouped, but it didn't fail if entries weren't grouped at all. Example: ```cpp // StdSpecialSymbolMap.inc SYMBOL(any_cast, std::, ) SYMBOL(div, std::, ) // StdSymbolMap.inc SYMBOL(any, std::, ) SYMBOL(any_cast, std::, ) // assertion doesn't fail because previous entry has a different name ... ``` https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (fixes #113494) (PR #113612)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (fixes #113494) (PR #113612)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (fixes #113494) (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 8fac50dc444eeb6c9ad19eb11f7d95457b153528 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:36:22 +0300 Subject: [PATCH 1/3] Move assertion to detect all ungrouped mappings --- clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..49e5765af112ff 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); +} +if (SymIndex >= 0 && +Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { + // Not a new symbol, use the same index. } else { // First symbol or new symbol, increment next available index. ++SymIndex; >From ba2d997ba87e2a5193429d3ca4900d4ae39420b7 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:22:56 +0300 Subject: [PATCH 2/3] Update std symbol mapping to v20230810 --- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 130 - .../Inclusions/Stdlib/StdSymbolMap.inc| 171 -- 2 files changed, 194 insertions(+), 107 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 0d351d688a3296..156e1e8ad5321c 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -233,6 +233,23 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// Overloads for different containers, actual header depends on function arg. +// Probably should use a special handler, like with std::move. +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) + // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) SYMBOL(abs, std::, ) @@ -242,9 +259,77 @@ SYMBOL(abs, None, ) SYMBOL(abs, None, ) SYMBOL(abs, None, ) -// Only add headers for the generic atomic template. +// Same as abs - ignore variants (std::complex, std::valarray) +SYMBOL(acos, std::, ) +SYMBOL(acos, None, ) +SYMBOL(acos, None, ) +SYMBOL(acosh, std::, ) +SYMBOL(acosh, None, ) +SYMBOL(acosh, None, ) +SYMBOL(asin, std::, ) +SYMBOL(asin, None, ) +SYMBOL(asin, None, ) +SYMBOL(asinh, std::, ) +SYMBOL(asinh, None, ) +SYMBOL(asinh, None, ) +SYMBOL(atan, std::, ) +SYMBOL(atan, None, ) +SYMBOL(atan, None, ) +SYMBOL(atan2, std::, ) +SYMBOL(atan2, None, ) +SYMBOL(atan2, None, ) +SYMBOL(atanh, std::, ) +SYMBOL(atanh, None, ) +SYMBOL(atanh, None, ) +SYMBOL(cos, std::, ) +SYMBOL(cos, None, ) +SYMBOL(cos, None, ) +SYMBOL(cosh, std::, ) +SYMBOL(cosh, None, ) +SYMBOL(cosh, None, ) +SYMBOL(exp, std::, ) +SYMBOL(exp, None, ) +SYMBOL(exp, None, ) +SYMBOL(log, std::, ) +SYMBOL(log, None, ) +SYMBOL(log, None, ) +SYMBOL(log10, std::, ) +SYMBOL(log10, None, ) +SYMBOL(log10, None, ) +SYMBOL(pow, std::, ) +SYMBOL(pow, None, ) +SYMBOL(pow, None, ) +SYMBOL(sin, std::, ) +SYMBOL(sin, None, ) +SYMBOL(sin, None, ) +SYMBOL(sinh, std::, ) +SYMBOL(sinh, None, ) +SYMBOL(sinh, None, ) +SYMBOL(sqrt, std::, ) +SYMBOL(sqrt, None, ) +SYMBOL(sqrt, None, ) +SYMBOL(tan, std::, ) +SYMBOL(tan, None, ) +SYMBOL(tan, None, ) +SYMBOL(tanh, std::, ) +SYMBOL(tanh, None, ) +SYMBOL(tanh, None, ) + +// Only add headers for the generic atomic template and atomic_* template functions. // Ignore variants (std::weak_ptr, std::shared_ptr). SYMBOL(atomic, std::, ) +SYMBOL(atomic_compare_exchange_strong, std::, ) +SYMBOL(atomic_compare_exchange_strong_explicit, std::, ) +SYMBOL(atomic_compare_exchange_weak, std::, ) +SYMBOL(atomic_compare_exchange_weak_explicit, std::, ) +SYMBOL(atomic_exchange, std::, ) +SYMBOL(atomic_exchange_explicit, std::, ) +SYMBOL
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 96662cb7f681e7158c05a0190894de70eee03d67 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Thu, 24 Oct 2024 23:18:52 +0300 Subject: [PATCH] Update std symbol mapping to v20230810; Move assertion to detect all ungrouped mappings --- .../Inclusions/Stdlib/StandardLibrary.cpp | 8 +- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 131 +- .../Inclusions/Stdlib/StdSymbolMap.inc| 171 -- 3 files changed, 200 insertions(+), 110 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..49e5765af112ff 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); +} +if (SymIndex >= 0 && +Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { + // Not a new symbol, use the same index. } else { // First symbol or new symbol, increment next available index. ++SymIndex; diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 0d351d688a3296..13060a0cc1d529 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -233,6 +233,23 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// Overloads for different containers, actual header depends on function arg. +// Probably should use a special handler, like with std::move. +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) + // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) SYMBOL(abs, std::, ) @@ -242,9 +259,78 @@ SYMBOL(abs, None, ) SYMBOL(abs, None, ) SYMBOL(abs, None, ) -// Only add headers for the generic atomic template. +// Same as abs - ignore variants (std::complex, std::valarray) +SYMBOL(acos, std::, ) +SYMBOL(acos, None, ) +SYMBOL(acos, None, ) +SYMBOL(acosh, std::, ) +SYMBOL(acosh, None, ) +SYMBOL(acosh, None, ) +SYMBOL(asin, std::, ) +SYMBOL(asin, None, ) +SYMBOL(asin, None, ) +SYMBOL(asinh, std::, ) +SYMBOL(asinh, None, ) +SYMBOL(asinh, None, ) +SYMBOL(atan, std::, ) +SYMBOL(atan, None, ) +SYMBOL(atan, None, ) +SYMBOL(atan2, std::, ) +SYMBOL(atan2, None, ) +SYMBOL(atan2, None, ) +SYMBOL(atanh, std::, ) +SYMBOL(atanh, None, ) +SYMBOL(atanh, None, ) +SYMBOL(cos, std::, ) +SYMBOL(cos, None, ) +SYMBOL(cos, None, ) +SYMBOL(cosh, std::, ) +SYMBOL(cosh, None, ) +SYMBOL(cosh, None, ) +SYMBOL(exp, std::, ) +SYMBOL(exp, None, ) +SYMBOL(exp, None, ) +SYMBOL(log, std::, ) +SYMBOL(log, None, ) +SYMBOL(log, None, ) +SYMBOL(log10, std::, ) +SYMBOL(log10, None, ) +SYMBOL(log10, None, ) +SYMBOL(pow, std::, ) +SYMBOL(pow, None, ) +SYMBOL(pow, None, ) +SYMBOL(sin, std::, ) +SYMBOL(sin, None, ) +SYMBOL(sin, None, ) +SYMBOL(sinh, std::, ) +SYMBOL(sinh, None, ) +SYMBOL(sinh, None, ) +SYMBOL(sqrt, std::, ) +SYMBOL(sqrt, None, ) +SYMBOL(sqrt, None, ) +SYMBOL(tan, std::, ) +SYMBOL(tan, None, ) +SYMBOL(tan, None, ) +SYMBOL(tanh, std::, ) +SYMBOL(tanh, None, ) +SYMBOL(tanh, None, ) + +// Only add headers for the generic atomic template +// and atomic_* template functions. // Ignore variants (std::weak_ptr, std::shared_ptr). SYMBOL(atomic, std::, ) +SYMBOL(atomic_compare_exchange_strong, std::, ) +SYMBOL(atomic_compare_exchange_strong_explicit, std::, ) +SYMBOL(atomic_compare_exchange_weak, std::, ) +SYMBOL(atomic_compare_exchange_weak_explicit, std::, ) +SYMBOL(atomic_exchange, std::, ) +SYMBOL(atomic_exchange_explicit, std::, ) +SYMBOL(atomic_is_lock_free, std::, ) +SYMBOL(atomic_load, std::, ) +SYMBOL(atomic_load_explicit, std::, ) +SYMBOL(atomic_store, std::, ) +SYMBOL(atomic_store_explicit, std::, ) + // atomic_* family symbols. is for C compatibility. SYMBOL(atomic_bool, std::, ) SYMBOL(atomic_bool, None, ) @@ -355,18 +441,4
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
@@ -232,6 +232,37 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// C++ [range.access.general]: ... the customization point objects +// in [range.access] are available when the header is included. +SYMBOL(begin, std::ranges::, ) +SYMBOL(begin, std::ranges::, ) +SYMBOL(cbegin, std::ranges::, ) +SYMBOL(cbegin, std::ranges::, ) +SYMBOL(cdata, std::ranges::, ) +SYMBOL(cdata, std::ranges::, ) +SYMBOL(cend, std::ranges::, ) +SYMBOL(cend, std::ranges::, ) +SYMBOL(crbegin, std::ranges::, ) +SYMBOL(crbegin, std::ranges::, ) +SYMBOL(crend, std::ranges::, ) +SYMBOL(crend, std::ranges::, ) +SYMBOL(data, std::ranges::, ) +SYMBOL(data, std::ranges::, ) +SYMBOL(empty, std::ranges::, ) +SYMBOL(empty, std::ranges::, ) +SYMBOL(end, std::ranges::, ) +SYMBOL(end, std::ranges::, ) +SYMBOL(rbegin, std::ranges::, ) +SYMBOL(rbegin, std::ranges::, ) +SYMBOL(rend, std::ranges::, ) +SYMBOL(rend, std::ranges::, ) +SYMBOL(size, std::ranges::, ) +SYMBOL(size, std::ranges::, ) +SYMBOL(ssize, std::ranges::, ) +SYMBOL(ssize, std::ranges::, ) vvd170501 wrote: Done https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
vvd170501 wrote: I've reverted the optimizations, will create a new PR when this one is merged (the commit depends on other changes that I've left in this PR) https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 853881983faeeb5b7e0582d3e94037c12df12c7c Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 00:17:26 +0300 Subject: [PATCH 1/4] Fix variant parsing --- .../include-mapping/cppreference_parser.py| 33 --- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index f2ea55384fac80..70e403bba64917 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -7,7 +7,7 @@ # # ======# -from bs4 import BeautifulSoup, NavigableString +from bs4 import BeautifulSoup, NavigableString, Tag import collections import multiprocessing @@ -89,6 +89,23 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): return headers or all_headers +def _ParseSymbolVariant(caption): +if not (isinstance(caption, NavigableString) and "(" in caption): +return None + +if ')' in caption.text: # (locale), (algorithm), etc. +return caption.text.strip(" ()") + +second_part = caption.next_sibling +if isinstance(second_part, Tag) and second_part.name == "code": +# (std::complex), etc. +third_part = second_part.next_sibling +if isinstance(third_part, NavigableString) and third_part.text.startswith(')'): +return second_part.text +return None + + + def _ParseIndexPage(index_page_html): """Parse index page. The index page lists all std symbols and hrefs to their detailed pages @@ -107,9 +124,7 @@ def _ParseIndexPage(index_page_html): # This accidentally accepts begin/end despite the (iterator) caption: the # (since C++11) note is first. They are good symbols, so the bug is unfixed. caption = symbol_href.next_sibling -variant = None -if isinstance(caption, NavigableString) and "(" in caption: -variant = caption.text.strip(" ()") +variant = _ParseSymbolVariant(caption) symbol_tt = symbol_href.find("tt") if symbol_tt: symbols.append( @@ -192,6 +207,16 @@ def GetSymbols(parse_pages): variants_to_accept = { # std::remove<> has variant algorithm. "std::remove": ("algorithm"), +# These functions don't have a generic version, and all variants are defined in +"std::chrono::abs": ("std::chrono::duration"), +"std::chrono::ceil": ("std::chrono::duration"), +"std::chrono::floor": ("std::chrono::duration"), +"std::chrono::from_stream": ("std::chrono::day"), +"std::chrono::round": ("std::chrono::duration"), +# Same, but in +"std::filesystem::begin": ("std::filesystem::directory_iterator"), +"std::filesystem::end": ("std::filesystem::directory_iterator"), +"std::ranges::get": ("std::ranges::subrange"), } symbols = [] # Run many workers to process individual symbol pages under the symbol index. >From 76fd590931925f817f54f684af90a81305c7b1f5 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 06:38:41 +0300 Subject: [PATCH 2/4] Parse symbols with qualified name --- .../include-mapping/cppreference_parser.py| 24 ++- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index 70e403bba64917..9101f3dbff0f94 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -40,7 +40,7 @@ def _HasClass(tag, *classes): return False -def _ParseSymbolPage(symbol_page_html, symbol_name): +def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): """Parse symbol page and retrieve the include header defined in this page. The symbol page provides header for the symbol, specifically in "Defined in header " section. An example: @@ -69,7 +69,9 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): was_decl = True # Symbols are in the first cell. found_symbols = row.find("td").stripped_strings -if not symbol_name in found_symbols: +if not any( +sym == symbol_name or sym == qual_name for sym in found_symbols +): continue headers.update(current_headers) elif _HasClass(row, "t-dsc-header"): @@ -93,19 +95,18 @@ def _ParseSymbolVariant(caption): if not (isinstance(caption, NavigableString) and "(" in caption): return None -if ')' in caption.text: # (locale), (algorithm), etc. +if ")"
[clang] [Tooling/Inclusion] Optimize cppreference parser (parse each page only once) (PR #114832)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/114832 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Optimize cppreference parser (PR #114832)
https://github.com/vvd170501 created https://github.com/llvm/llvm-project/pull/114832 These are reverted changes from #113612. They don't affect clang itself, but speed up std symbol mapping generator by ~1.5x. On a machine with 2 cores, it previously took 3 minutes to generate the mapping, now it only takes 2 minutes. With 8 cores, the time goes down from ~50s to ~30s >From cde239f6168e525d543f90a029ba643bc1b8c797 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Mon, 4 Nov 2024 19:53:35 +0300 Subject: [PATCH] Don't reparse symbol pages (speedup up to 1.5x) --- .../include-mapping/cppreference_parser.py| 48 +++ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index 9101f3dbff0f94..d26f4c4395ab92 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -40,7 +40,7 @@ def _HasClass(tag, *classes): return False -def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): +def _ParseSymbolPage(symbol_page_html, symbols): """Parse symbol page and retrieve the include header defined in this page. The symbol page provides header for the symbol, specifically in "Defined in header " section. An example: @@ -51,8 +51,12 @@ def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): Returns a list of headers. """ -headers = set() +headers = collections.defaultdict(set) all_headers = set() +symbol_names = {} +for symbol_name, qualified_symbol_name in symbols: +symbol_names[symbol_name] = symbol_name +symbol_names[qualified_symbol_name] = symbol_name soup = BeautifulSoup(symbol_page_html, "html.parser") # Rows in table are like: @@ -69,11 +73,10 @@ def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): was_decl = True # Symbols are in the first cell. found_symbols = row.find("td").stripped_strings -if not any( -sym == symbol_name or sym == qual_name for sym in found_symbols -): -continue -headers.update(current_headers) +for found_symbol in found_symbols: +symbol_name = symbol_names.get(found_symbol) +if symbol_name: +headers[symbol_name].update(current_headers) elif _HasClass(row, "t-dsc-header"): # If we saw a decl since the last header, this is a new block of headers # for a new block of decls. @@ -88,7 +91,10 @@ def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): current_headers.append(header_code.text) all_headers.add(header_code.text) # If the symbol was never named, consider all named headers. -return headers or all_headers +return [ +(symbol_name, headers.get(symbol_name) or all_headers) +for symbol_name, _ in symbols +] def _ParseSymbolVariant(caption): @@ -138,9 +144,9 @@ def _ParseIndexPage(index_page_html): return symbols -def _ReadSymbolPage(path, name, qual_name): +def _ReadSymbolPage(path, symbols): with open(path) as f: -return _ParseSymbolPage(f.read(), name, qual_name) +return _ParseSymbolPage(f.read(), symbols) def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept): @@ -159,6 +165,7 @@ def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept): with open(index_page_path, "r") as f: # Read each symbol page in parallel. results = [] # (symbol_name, promise of [header...]) +symbols_by_page = collections.defaultdict(list) for symbol_name, symbol_page_path, variant in _ParseIndexPage(f.read()): # Variant symbols (e.g. the std::locale version of isalpha) add ambiguity. # FIXME: use these as a fallback rather than ignoring entirely. @@ -167,25 +174,24 @@ def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept): if variant and variant not in variants_for_symbol: continue path = os.path.join(root_dir, symbol_page_path) -if os.path.isfile(path): -results.append( -( -symbol_name, -pool.apply_async( -_ReadSymbolPage, (path, symbol_name, qualified_symbol_name) -), -) -) +if path in symbols_by_page or os.path.isfile(path): +symbols_by_page[path].append((symbol_name, qualified_symbol_name)) else: sys.stderr.write( "Discarding information for symbol: %s. Page %s does not
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 1baa1c2aebd37da2f2ccc3918fa3425698860566 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 00:17:26 +0300 Subject: [PATCH] Update std symbol mapping to v20240610; Update mapping generator; Move assertion to detect all ungrouped mappings (rebase to test with updated StdSpecialSymbolMap.inc) --- .../Inclusions/Stdlib/StandardLibrary.cpp | 10 +- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 47 ++- .../Inclusions/Stdlib/StdSymbolMap.inc| 116 ++ .../include-mapping/cppreference_parser.py| 51 ++-- 4 files changed, 178 insertions(+), 46 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..90c95d5cf60d86 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,19 +115,19 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); -} else { +} +if (SymIndex < 0 || +Mapping->SymbolNames[SymIndex].qualifiedName() != QName) { // First symbol or new symbol, increment next available index. ++SymIndex; -} +} // Else use the same index. Mapping->SymbolNames[SymIndex] = { QName.data(), NSLen, static_cast(QName.size() - NSLen)}; if (!HeaderName.empty()) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 4d466013eeac3f..8f20ce98152f08 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -232,6 +232,38 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// C++ [range.access.general]: ... the customization point objects +// in [range.access] are available when the header is included. +// (see https://eel.is/c++draft/range.access#general) +SYMBOL(begin, std::ranges::, ) +SYMBOL(begin, std::ranges::, ) +SYMBOL(end, std::ranges::, ) +SYMBOL(end, std::ranges::, ) +SYMBOL(cbegin, std::ranges::, ) +SYMBOL(cbegin, std::ranges::, ) +SYMBOL(cend, std::ranges::, ) +SYMBOL(cend, std::ranges::, ) +SYMBOL(rbegin, std::ranges::, ) +SYMBOL(rbegin, std::ranges::, ) +SYMBOL(rend, std::ranges::, ) +SYMBOL(rend, std::ranges::, ) +SYMBOL(crbegin, std::ranges::, ) +SYMBOL(crbegin, std::ranges::, ) +SYMBOL(crend, std::ranges::, ) +SYMBOL(crend, std::ranges::, ) +SYMBOL(size, std::ranges::, ) +SYMBOL(size, std::ranges::, ) +SYMBOL(ssize, std::ranges::, ) +SYMBOL(ssize, std::ranges::, ) +SYMBOL(empty, std::ranges::, ) +SYMBOL(empty, std::ranges::, ) +SYMBOL(data, std::ranges::, ) +SYMBOL(data, std::ranges::, ) +SYMBOL(cdata, std::ranges::, ) +SYMBOL(cdata, std::ranges::, ) + +// Ignore specializations +SYMBOL(hash, std::, ) // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) @@ -352,20 +384,23 @@ SYMBOL(get, std::, /*no headers*/) // providing the type. SYMBOL(make_error_code, std::, /*no headers*/) SYMBOL(make_error_condition, std::, /*no headers*/) +// Similar to std::get, has variants for multiple containers +// (vector, deque, list, etc.) +SYMBOL(erase, std::, /*no headers*/) +SYMBOL(erase_if, std::, /*no headers*/) // cppreference symbol index page was missing these symbols. // Remove them when the cppreference offline archive catches up. -SYMBOL(index_sequence, std::, ) -SYMBOL(index_sequence_for, std::, ) -SYMBOL(make_index_sequence, std::, ) -SYMBOL(make_integer_sequence, std::, ) +SYMBOL(regular_invocable, std::, ) // Symbols missing from the generated symbol map as reported by users. // Remove when the generator starts producing them. -SYMBOL(make_any, std::, ) -SYMBOL(any_cast, std::, ) SYMBOL(div, std::, ) SYMBOL(abort, std::, ) +SYMBOL(atomic_wait, std::, ) +SYMBOL(atomic_wait_explicit, std::, ) +SYMBOL(move_backward, std::, ) +SYMBOL(month_weekday, std::chrono::, ) SYMBOL(binary_search, std::ranges::, ) SYMBOL(equal_range, std::ranges::, ) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc index b46bd2e4d7a4b5..b4afd0228694ff 100644 --- a/clang/lib/Tooling
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
vvd170501 wrote: @kadircet, ping. Could you commit these changes, please? I've rebased to make sure that 68daf7d27ecc085fe7347552736197db6453f71c didn't cause any conflicts. https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
vvd170501 wrote: > thanks a lot, lgtm! > > LMK if i should commit this for you Yes, commit it please, I don't have the permissions. https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
@@ -352,20 +383,23 @@ SYMBOL(get, std::, /*no headers*/) // providing the type. SYMBOL(make_error_code, std::, /*no headers*/) SYMBOL(make_error_condition, std::, /*no headers*/) +// Similar to std::get, has variants for multiple containers +// (vector, deque, list, etc.) +SYMBOL(erase, std::, /*no headers*/) +SYMBOL(erase_if, std::, /*no headers*/) // cppreference symbol index page was missing these symbols. // Remove them when the cppreference offline archive catches up. -SYMBOL(index_sequence, std::, ) -SYMBOL(index_sequence_for, std::, ) -SYMBOL(make_index_sequence, std::, ) -SYMBOL(make_integer_sequence, std::, ) +SYMBOL(regular_invocable, std::, ) // Symbols missing from the generated symbol map as reported by users. // Remove when the generator starts producing them. -SYMBOL(make_any, std::, ) -SYMBOL(any_cast, std::, ) SYMBOL(div, std::, ) SYMBOL(abort, std::, ) +SYMBOL(atomic_wait, std::, ) +SYMBOL(atomic_wait_explicit, std::, ) +SYMBOL(move_backward, std::, ) +SYMBOL(month_weekday, std::chrono::, ) vvd170501 wrote: I've suggested fixes to the corresponding cppreference pages, the editors have added them. https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 853881983faeeb5b7e0582d3e94037c12df12c7c Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 00:17:26 +0300 Subject: [PATCH 1/5] Fix variant parsing --- .../include-mapping/cppreference_parser.py| 33 --- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index f2ea55384fac80..70e403bba64917 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -7,7 +7,7 @@ # # ======# -from bs4 import BeautifulSoup, NavigableString +from bs4 import BeautifulSoup, NavigableString, Tag import collections import multiprocessing @@ -89,6 +89,23 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): return headers or all_headers +def _ParseSymbolVariant(caption): +if not (isinstance(caption, NavigableString) and "(" in caption): +return None + +if ')' in caption.text: # (locale), (algorithm), etc. +return caption.text.strip(" ()") + +second_part = caption.next_sibling +if isinstance(second_part, Tag) and second_part.name == "code": +# (std::complex), etc. +third_part = second_part.next_sibling +if isinstance(third_part, NavigableString) and third_part.text.startswith(')'): +return second_part.text +return None + + + def _ParseIndexPage(index_page_html): """Parse index page. The index page lists all std symbols and hrefs to their detailed pages @@ -107,9 +124,7 @@ def _ParseIndexPage(index_page_html): # This accidentally accepts begin/end despite the (iterator) caption: the # (since C++11) note is first. They are good symbols, so the bug is unfixed. caption = symbol_href.next_sibling -variant = None -if isinstance(caption, NavigableString) and "(" in caption: -variant = caption.text.strip(" ()") +variant = _ParseSymbolVariant(caption) symbol_tt = symbol_href.find("tt") if symbol_tt: symbols.append( @@ -192,6 +207,16 @@ def GetSymbols(parse_pages): variants_to_accept = { # std::remove<> has variant algorithm. "std::remove": ("algorithm"), +# These functions don't have a generic version, and all variants are defined in +"std::chrono::abs": ("std::chrono::duration"), +"std::chrono::ceil": ("std::chrono::duration"), +"std::chrono::floor": ("std::chrono::duration"), +"std::chrono::from_stream": ("std::chrono::day"), +"std::chrono::round": ("std::chrono::duration"), +# Same, but in +"std::filesystem::begin": ("std::filesystem::directory_iterator"), +"std::filesystem::end": ("std::filesystem::directory_iterator"), +"std::ranges::get": ("std::ranges::subrange"), } symbols = [] # Run many workers to process individual symbol pages under the symbol index. >From 76fd590931925f817f54f684af90a81305c7b1f5 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 06:38:41 +0300 Subject: [PATCH 2/5] Parse symbols with qualified name --- .../include-mapping/cppreference_parser.py| 24 ++- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index 70e403bba64917..9101f3dbff0f94 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -40,7 +40,7 @@ def _HasClass(tag, *classes): return False -def _ParseSymbolPage(symbol_page_html, symbol_name): +def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): """Parse symbol page and retrieve the include header defined in this page. The symbol page provides header for the symbol, specifically in "Defined in header " section. An example: @@ -69,7 +69,9 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): was_decl = True # Symbols are in the first cell. found_symbols = row.find("td").stripped_strings -if not symbol_name in found_symbols: +if not any( +sym == symbol_name or sym == qual_name for sym in found_symbols +): continue headers.update(current_headers) elif _HasClass(row, "t-dsc-header"): @@ -93,19 +95,18 @@ def _ParseSymbolVariant(caption): if not (isinstance(caption, NavigableString) and "(" in caption): return None -if ')' in caption.text: # (locale), (algorithm), etc. +if ")"
[clang] Update std symbols mapping (fixes #113494) (PR #113612)
https://github.com/vvd170501 created https://github.com/llvm/llvm-project/pull/113612 None >From 8fac50dc444eeb6c9ad19eb11f7d95457b153528 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:36:22 +0300 Subject: [PATCH 1/2] Move assertion to detect all ungrouped mappings --- clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..49e5765af112ff 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); +} +if (SymIndex >= 0 && +Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { + // Not a new symbol, use the same index. } else { // First symbol or new symbol, increment next available index. ++SymIndex; >From ba2d997ba87e2a5193429d3ca4900d4ae39420b7 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:22:56 +0300 Subject: [PATCH 2/2] Update std symbol mapping to v20230810 --- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 130 - .../Inclusions/Stdlib/StdSymbolMap.inc| 171 -- 2 files changed, 194 insertions(+), 107 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 0d351d688a3296..156e1e8ad5321c 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -233,6 +233,23 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// Overloads for different containers, actual header depends on function arg. +// Probably should use a special handler, like with std::move. +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) + // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) SYMBOL(abs, std::, ) @@ -242,9 +259,77 @@ SYMBOL(abs, None, ) SYMBOL(abs, None, ) SYMBOL(abs, None, ) -// Only add headers for the generic atomic template. +// Same as abs - ignore variants (std::complex, std::valarray) +SYMBOL(acos, std::, ) +SYMBOL(acos, None, ) +SYMBOL(acos, None, ) +SYMBOL(acosh, std::, ) +SYMBOL(acosh, None, ) +SYMBOL(acosh, None, ) +SYMBOL(asin, std::, ) +SYMBOL(asin, None, ) +SYMBOL(asin, None, ) +SYMBOL(asinh, std::, ) +SYMBOL(asinh, None, ) +SYMBOL(asinh, None, ) +SYMBOL(atan, std::, ) +SYMBOL(atan, None, ) +SYMBOL(atan, None, ) +SYMBOL(atan2, std::, ) +SYMBOL(atan2, None, ) +SYMBOL(atan2, None, ) +SYMBOL(atanh, std::, ) +SYMBOL(atanh, None, ) +SYMBOL(atanh, None, ) +SYMBOL(cos, std::, ) +SYMBOL(cos, None, ) +SYMBOL(cos, None, ) +SYMBOL(cosh, std::, ) +SYMBOL(cosh, None, ) +SYMBOL(cosh, None, ) +SYMBOL(exp, std::, ) +SYMBOL(exp, None, ) +SYMBOL(exp, None, ) +SYMBOL(log, std::, ) +SYMBOL(log, None, ) +SYMBOL(log, None, ) +SYMBOL(log10, std::, ) +SYMBOL(log10, None, ) +SYMBOL(log10, None, ) +SYMBOL(pow, std::, ) +SYMBOL(pow, None, ) +SYMBOL(pow, None, ) +SYMBOL(sin, std::, ) +SYMBOL(sin, None, ) +SYMBOL(sin, None, ) +SYMBOL(sinh, std::, ) +SYMBOL(sinh, None, ) +SYMBOL(sinh, None, ) +SYMBOL(sqrt, std::, ) +SYMBOL(sqrt, None, ) +SYMBOL(sqrt, None, ) +SYMBOL(tan, std::, ) +SYMBOL(tan, None, ) +SYMBOL(tan, None, ) +SYMBOL(tanh, std::, ) +SYMBOL(tanh, None, ) +SYMBOL(tanh, None, ) + +// Only add headers for the generic atomic template and atomic_* template functions. // Ignore variants (std::weak_ptr, std::shared_ptr). SYMBOL(atomic, std::, ) +SYMBOL(atomic_compare_exchange_strong, std::, ) +SYMBOL(atomic_compare_exchange_strong_explicit, std::, ) +SYMBOL(atomic_compare_exchange_weak, std::, ) +SYMBOL(atomic_compare_exchange_weak_explicit, std::, ) +SYMBOL(atomic_exchange, std::, ) +SYMBOL(atomic_exchange_explicit, std::, ) +
[clang] Update std symbols mapping (PR #113612)
@@ -143,32 +165,33 @@ def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept): with open(index_page_path, "r") as f: # Read each symbol page in parallel. results = [] # (symbol_name, promise of [header...]) +symbols_by_page = collections.defaultdict(list) vvd170501 wrote: On my machine it took about 3 minutes for the generator to run, so I tried to optimize it by grouping symbols that are defined on the same page (now it takes 2 minutes). If the diff is too large or complex, I can move the commit with optimizations to a separate PR. https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 96662cb7f681e7158c05a0190894de70eee03d67 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Thu, 24 Oct 2024 23:18:52 +0300 Subject: [PATCH 01/13] Update std symbol mapping to v20230810; Move assertion to detect all ungrouped mappings --- .../Inclusions/Stdlib/StandardLibrary.cpp | 8 +- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 131 +- .../Inclusions/Stdlib/StdSymbolMap.inc| 171 -- 3 files changed, 200 insertions(+), 110 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..49e5765af112ff 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); +} +if (SymIndex >= 0 && +Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { + // Not a new symbol, use the same index. } else { // First symbol or new symbol, increment next available index. ++SymIndex; diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 0d351d688a3296..13060a0cc1d529 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -233,6 +233,23 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// Overloads for different containers, actual header depends on function arg. +// Probably should use a special handler, like with std::move. +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) + // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) SYMBOL(abs, std::, ) @@ -242,9 +259,78 @@ SYMBOL(abs, None, ) SYMBOL(abs, None, ) SYMBOL(abs, None, ) -// Only add headers for the generic atomic template. +// Same as abs - ignore variants (std::complex, std::valarray) +SYMBOL(acos, std::, ) +SYMBOL(acos, None, ) +SYMBOL(acos, None, ) +SYMBOL(acosh, std::, ) +SYMBOL(acosh, None, ) +SYMBOL(acosh, None, ) +SYMBOL(asin, std::, ) +SYMBOL(asin, None, ) +SYMBOL(asin, None, ) +SYMBOL(asinh, std::, ) +SYMBOL(asinh, None, ) +SYMBOL(asinh, None, ) +SYMBOL(atan, std::, ) +SYMBOL(atan, None, ) +SYMBOL(atan, None, ) +SYMBOL(atan2, std::, ) +SYMBOL(atan2, None, ) +SYMBOL(atan2, None, ) +SYMBOL(atanh, std::, ) +SYMBOL(atanh, None, ) +SYMBOL(atanh, None, ) +SYMBOL(cos, std::, ) +SYMBOL(cos, None, ) +SYMBOL(cos, None, ) +SYMBOL(cosh, std::, ) +SYMBOL(cosh, None, ) +SYMBOL(cosh, None, ) +SYMBOL(exp, std::, ) +SYMBOL(exp, None, ) +SYMBOL(exp, None, ) +SYMBOL(log, std::, ) +SYMBOL(log, None, ) +SYMBOL(log, None, ) +SYMBOL(log10, std::, ) +SYMBOL(log10, None, ) +SYMBOL(log10, None, ) +SYMBOL(pow, std::, ) +SYMBOL(pow, None, ) +SYMBOL(pow, None, ) +SYMBOL(sin, std::, ) +SYMBOL(sin, None, ) +SYMBOL(sin, None, ) +SYMBOL(sinh, std::, ) +SYMBOL(sinh, None, ) +SYMBOL(sinh, None, ) +SYMBOL(sqrt, std::, ) +SYMBOL(sqrt, None, ) +SYMBOL(sqrt, None, ) +SYMBOL(tan, std::, ) +SYMBOL(tan, None, ) +SYMBOL(tan, None, ) +SYMBOL(tanh, std::, ) +SYMBOL(tanh, None, ) +SYMBOL(tanh, None, ) + +// Only add headers for the generic atomic template +// and atomic_* template functions. // Ignore variants (std::weak_ptr, std::shared_ptr). SYMBOL(atomic, std::, ) +SYMBOL(atomic_compare_exchange_strong, std::, ) +SYMBOL(atomic_compare_exchange_strong_explicit, std::, ) +SYMBOL(atomic_compare_exchange_weak, std::, ) +SYMBOL(atomic_compare_exchange_weak_explicit, std::, ) +SYMBOL(atomic_exchange, std::, ) +SYMBOL(atomic_exchange_explicit, std::, ) +SYMBOL(atomic_is_lock_free, std::, ) +SYMBOL(atomic_load, std::, ) +SYMBOL(atomic_load_explicit, std::, ) +SYMBOL(atomic_store, std::, ) +SYMBOL(atomic_store_explicit, std::, ) + // atomic_* family symbols. is for C compatibility. SYMBOL(atomic_bool, std::, ) SYMBOL(atomic_bool, None, ) @@ -355,18
[clang] Update std symbols mapping (PR #113612)
@@ -232,6 +232,47 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// C++ [range.access.general]: ... the customization point objects +// in [range.access] are available when the header is included. +SYMBOL(begin, std::ranges::, ) +SYMBOL(begin, std::ranges::, ) +SYMBOL(cbegin, std::ranges::, ) +SYMBOL(cbegin, std::ranges::, ) +SYMBOL(cdata, std::ranges::, ) +SYMBOL(cdata, std::ranges::, ) +SYMBOL(cend, std::ranges::, ) +SYMBOL(cend, std::ranges::, ) +SYMBOL(crbegin, std::ranges::, ) +SYMBOL(crbegin, std::ranges::, ) +SYMBOL(crend, std::ranges::, ) +SYMBOL(crend, std::ranges::, ) +SYMBOL(data, std::ranges::, ) +SYMBOL(data, std::ranges::, ) +SYMBOL(empty, std::ranges::, ) +SYMBOL(empty, std::ranges::, ) +SYMBOL(end, std::ranges::, ) +SYMBOL(end, std::ranges::, ) +SYMBOL(rbegin, std::ranges::, ) +SYMBOL(rbegin, std::ranges::, ) +SYMBOL(rend, std::ranges::, ) +SYMBOL(rend, std::ranges::, ) +SYMBOL(size, std::ranges::, ) +SYMBOL(size, std::ranges::, ) +SYMBOL(ssize, std::ranges::, ) +SYMBOL(ssize, std::ranges::, ) + +// FIXME lost after generator update - variants, probably should not be removed +SYMBOL(abs, std::chrono::, ) +SYMBOL(ceil, std::chrono::, ) +SYMBOL(floor, std::chrono::, ) +SYMBOL(from_stream, std::chrono::, ) +SYMBOL(round, std::chrono::, ) +SYMBOL(begin, std::filesystem::, ) +SYMBOL(end, std::filesystem::, ) +SYMBOL(get, std::ranges::, ) + +// Ignore specializations +SYMBOL(hash, std::, ) vvd170501 wrote: Not sure if it's better to keep `` or replace it with `/*no headers*/` https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Tooling/Inclusion] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 853881983faeeb5b7e0582d3e94037c12df12c7c Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 00:17:26 +0300 Subject: [PATCH 1/4] Fix variant parsing --- .../include-mapping/cppreference_parser.py| 33 --- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index f2ea55384fac80..70e403bba64917 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -7,7 +7,7 @@ # # ======# -from bs4 import BeautifulSoup, NavigableString +from bs4 import BeautifulSoup, NavigableString, Tag import collections import multiprocessing @@ -89,6 +89,23 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): return headers or all_headers +def _ParseSymbolVariant(caption): +if not (isinstance(caption, NavigableString) and "(" in caption): +return None + +if ')' in caption.text: # (locale), (algorithm), etc. +return caption.text.strip(" ()") + +second_part = caption.next_sibling +if isinstance(second_part, Tag) and second_part.name == "code": +# (std::complex), etc. +third_part = second_part.next_sibling +if isinstance(third_part, NavigableString) and third_part.text.startswith(')'): +return second_part.text +return None + + + def _ParseIndexPage(index_page_html): """Parse index page. The index page lists all std symbols and hrefs to their detailed pages @@ -107,9 +124,7 @@ def _ParseIndexPage(index_page_html): # This accidentally accepts begin/end despite the (iterator) caption: the # (since C++11) note is first. They are good symbols, so the bug is unfixed. caption = symbol_href.next_sibling -variant = None -if isinstance(caption, NavigableString) and "(" in caption: -variant = caption.text.strip(" ()") +variant = _ParseSymbolVariant(caption) symbol_tt = symbol_href.find("tt") if symbol_tt: symbols.append( @@ -192,6 +207,16 @@ def GetSymbols(parse_pages): variants_to_accept = { # std::remove<> has variant algorithm. "std::remove": ("algorithm"), +# These functions don't have a generic version, and all variants are defined in +"std::chrono::abs": ("std::chrono::duration"), +"std::chrono::ceil": ("std::chrono::duration"), +"std::chrono::floor": ("std::chrono::duration"), +"std::chrono::from_stream": ("std::chrono::day"), +"std::chrono::round": ("std::chrono::duration"), +# Same, but in +"std::filesystem::begin": ("std::filesystem::directory_iterator"), +"std::filesystem::end": ("std::filesystem::directory_iterator"), +"std::ranges::get": ("std::ranges::subrange"), } symbols = [] # Run many workers to process individual symbol pages under the symbol index. >From 09a421726314f2d9edb110e33106b3194e9f7014 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 06:38:41 +0300 Subject: [PATCH 2/4] Parse symbols with qualified name (not sure if it works in this revision) --- clang/tools/include-mapping/cppreference_parser.py | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index 70e403bba64917..d63be5d241884b 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -40,7 +40,7 @@ def _HasClass(tag, *classes): return False -def _ParseSymbolPage(symbol_page_html, symbol_name): +def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): """Parse symbol page and retrieve the include header defined in this page. The symbol page provides header for the symbol, specifically in "Defined in header " section. An example: @@ -69,7 +69,7 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): was_decl = True # Symbols are in the first cell. found_symbols = row.find("td").stripped_strings -if not symbol_name in found_symbols: +if not (symbol_name in found_symbols or qual_name in found_symbols): continue headers.update(current_headers) elif _HasClass(row, "t-dsc-header"): @@ -137,9 +137,9 @@ def _ParseIndexPage(index_page_html): return symbols -def _ReadSymbolPage(path, name): +def _ReadSymbolPage(path, name, qual_name): with open(path) as f: -return _ParseSymbolPage(f.read(),
[clang] Update std symbols mapping (PR #113612)
@@ -352,20 +383,23 @@ SYMBOL(get, std::, /*no headers*/) // providing the type. SYMBOL(make_error_code, std::, /*no headers*/) SYMBOL(make_error_condition, std::, /*no headers*/) +// Similar to std::get, has variants for multiple containers +// (vector, deque, list, etc.) +SYMBOL(erase, std::, /*no headers*/) +SYMBOL(erase_if, std::, /*no headers*/) // cppreference symbol index page was missing these symbols. // Remove them when the cppreference offline archive catches up. -SYMBOL(index_sequence, std::, ) -SYMBOL(index_sequence_for, std::, ) -SYMBOL(make_index_sequence, std::, ) -SYMBOL(make_integer_sequence, std::, ) +SYMBOL(regular_invocable, std::, ) // Symbols missing from the generated symbol map as reported by users. // Remove when the generator starts producing them. -SYMBOL(make_any, std::, ) -SYMBOL(any_cast, std::, ) SYMBOL(div, std::, ) SYMBOL(abort, std::, ) +SYMBOL(atomic_wait, std::, ) +SYMBOL(atomic_wait_explicit, std::, ) +SYMBOL(move_backward, std::, ) +SYMBOL(month_weekday, std::chrono::, ) vvd170501 wrote: These symbols and `std::regular_invocable` were lost in newer edits, but should be back in the next release of offline archive https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 ready_for_review https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 8fac50dc444eeb6c9ad19eb11f7d95457b153528 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:36:22 +0300 Subject: [PATCH 1/4] Move assertion to detect all ungrouped mappings --- clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp | 8 +--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..49e5765af112ff 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); +} +if (SymIndex >= 0 && +Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { + // Not a new symbol, use the same index. } else { // First symbol or new symbol, increment next available index. ++SymIndex; >From ba2d997ba87e2a5193429d3ca4900d4ae39420b7 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:22:56 +0300 Subject: [PATCH 2/4] Update std symbol mapping to v20230810 --- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 130 - .../Inclusions/Stdlib/StdSymbolMap.inc| 171 -- 2 files changed, 194 insertions(+), 107 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 0d351d688a3296..156e1e8ad5321c 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -233,6 +233,23 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// Overloads for different containers, actual header depends on function arg. +// Probably should use a special handler, like with std::move. +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) + // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) SYMBOL(abs, std::, ) @@ -242,9 +259,77 @@ SYMBOL(abs, None, ) SYMBOL(abs, None, ) SYMBOL(abs, None, ) -// Only add headers for the generic atomic template. +// Same as abs - ignore variants (std::complex, std::valarray) +SYMBOL(acos, std::, ) +SYMBOL(acos, None, ) +SYMBOL(acos, None, ) +SYMBOL(acosh, std::, ) +SYMBOL(acosh, None, ) +SYMBOL(acosh, None, ) +SYMBOL(asin, std::, ) +SYMBOL(asin, None, ) +SYMBOL(asin, None, ) +SYMBOL(asinh, std::, ) +SYMBOL(asinh, None, ) +SYMBOL(asinh, None, ) +SYMBOL(atan, std::, ) +SYMBOL(atan, None, ) +SYMBOL(atan, None, ) +SYMBOL(atan2, std::, ) +SYMBOL(atan2, None, ) +SYMBOL(atan2, None, ) +SYMBOL(atanh, std::, ) +SYMBOL(atanh, None, ) +SYMBOL(atanh, None, ) +SYMBOL(cos, std::, ) +SYMBOL(cos, None, ) +SYMBOL(cos, None, ) +SYMBOL(cosh, std::, ) +SYMBOL(cosh, None, ) +SYMBOL(cosh, None, ) +SYMBOL(exp, std::, ) +SYMBOL(exp, None, ) +SYMBOL(exp, None, ) +SYMBOL(log, std::, ) +SYMBOL(log, None, ) +SYMBOL(log, None, ) +SYMBOL(log10, std::, ) +SYMBOL(log10, None, ) +SYMBOL(log10, None, ) +SYMBOL(pow, std::, ) +SYMBOL(pow, None, ) +SYMBOL(pow, None, ) +SYMBOL(sin, std::, ) +SYMBOL(sin, None, ) +SYMBOL(sin, None, ) +SYMBOL(sinh, std::, ) +SYMBOL(sinh, None, ) +SYMBOL(sinh, None, ) +SYMBOL(sqrt, std::, ) +SYMBOL(sqrt, None, ) +SYMBOL(sqrt, None, ) +SYMBOL(tan, std::, ) +SYMBOL(tan, None, ) +SYMBOL(tan, None, ) +SYMBOL(tanh, std::, ) +SYMBOL(tanh, None, ) +SYMBOL(tanh, None, ) + +// Only add headers for the generic atomic template and atomic_* template functions. // Ignore variants (std::weak_ptr, std::shared_ptr). SYMBOL(atomic, std::, ) +SYMBOL(atomic_compare_exchange_strong, std::, ) +SYMBOL(atomic_compare_exchange_strong_explicit, std::, ) +SYMBOL(atomic_compare_exchange_weak, std::, ) +SYMBOL(atomic_compare_exchange_weak_explicit, std::, ) +SYMBOL(atomic_exchange, std::, ) +SYMBOL(atomic_exchange_explicit, std::, ) +SYMBOL
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 edited https://github.com/llvm/llvm-project/pull/113612 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 96662cb7f681e7158c05a0190894de70eee03d67 Mon Sep 17 00:00:00 2001 From: Vadim Dudkin Date: Thu, 24 Oct 2024 23:18:52 +0300 Subject: [PATCH 1/2] Update std symbol mapping to v20230810; Move assertion to detect all ungrouped mappings --- .../Inclusions/Stdlib/StandardLibrary.cpp | 8 +- .../Inclusions/Stdlib/StdSpecialSymbolMap.inc | 131 +- .../Inclusions/Stdlib/StdSymbolMap.inc| 171 -- 3 files changed, 200 insertions(+), 110 deletions(-) diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp index 0832bcf66145fa..49e5765af112ff 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp +++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp @@ -115,15 +115,17 @@ static int initialize(Lang Language) { NSLen = 0; } -if (SymIndex >= 0 && -Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { - // Not a new symbol, use the same index. +if (SymIndex > 0) { assert(llvm::none_of(llvm::ArrayRef(Mapping->SymbolNames, SymIndex), [&QName](const SymbolHeaderMapping::SymbolName &S) { return S.qualifiedName() == QName; }) && "The symbol has been added before, make sure entries in the .inc " "file are grouped by symbol name!"); +} +if (SymIndex >= 0 && +Mapping->SymbolNames[SymIndex].qualifiedName() == QName) { + // Not a new symbol, use the same index. } else { // First symbol or new symbol, increment next available index. ++SymIndex; diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc index 0d351d688a3296..13060a0cc1d529 100644 --- a/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc +++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc @@ -233,6 +233,23 @@ SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) SYMBOL(ssize, std::, ) +// Overloads for different containers, actual header depends on function arg. +// Probably should use a special handler, like with std::move. +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) +SYMBOL(erase_if, std::, ) + // Add headers for generic integer-type abs. // Ignore other variants (std::complex, std::valarray, std::intmax_t) SYMBOL(abs, std::, ) @@ -242,9 +259,78 @@ SYMBOL(abs, None, ) SYMBOL(abs, None, ) SYMBOL(abs, None, ) -// Only add headers for the generic atomic template. +// Same as abs - ignore variants (std::complex, std::valarray) +SYMBOL(acos, std::, ) +SYMBOL(acos, None, ) +SYMBOL(acos, None, ) +SYMBOL(acosh, std::, ) +SYMBOL(acosh, None, ) +SYMBOL(acosh, None, ) +SYMBOL(asin, std::, ) +SYMBOL(asin, None, ) +SYMBOL(asin, None, ) +SYMBOL(asinh, std::, ) +SYMBOL(asinh, None, ) +SYMBOL(asinh, None, ) +SYMBOL(atan, std::, ) +SYMBOL(atan, None, ) +SYMBOL(atan, None, ) +SYMBOL(atan2, std::, ) +SYMBOL(atan2, None, ) +SYMBOL(atan2, None, ) +SYMBOL(atanh, std::, ) +SYMBOL(atanh, None, ) +SYMBOL(atanh, None, ) +SYMBOL(cos, std::, ) +SYMBOL(cos, None, ) +SYMBOL(cos, None, ) +SYMBOL(cosh, std::, ) +SYMBOL(cosh, None, ) +SYMBOL(cosh, None, ) +SYMBOL(exp, std::, ) +SYMBOL(exp, None, ) +SYMBOL(exp, None, ) +SYMBOL(log, std::, ) +SYMBOL(log, None, ) +SYMBOL(log, None, ) +SYMBOL(log10, std::, ) +SYMBOL(log10, None, ) +SYMBOL(log10, None, ) +SYMBOL(pow, std::, ) +SYMBOL(pow, None, ) +SYMBOL(pow, None, ) +SYMBOL(sin, std::, ) +SYMBOL(sin, None, ) +SYMBOL(sin, None, ) +SYMBOL(sinh, std::, ) +SYMBOL(sinh, None, ) +SYMBOL(sinh, None, ) +SYMBOL(sqrt, std::, ) +SYMBOL(sqrt, None, ) +SYMBOL(sqrt, None, ) +SYMBOL(tan, std::, ) +SYMBOL(tan, None, ) +SYMBOL(tan, None, ) +SYMBOL(tanh, std::, ) +SYMBOL(tanh, None, ) +SYMBOL(tanh, None, ) + +// Only add headers for the generic atomic template +// and atomic_* template functions. // Ignore variants (std::weak_ptr, std::shared_ptr). SYMBOL(atomic, std::, ) +SYMBOL(atomic_compare_exchange_strong, std::, ) +SYMBOL(atomic_compare_exchange_strong_explicit, std::, ) +SYMBOL(atomic_compare_exchange_weak, std::, ) +SYMBOL(atomic_compare_exchange_weak_explicit, std::, ) +SYMBOL(atomic_exchange, std::, ) +SYMBOL(atomic_exchange_explicit, std::, ) +SYMBOL(atomic_is_lock_free, std::, ) +SYMBOL(atomic_load, std::, ) +SYMBOL(atomic_load_explicit, std::, ) +SYMBOL(atomic_store, std::, ) +SYMBOL(atomic_store_explicit, std::, ) + // atomic_* family symbols. is for C compatibility. SYMBOL(atomic_bool, std::, ) SYMBOL(atomic_bool, None, ) @@ -355,18 +4
[clang] Update std symbols mapping (PR #113612)
https://github.com/vvd170501 updated https://github.com/llvm/llvm-project/pull/113612 >From 489d258577552cde839f0949a1ce24d4b1f72103 Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 00:17:26 +0300 Subject: [PATCH 1/4] Fix variant parsing --- .../include-mapping/cppreference_parser.py| 23 +++ 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index f2ea55384fac80..ff8d16bd792b33 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -7,7 +7,7 @@ # # ======# -from bs4 import BeautifulSoup, NavigableString +from bs4 import BeautifulSoup, NavigableString, Tag import collections import multiprocessing @@ -89,6 +89,23 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): return headers or all_headers +def _ParseSymbolVariant(caption): +if not (isinstance(caption, NavigableString) and "(" in caption): +return None + +if ')' in caption.text: # (locale), (algorithm), etc. +return caption.text.strip(" ()") + +second_part = caption.next_sibling +if isinstance(second_part, Tag) and second_part.name == "code": +# (std::complex), etc. +third_part = second_part.next_sibling +if isinstance(third_part, NavigableString) and third_part.text.startswith(')'): +return second_part.text +return None + + + def _ParseIndexPage(index_page_html): """Parse index page. The index page lists all std symbols and hrefs to their detailed pages @@ -107,9 +124,7 @@ def _ParseIndexPage(index_page_html): # This accidentally accepts begin/end despite the (iterator) caption: the # (since C++11) note is first. They are good symbols, so the bug is unfixed. caption = symbol_href.next_sibling -variant = None -if isinstance(caption, NavigableString) and "(" in caption: -variant = caption.text.strip(" ()") +variant = _ParseSymbolVariant(caption) symbol_tt = symbol_href.find("tt") if symbol_tt: symbols.append( >From 2a4796c7618575bac80817bfe33774860564b8be Mon Sep 17 00:00:00 2001 From: vvd170501 <36827317+vvd170...@users.noreply.github.com> Date: Sat, 26 Oct 2024 06:38:41 +0300 Subject: [PATCH 2/4] Parse symbols with qualified name (not sure if it works in this revision) --- clang/tools/include-mapping/cppreference_parser.py | 13 +++-- 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/tools/include-mapping/cppreference_parser.py b/clang/tools/include-mapping/cppreference_parser.py index ff8d16bd792b33..110c8b1cf2b11f 100644 --- a/clang/tools/include-mapping/cppreference_parser.py +++ b/clang/tools/include-mapping/cppreference_parser.py @@ -40,7 +40,7 @@ def _HasClass(tag, *classes): return False -def _ParseSymbolPage(symbol_page_html, symbol_name): +def _ParseSymbolPage(symbol_page_html, symbol_name, qual_name): """Parse symbol page and retrieve the include header defined in this page. The symbol page provides header for the symbol, specifically in "Defined in header " section. An example: @@ -69,7 +69,7 @@ def _ParseSymbolPage(symbol_page_html, symbol_name): was_decl = True # Symbols are in the first cell. found_symbols = row.find("td").stripped_strings -if not symbol_name in found_symbols: +if not (symbol_name in found_symbols or qual_name in found_symbols): continue headers.update(current_headers) elif _HasClass(row, "t-dsc-header"): @@ -137,9 +137,9 @@ def _ParseIndexPage(index_page_html): return symbols -def _ReadSymbolPage(path, name): +def _ReadSymbolPage(path, name, qual_name): with open(path) as f: -return _ParseSymbolPage(f.read(), name) +return _ParseSymbolPage(f.read(), name, qual_name) def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept): @@ -161,8 +161,9 @@ def _GetSymbols(pool, root_dir, index_page_name, namespace, variants_to_accept): for symbol_name, symbol_page_path, variant in _ParseIndexPage(f.read()): # Variant symbols (e.g. the std::locale version of isalpha) add ambiguity. # FIXME: use these as a fallback rather than ignoring entirely. +qualified_symbol_name = (namespace or "") + symbol_name variants_for_symbol = variants_to_accept.get( -(namespace or "") + symbol_name, () +qualified_symbol_name, () ) if variant and variant not in variants_for_symbol: continue @@ -171,7 +172,7 @@ def _GetSymbols(pool, root_dir