10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "clang/ASTMatchers/ASTMatchers.h"
12#include "clang/Lex/Lexer.h"
23 "has_unique_object_representations",
24 "has_virtual_destructor",
38 "is_copy_constructible",
39 "is_default_constructible",
50 "is_layout_compatible",
51 "is_lvalue_reference",
52 "is_member_function_pointer",
53 "is_member_object_pointer",
56 "is_move_constructible",
57 "is_nothrow_assignable",
58 "is_nothrow_constructible",
59 "is_nothrow_convertible",
60 "is_nothrow_copy_assignable",
61 "is_nothrow_copy_constructible",
62 "is_nothrow_default_constructible",
63 "is_nothrow_destructible",
64 "is_nothrow_invocable",
65 "is_nothrow_invocable_r",
66 "is_nothrow_move_assignable",
67 "is_nothrow_move_constructible",
68 "is_nothrow_swappable",
69 "is_nothrow_swappable_with",
73 "is_pointer_interconvertible_base_of",
76 "is_rvalue_reference",
85 "is_trivially_assignable",
86 "is_trivially_constructible",
87 "is_trivially_copy_assignable",
88 "is_trivially_copy_constructible",
89 "is_trivially_copyable",
90 "is_trivially_default_constructible",
91 "is_trivially_destructible",
92 "is_trivially_move_assignable",
93 "is_trivially_move_constructible",
101 "reference_constructs_from_temporary",
102 "reference_converts_from_temporary",
113 "add_lvalue_reference",
114 "add_rvalue_reference",
120 "remove_all_extents",
135static DeclarationName
getName(
const DependentScopeDeclRefExpr &D) {
136 return D.getDeclName();
139static DeclarationName
getName(
const DeclRefExpr &D) {
140 return D.getDecl()->getDeclName();
144 if (
const auto *TFT =
145 ETL.getNamedTypeLoc().getTypePtr()->getAs<TypedefType>()) {
146 const TypedefNameDecl *
Decl = TFT->getDecl();
147 return Decl->getDeclName().isIdentifier() &&
Decl->getName() ==
"type";
153 return DTL.getTypePtr()->getIdentifier()->getName() ==
"type";
158 DeclRefExpr, DependentScopeDeclRefExpr)) {
159 const IdentifierInfo *Ident =
getName(Node).getAsIdentifierInfo();
160 return Ident && Ident->isStr(
"value");
164 AST_POLYMORPHIC_SUPPORTED_TYPES(ElaboratedTypeLoc,
165 DependentNameTypeLoc)) {
170static constexpr char Bind[] =
"";
173 const ast_matchers::internal::VariadicDynCastAllOfMatcher<
175 DependentScopeDeclRefExpr>
176 dependentScopeDeclRefExpr;
177 const ast_matchers::internal::VariadicDynCastAllOfMatcher<
179 DependentNameTypeLoc>
180 dependentNameTypeLoc;
184 Finder->addMatcher(mapAnyOf(declRefExpr, dependentScopeDeclRefExpr)
189 Finder->addMatcher(mapAnyOf(elaboratedTypeLoc, dependentNameTypeLoc)
196 const llvm::StringSet<> &Set) {
197 return ND->isInStdNamespace() && ND->getDeclName().isIdentifier() &&
198 Set.contains(ND->getName());
202 const llvm::StringSet<> &Set) {
205 const Type *NNST = NNS->getAsType();
208 const auto *TST = NNST->getAs<TemplateSpecializationType>();
211 if (
const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) {
219 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", false)) {}
222 auto EmitValueWarning = [
this, &Result](
const NestedNameSpecifierLoc &QualLoc,
223 SourceLocation EndLoc) {
224 SourceLocation TemplateNameEndLoc;
225 if (
auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
227 TemplateNameEndLoc = Lexer::getLocForEndOfToken(
228 TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
229 Result.Context->getLangOpts());
233 if (EndLoc.isMacroID() || QualLoc.getEndLoc().isMacroID() ||
234 TemplateNameEndLoc.isMacroID()) {
237 diag(QualLoc.getBeginLoc(),
"use c++17 style variable templates");
240 diag(QualLoc.getBeginLoc(),
"use c++17 style variable templates")
241 << FixItHint::CreateInsertion(TemplateNameEndLoc,
"_v")
242 << FixItHint::CreateRemoval({QualLoc.getEndLoc(), EndLoc});
245 auto EmitTypeWarning = [
this, &Result](
const NestedNameSpecifierLoc &QualLoc,
246 SourceLocation EndLoc,
247 SourceLocation TypenameLoc) {
248 SourceLocation TemplateNameEndLoc;
249 if (
auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
251 TemplateNameEndLoc = Lexer::getLocForEndOfToken(
252 TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
253 Result.Context->getLangOpts());
257 if (EndLoc.isMacroID() || QualLoc.getEndLoc().isMacroID() ||
258 TemplateNameEndLoc.isMacroID() || TypenameLoc.isMacroID()) {
261 diag(QualLoc.getBeginLoc(),
"use c++14 style type templates");
264 auto Diag =
diag(QualLoc.getBeginLoc(),
"use c++14 style type templates");
266 if (TypenameLoc.isValid())
267 Diag << FixItHint::CreateRemoval(TypenameLoc);
268 Diag << FixItHint::CreateInsertion(TemplateNameEndLoc,
"_t")
269 << FixItHint::CreateRemoval({QualLoc.getEndLoc(), EndLoc});
272 if (
const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>(
Bind)) {
273 if (!DRE->hasQualifier())
275 if (
const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
276 DRE->getQualifier()->getAsRecordDecl())) {
278 EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc());
283 if (
const auto *ETL = Result.Nodes.getNodeAs<ElaboratedTypeLoc>(
Bind)) {
284 const NestedNameSpecifierLoc QualLoc = ETL->getQualifierLoc();
285 const auto *NNS = QualLoc.getNestedNameSpecifier();
288 if (
const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
289 NNS->getAsRecordDecl())) {
291 EmitTypeWarning(ETL->getQualifierLoc(), ETL->getEndLoc(),
292 ETL->getElaboratedKeywordLoc());
297 if (
const auto *DSDRE =
298 Result.Nodes.getNodeAs<DependentScopeDeclRefExpr>(
Bind)) {
300 EmitValueWarning(DSDRE->getQualifierLoc(), DSDRE->getEndLoc());
304 if (
const auto *DNTL = Result.Nodes.getNodeAs<DependentNameTypeLoc>(
Bind)) {
305 NestedNameSpecifierLoc QualLoc = DNTL->getQualifierLoc();
307 EmitTypeWarning(QualLoc, DNTL->getEndLoc(),
308 DNTL->getElaboratedKeywordLoc());
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
::clang::DynTypedNode Node
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
TypeTraitsCheck(StringRef Name, ClangTidyContext *Context)
AST_POLYMORPHIC_MATCHER(isInAbseilFile, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc, NestedNameSpecifierLoc))
Matches AST nodes that were found within Abseil files.
static constexpr char Bind[]
static DeclarationName getName(const DependentScopeDeclRefExpr &D)
static const llvm::StringSet ValueTraits
static bool checkTemplatedDecl(const NestedNameSpecifier *NNS, const llvm::StringSet<> &Set)
static const llvm::StringSet TypeTraits
static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND, const llvm::StringSet<> &Set)
static bool isNamedType(const ElaboratedTypeLoc &ETL)
llvm::StringMap< ClangTidyValue > OptionMap