101 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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 20using namespace clang::ast_matchers;21using namespace clang::tidy::matchers;22 23namespace clang::tidy::bugprone {24 25namespace {26static 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 31AST_MATCHER(VarDecl, isLocalVarDecl) { return Node.isLocalVarDecl(); }32AST_MATCHER(VarDecl, isReferenced) { return Node.isReferenced(); }33AST_MATCHER(VarDecl, explicitMarkUnused) {34 // Implementations should not emit a warning that a name-independent35 // declaration is used or unused.36 const LangOptions &LangOpts = Finder->getASTContext().getLangOpts();37 return Node.hasAttr<UnusedAttr>() ||38 (LangOpts.CPlusPlus26 && Node.isPlaceholderVar(LangOpts));39}40AST_MATCHER(Type, isReferenceType) { return Node.isReferenceType(); }41AST_MATCHER(QualType, isTrivial) {42 return Node.isTrivialType(Finder->getASTContext()) ||43 Node.isTriviallyCopyableType(Finder->getASTContext());44}45} // namespace46 47UnusedLocalNonTrivialVariableCheck::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 55void 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 63void 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 83void 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 90bool UnusedLocalNonTrivialVariableCheck::isLanguageVersionSupported(91 const LangOptions &LangOpts) const {92 return LangOpts.CPlusPlus;93}94 95std::optional<TraversalKind>96UnusedLocalNonTrivialVariableCheck::getCheckTraversalKind() const {97 return TK_IgnoreUnlessSpelledInSource;98}99 100} // namespace clang::tidy::bugprone101