[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 : 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 : 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 : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config ) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config ) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto : *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/clang-tools-extra/clangd/ConfigYAML.cpp +++
[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 : 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 : 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 : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config ) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config ) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto : *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/clang-tools-extra/clangd/ConfigYAML.cpp +++
[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)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 82c6eeed08b1c8267f6e92d594c910fe57a9775e f222e44f5586297ddd61ac0efff4a7115a766c53 -- clang-tools-extra/clangd/Config.h clang-tools-extra/clangd/ConfigCompile.cpp clang-tools-extra/clangd/ConfigFragment.h clang-tools-extra/clangd/ConfigYAML.cpp clang-tools-extra/clangd/IncludeCleaner.cpp clang-tools-extra/clangd/IncludeCleaner.h clang-tools-extra/clangd/ParsedAST.cpp clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp clang-tools-extra/clangd/unittests/ConfigYAMLTests.cpp clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp `` View the diff from clang-format here. ``diff diff --git a/clang-tools-extra/clangd/ConfigCompile.cpp b/clang-tools-extra/clangd/ConfigCompile.cpp index 570f3cfc3c..f74c870adf 100644 --- a/clang-tools-extra/clangd/ConfigCompile.cpp +++ b/clang-tools-extra/clangd/ConfigCompile.cpp @@ -584,7 +584,8 @@ struct FragmentCompiler { diag(Warning, llvm::formatv("Invalid regular expression '{0}': {1}", *HeaderPattern, RegexError) - .str(), HeaderPattern.Range); + .str(), + HeaderPattern.Range); continue; } Filters->push_back(std::move(CompiledRegex)); `` 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)
github-actions[bot] wrote: ⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo. Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account. See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information. 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 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 : 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 : 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 : *Filters) -if (Regex.match(Path)) - return true; - return false; -}; -Out.Apply.push_back([Filter](const Params &, Config ) { - C.Diagnostics.Includes.IgnoreHeader.emplace_back(Filter); +Out.Apply.push_back([Filters = std::move(Filters), + AnalyzeSystemHeaders](const Params &, Config ) { + if (Filters) { +auto Filter = [Filters](llvm::StringRef Path) { + for (auto : *Filters) +if (Regex.match(Path)) + return true; + return false; +}; +