- Notifications
You must be signed in to change notification settings - Fork 15.3k
[clang-tidy] introduce a unused local non trival variable check #76101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
| @llvm/pr-subscribers-clang-tidy Author: Tyler Rockwood (rockwotj) ChangesIntroduce a new (off by default) clang tidy check to ensure that variables of a specific type are always used even if -Wunused-variables wouldn't generate a warning. This check has already caught a couple of different bugs on the codebase I work on, where not handling a future means that lifetimes may not be kept alive properly as an async chunk of code may run after a class has been destroyed, etc. I would like to upstream it because I believe there could be other applications of this check that would be useful in different contexts. Full diff: https://github.com/llvm/llvm-project/pull/76101.diff 8 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index d9ec268650c053..374b4fc049c452 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -27,6 +27,7 @@ add_clang_library(clangTidyMiscModule MisleadingBidirectional.cpp MisleadingIdentifier.cpp MisplacedConstCheck.cpp + MustUseCheck.cpp NewDeleteOverloadsCheck.cpp NoRecursionCheck.cpp NonCopyableObjects.cpp diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index d8a88324ee63e0..9f7cf912fbc0d5 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -18,6 +18,7 @@ #include "MisleadingBidirectional.h" #include "MisleadingIdentifier.h" #include "MisplacedConstCheck.h" +#include "MustUseCheck.h" #include "NewDeleteOverloadsCheck.h" #include "NoRecursionCheck.h" #include "NonCopyableObjects.h" @@ -54,6 +55,8 @@ class MiscModule : public ClangTidyModule { CheckFactories.registerCheck<MisleadingIdentifierCheck>( "misc-misleading-identifier"); CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const"); + CheckFactories.registerCheck<MustUseCheck>( + "misc-must-use"); CheckFactories.registerCheck<NewDeleteOverloadsCheck>( "misc-new-delete-overloads"); CheckFactories.registerCheck<NoRecursionCheck>("misc-no-recursion"); diff --git a/clang-tools-extra/clang-tidy/misc/MustUseCheck.cpp b/clang-tools-extra/clang-tidy/misc/MustUseCheck.cpp new file mode 100644 index 00000000000000..31870994e4a9f8 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/MustUseCheck.cpp @@ -0,0 +1,49 @@ +//===--- MustUseCheck.cpp - clang-tidy ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MustUseCheck.h" +#include "../utils/Matchers.h" +#include "../utils/OptionsUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::misc { + +namespace { +AST_MATCHER(VarDecl, isLocalVar) { return Node.isLocalVarDecl(); } +AST_MATCHER(VarDecl, isReferenced) { return Node.isReferenced(); } +} // namespace + +MustUseCheck::MustUseCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + Types(utils::options::parseStringList(Options.get("Types", ""))) {} + +void MustUseCheck::registerMatchers(MatchFinder *Finder) { + if (Types.empty()) { + return; + } + Finder->addMatcher( + varDecl(isLocalVar(), unless(isReferenced()), + hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( + recordDecl(matchers::matchesAnyListedName(Types))))))) + .bind("var"), + this); +} + +void MustUseCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var"); + diag(MatchedDecl->getLocation(), "variable %0 must be used") << MatchedDecl; +} + +void MustUseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "Types", utils::options::serializeStringList(Types)); +} + +} // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/misc/MustUseCheck.h b/clang-tools-extra/clang-tidy/misc/MustUseCheck.h new file mode 100644 index 00000000000000..5ac61295975c69 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/MustUseCheck.h @@ -0,0 +1,40 @@ +//===--- MustUseCheck.h - clang-tidy ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MUSTUSECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MUSTUSECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::misc { + +/// Warns when not using a variable of a specific type within a function. This +/// enforces a stronger check than clang's unused-variable warnings, as in C++ +/// this warning is not fired if the class has a custom destructor, or in +/// templates. This check allows re-enabling unused variable warnings in all +/// situations for specific classes. +/// +/// The check supports this option: +/// - 'Types': a semicolon-separated list of types to ensure must be used. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc/must-use.html +class MustUseCheck : public ClangTidyCheck { +public: + MustUseCheck(StringRef Name, ClangTidyContext *Context); + 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<StringRef> Types; +}; + +} // namespace clang::tidy::misc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MUSTUSECHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 6d91748e4cef18..33b48910f46745 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -187,6 +187,13 @@ New checks points in a coroutine. Such hostile types include scoped-lockable types and types belonging to a configurable denylist. +- New :doc:`misc-must-use + <clang-tidy/checks/misc/must-use>` check. + + Add the ability to strictly enforce variables are used for specific classes, + even with they would not be normally warned using -Wunused-variable due + templates or custom destructors. + - New :doc:`modernize-use-constraints <clang-tidy/checks/modernize/use-constraints>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 31f0e090db1d7d..b68c09842d9686 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -250,6 +250,7 @@ Clang-Tidy Checks :doc:`misc-misleading-bidirectional <misc/misleading-bidirectional>`, :doc:`misc-misleading-identifier <misc/misleading-identifier>`, :doc:`misc-misplaced-const <misc/misplaced-const>`, + :doc:`misc-must-use <misc/must-use>`, :doc:`misc-new-delete-overloads <misc/new-delete-overloads>`, :doc:`misc-no-recursion <misc/no-recursion>`, :doc:`misc-non-copyable-objects <misc/non-copyable-objects>`, diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/must-use.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/must-use.rst new file mode 100644 index 00000000000000..9d5e15f2716c17 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/must-use.rst @@ -0,0 +1,28 @@ +.. title:: clang-tidy - misc-must-use + +misc-must-use +============= + +Allows for strictly enforce variables are used for specific classes, even with +they would not be normally warned using -Wunused-variable due to templates or +custom destructors. + +In the following example, future2 normally would not trigger any unused variable checks, +but using `{key: "misc-must-use.Types", value: "std::future"}` would cause future2 to have +a warning triggered that it is unused. + +.. code-block:: c++ + + std::future<MyObject> future1; + std::future<MyObject> future2; + // ... + MyObject foo = future1.get(); + // future2 is not used. + +Options +------- + +.. option:: Types + + Semicolon-separated list of fully qualified names of classes to check. + By default it is an empty list, which disables the check. diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/must-use.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/must-use.cpp new file mode 100644 index 00000000000000..436d768a0e606a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/must-use.cpp @@ -0,0 +1,48 @@ +// RUN: %check_clang_tidy %s misc-must-use %t -- \ +// RUN: -config="{CheckOptions: [{key: 'misc-must-use.Types', value: '::async::Future'}]}" + +namespace async { +template<typename T> +class Future { +public: + T get() { + return Pending; + } +private: + T Pending; +}; + + +} // namespace async + +// Warning is still emitted if there are type aliases. +namespace a { +template<typename T> +using Future = async::Future<T>; +} // namespace a + +void releaseUnits(); +struct Units { + ~Units() { + releaseUnits(); + } +}; +a::Future<Units> acquireUnits(); + +template<typename T> +T qux(T Generic) { + async::Future<Units> PendingA = acquireUnits(); + auto PendingB = acquireUnits(); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: variable 'PendingB' must be used [misc-must-use] + PendingA.get(); + return Generic; +} + +int bar(int Num) { + a::Future<Units> PendingA = acquireUnits(); + a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: variable 'PendingB' must be used [misc-must-use] + auto Num2 = PendingA.get(); + auto Num3 = qux(Num); + return Num * Num3; +} |
| ✅ With the latest revision this PR passed the C/C++ code formatter. |
f7f9449 to 34feb9d Compare 34feb9d to 07158b0 Compare
PiotrZSL left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simple check, not bad. My main blocker for this check is a name.
07158b0 to 5afeaab Compare clang-tools-extra/docs/clang-tidy/checks/bugprone/unused-local-non-trivial-variable.rst Outdated Show resolved Hide resolved
clang-tools-extra/docs/clang-tidy/checks/bugprone/unused-local-non-trivial-variable.rst Outdated Show resolved Hide resolved
5afeaab to 90d92d0 Compare | This is a very nice check for us to have @rockwotj. |
PiotrZSL left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor tuning needed, some changes to documentation, options, default configuration.
clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp Outdated Show resolved Hide resolved
clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp Outdated Show resolved Hide resolved
clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp Outdated Show resolved Hide resolved
clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp Outdated Show resolved Hide resolved
clang-tools-extra/docs/clang-tidy/checks/bugprone/unused-local-non-trivial-variable.rst Outdated Show resolved Hide resolved
clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp Outdated Show resolved Hide resolved
clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp Outdated Show resolved Hide resolved
90d92d0 to fff68e1 Compare clang-tools-extra/docs/clang-tidy/checks/bugprone/unused-local-non-trivial-variable.rst Outdated Show resolved Hide resolved
f81d2c2 to 6e93bfd Compare 6e93bfd to b65cb64 Compare
PiotrZSL left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks fine.
clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp Outdated Show resolved Hide resolved
clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp Outdated Show resolved Hide resolved
clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp Outdated Show resolved Hide resolved
clang-tools-extra/test/clang-tidy/checkers/bugprone/unused-local-non-trivial-variable.cpp Outdated Show resolved Hide resolved
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
unused-local-non-trivial-variable Also add the ability to match against template specializations, this can be useful if you want all std::future types to be matched, no matter what type is held within the future. Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
b65cb64 to e9ebeab Compare
PiotrZSL left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Unless you want this to be merged by rockwotj@users.noreply.github.com please change your github privacy settings.
| Changed |
…-non-trivial-variable Added -fexceptions switch to test. It were missing in #76101.
…-non-trivial-variable Added -fexceptions switch to test. Added missing Fixes for #76101.
Fixed spelling of some classes in code and in documentation. Fixes for #76101
Introduce a new (off by default) clang tidy check to ensure that variables of a specific type are always used even if -Wunused-variables wouldn't generate a warning.
This check has already caught a couple of different bugs on the codebase I work on, where not handling a future means that lifetimes may not be kept alive properly as an async chunk of code may run after a class has been destroyed, etc.
I would like to upstream it because I believe there could be other applications of this check that would be useful in different contexts.