//===--- UnusedLocalNonTrivialVariableCheck.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 "UnusedLocalNonTrivialVariableCheck.h" #include "../utils/Matchers.h" #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" using namespace clang::ast_matchers; using namespace clang::tidy::matchers; namespace clang::tidy::bugprone { namespace { static constexpr StringRef DefaultIncludeTypeRegex = "::std::.*mutex;::std::future;::std::basic_string;::std::basic_regex;" "::std::basic_istringstream;::std::basic_stringstream;::std::bitset;" "::std::filesystem::path"; AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); } AST_MATCHER(VarDecl, isReferenced) { return Node.isReferenced(); } AST_MATCHER(Type, isReferenceType) { return Node.isReferenceType(); } AST_MATCHER(QualType, isTrivial) { return Node.isTrivialType(Finder->getASTContext()) || Node.isTriviallyCopyableType(Finder->getASTContext()); } } // namespace UnusedLocalNonTrivialVariableCheck::UnusedLocalNonTrivialVariableCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), IncludeTypes(utils::options::parseStringList( Options.get("IncludeTypes", DefaultIncludeTypeRegex))), ExcludeTypes( utils::options::parseStringList(Options.get("ExcludeTypes", ""))) {} void UnusedLocalNonTrivialVariableCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IncludeTypes", utils::options::serializeStringList(IncludeTypes)); Options.store(Opts, "ExcludeTypes", utils::options::serializeStringList(ExcludeTypes)); } void UnusedLocalNonTrivialVariableCheck::registerMatchers(MatchFinder *Finder) { if (IncludeTypes.empty()) return; Finder->addMatcher( varDecl(isLocalVarDecl(), unless(isReferenced()), unless(isExceptionVariable()), hasLocalStorage(), isDefinition(), unless(hasType(isReferenceType())), unless(hasType(isTrivial())), hasType(hasUnqualifiedDesugaredType( anyOf(recordType(hasDeclaration(namedDecl( matchesAnyListedName(IncludeTypes), unless(matchesAnyListedName(ExcludeTypes))))), templateSpecializationType(hasDeclaration(namedDecl( matchesAnyListedName(IncludeTypes), unless(matchesAnyListedName(ExcludeTypes))))))))) .bind("var"), this); } void UnusedLocalNonTrivialVariableCheck::check( const MatchFinder::MatchResult &Result) { const auto *MatchedDecl = Result.Nodes.getNodeAs("var"); diag(MatchedDecl->getLocation(), "unused local variable %0 of type %1") << MatchedDecl << MatchedDecl->getType(); } bool UnusedLocalNonTrivialVariableCheck::isLanguageVersionSupported( const LangOptions &LangOpts) const { return LangOpts.CPlusPlus; } std::optional UnusedLocalNonTrivialVariableCheck::getCheckTraversalKind() const { return TK_IgnoreUnlessSpelledInSource; } } // namespace clang::tidy::bugprone