1 | //===--- PreferRegisterOverUnsignedCheck.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 "PreferRegisterOverUnsignedCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | |
13 | using namespace clang::ast_matchers; |
14 | |
15 | namespace clang::tidy::llvm_check { |
16 | |
17 | void PreferRegisterOverUnsignedCheck::registerMatchers(MatchFinder *Finder) { |
18 | auto RegisterClassMatch = hasType( |
19 | InnerMatcher: cxxRecordDecl(hasName(Name: "::llvm::Register")).bind(ID: "registerClassDecl")); |
20 | |
21 | Finder->addMatcher( |
22 | NodeMatch: traverse(TK: TK_AsIs, |
23 | InnerMatcher: valueDecl(hasType(InnerMatcher: qualType(isUnsignedInteger()).bind(ID: "varType")), |
24 | varDecl(hasInitializer(InnerMatcher: exprWithCleanups( |
25 | has(implicitCastExpr(has(cxxMemberCallExpr( |
26 | on(InnerMatcher: RegisterClassMatch), |
27 | has(memberExpr(hasDeclaration( |
28 | InnerMatcher: cxxConversionDecl())))))))))) |
29 | .bind(ID: "var"))), |
30 | Action: this); |
31 | } |
32 | |
33 | void PreferRegisterOverUnsignedCheck::check( |
34 | const MatchFinder::MatchResult &Result) { |
35 | const auto *VarType = Result.Nodes.getNodeAs<QualType>(ID: "varType"); |
36 | const auto *UserVarDecl = Result.Nodes.getNodeAs<VarDecl>(ID: "var"); |
37 | |
38 | bool NeedsQualification = true; |
39 | const DeclContext *Context = UserVarDecl->getDeclContext(); |
40 | while (Context) { |
41 | if (const auto *Namespace = dyn_cast<NamespaceDecl>(Context)) |
42 | if (isa<TranslationUnitDecl>(Namespace->getDeclContext()) && |
43 | Namespace->getName() == "llvm") |
44 | NeedsQualification = false; |
45 | for (const auto *UsingDirective : Context->using_directives()) { |
46 | const NamespaceDecl *Namespace = UsingDirective->getNominatedNamespace(); |
47 | if (isa<TranslationUnitDecl>(Namespace->getDeclContext()) && |
48 | Namespace->getName() == "llvm") |
49 | NeedsQualification = false; |
50 | } |
51 | Context = Context->getParent(); |
52 | } |
53 | diag(UserVarDecl->getLocation(), |
54 | "variable %0 declared as %1; use '%select{|llvm::}2Register' instead") |
55 | << UserVarDecl << *VarType << NeedsQualification |
56 | << FixItHint::CreateReplacement( |
57 | UserVarDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange(), |
58 | NeedsQualification ? "llvm::Register": "Register"); |
59 | } |
60 | |
61 | } // namespace clang::tidy::llvm_check |
62 |