xref: /llvm-project/clang-tools-extra/clang-tidy/bugprone/UnusedLocalNonTrivialVariableCheck.cpp (revision e41f96ad251a403d02919755d9fe2b473a46966a)
1 //===--- UnusedLocalNonTrivialVariableCheck.cpp - clang-tidy --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "UnusedLocalNonTrivialVariableCheck.h"
10 #include "../utils/Matchers.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/ASTTypeTraits.h"
14 #include "clang/AST/Type.h"
15 #include "clang/ASTMatchers/ASTMatchFinder.h"
16 #include "clang/ASTMatchers/ASTMatchers.h"
17 #include "clang/ASTMatchers/ASTMatchersMacros.h"
18 #include "clang/Basic/LangOptions.h"
19 
20 using namespace clang::ast_matchers;
21 using namespace clang::tidy::matchers;
22 
23 namespace clang::tidy::bugprone {
24 
25 namespace {
26 static constexpr StringRef DefaultIncludeTypeRegex =
27     "::std::.*mutex;::std::future;::std::basic_string;::std::basic_regex;"
28     "::std::basic_istringstream;::std::basic_stringstream;::std::bitset;"
29     "::std::filesystem::path";
30 
31 AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); }
32 AST_MATCHER(VarDecl, isReferenced) { return Node.isReferenced(); }
33 AST_MATCHER(VarDecl, explicitMarkUnused) {
34   // Implementations should not emit a warning that a name-independent
35   // declaration is used or unused.
36   LangOptions const &LangOpts = Finder->getASTContext().getLangOpts();
37   return Node.hasAttr<UnusedAttr>() ||
38          (LangOpts.CPlusPlus26 && Node.isPlaceholderVar(LangOpts));
39 }
40 AST_MATCHER(Type, isReferenceType) { return Node.isReferenceType(); }
41 AST_MATCHER(QualType, isTrivial) {
42   return Node.isTrivialType(Finder->getASTContext()) ||
43          Node.isTriviallyCopyableType(Finder->getASTContext());
44 }
45 } // namespace
46 
47 UnusedLocalNonTrivialVariableCheck::UnusedLocalNonTrivialVariableCheck(
48     StringRef Name, ClangTidyContext *Context)
49     : ClangTidyCheck(Name, Context),
50       IncludeTypes(utils::options::parseStringList(
51           Options.get("IncludeTypes", DefaultIncludeTypeRegex))),
52       ExcludeTypes(
53           utils::options::parseStringList(Options.get("ExcludeTypes", ""))) {}
54 
55 void UnusedLocalNonTrivialVariableCheck::storeOptions(
56     ClangTidyOptions::OptionMap &Opts) {
57   Options.store(Opts, "IncludeTypes",
58                 utils::options::serializeStringList(IncludeTypes));
59   Options.store(Opts, "ExcludeTypes",
60                 utils::options::serializeStringList(ExcludeTypes));
61 }
62 
63 void UnusedLocalNonTrivialVariableCheck::registerMatchers(MatchFinder *Finder) {
64   if (IncludeTypes.empty())
65     return;
66 
67   Finder->addMatcher(
68       varDecl(isLocalVarDecl(), unless(isReferenced()),
69               unless(isExceptionVariable()), hasLocalStorage(), isDefinition(),
70               unless(hasType(isReferenceType())), unless(hasType(isTrivial())),
71               unless(explicitMarkUnused()),
72               hasType(hasUnqualifiedDesugaredType(
73                   anyOf(recordType(hasDeclaration(namedDecl(
74                             matchesAnyListedName(IncludeTypes),
75                             unless(matchesAnyListedName(ExcludeTypes))))),
76                         templateSpecializationType(hasDeclaration(namedDecl(
77                             matchesAnyListedName(IncludeTypes),
78                             unless(matchesAnyListedName(ExcludeTypes)))))))))
79           .bind("var"),
80       this);
81 }
82 
83 void UnusedLocalNonTrivialVariableCheck::check(
84     const MatchFinder::MatchResult &Result) {
85   const auto *MatchedDecl = Result.Nodes.getNodeAs<VarDecl>("var");
86   diag(MatchedDecl->getLocation(), "unused local variable %0 of type %1")
87       << MatchedDecl << MatchedDecl->getType();
88 }
89 
90 bool UnusedLocalNonTrivialVariableCheck::isLanguageVersionSupported(
91     const LangOptions &LangOpts) const {
92   return LangOpts.CPlusPlus;
93 }
94 
95 std::optional<TraversalKind>
96 UnusedLocalNonTrivialVariableCheck::getCheckTraversalKind() const {
97   return TK_IgnoreUnlessSpelledInSource;
98 }
99 
100 } // namespace clang::tidy::bugprone
101