clang-tools  14.0.0git
ContainerDataPointerCheck.cpp
Go to the documentation of this file.
1 //===--- ContainerDataPointerCheck.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 
10 
11 #include "clang/Lex/Lexer.h"
12 #include "llvm/ADT/StringRef.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace readability {
19 
20 constexpr llvm::StringLiteral ContainerExprName = "container-expr";
21 constexpr llvm::StringLiteral DerefContainerExprName = "deref-container-expr";
22 constexpr llvm::StringLiteral AddrOfContainerExprName =
23  "addr-of-container-expr";
24 constexpr llvm::StringLiteral AddressOfName = "address-of";
25 
26 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
27  ClangTidyContext *Context)
28  : ClangTidyCheck(Name, Context) {}
29 
31  const auto Record =
32  cxxRecordDecl(
33  isSameOrDerivedFrom(
34  namedDecl(
35  has(cxxMethodDecl(isPublic(), hasName("data")).bind("data")))
36  .bind("container")))
37  .bind("record");
38 
39  const auto NonTemplateContainerType =
40  qualType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(Record))));
41  const auto TemplateContainerType =
42  qualType(hasUnqualifiedDesugaredType(templateSpecializationType(
43  hasDeclaration(classTemplateDecl(has(Record))))));
44 
45  const auto Container =
46  qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
47 
48  const auto ContainerExpr = anyOf(
49  unaryOperator(
50  hasOperatorName("*"),
51  hasUnaryOperand(
52  expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
53  .bind(ContainerExprName),
54  unaryOperator(hasOperatorName("&"),
55  hasUnaryOperand(expr(anyOf(hasType(Container),
56  hasType(references(Container))))
58  .bind(ContainerExprName),
59  expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
60  hasType(references(Container))))
61  .bind(ContainerExprName));
62 
63  const auto Zero = integerLiteral(equals(0));
64 
65  const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
66 
67  Finder->addMatcher(
68  unaryOperator(
69  unless(isExpansionInSystemHeader()), hasOperatorName("&"),
70  hasUnaryOperand(expr(
71  anyOf(cxxOperatorCallExpr(SubscriptOperator, argumentCountIs(2),
72  hasArgument(0, ContainerExpr),
73  hasArgument(1, Zero)),
74  cxxMemberCallExpr(SubscriptOperator, on(ContainerExpr),
75  argumentCountIs(1), hasArgument(0, Zero)),
76  arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero))))))
77  .bind(AddressOfName),
78  this);
79 }
80 
81 void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) {
82  const auto *UO = Result.Nodes.getNodeAs<UnaryOperator>(AddressOfName);
83  const auto *CE = Result.Nodes.getNodeAs<Expr>(ContainerExprName);
84  const auto *DCE = Result.Nodes.getNodeAs<Expr>(DerefContainerExprName);
85  const auto *ACE = Result.Nodes.getNodeAs<Expr>(AddrOfContainerExprName);
86 
87  if (!UO || !CE)
88  return;
89 
90  if (DCE && !CE->getType()->isPointerType())
91  CE = DCE;
92  else if (ACE)
93  CE = ACE;
94 
95  SourceRange SrcRange = CE->getSourceRange();
96 
97  std::string ReplacementText{
98  Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange),
99  *Result.SourceManager, getLangOpts())};
100 
101  if (!isa<DeclRefExpr, ArraySubscriptExpr, CXXOperatorCallExpr, CallExpr>(CE))
102  ReplacementText = "(" + ReplacementText + ")";
103 
104  if (CE->getType()->isPointerType())
105  ReplacementText += "->data()";
106  else
107  ReplacementText += ".data()";
108 
109  FixItHint Hint =
110  FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText);
111  diag(UO->getBeginLoc(),
112  "'data' should be used for accessing the data pointer instead of taking "
113  "the address of the 0-th element")
114  << Hint;
115 }
116 } // namespace readability
117 } // namespace tidy
118 } // namespace clang
clang::tidy::readability::DerefContainerExprName
constexpr llvm::StringLiteral DerefContainerExprName
Definition: ContainerDataPointerCheck.cpp:21
clang::tidy::cppcoreguidelines::getSourceText
static std::string getSourceText(const CXXDestructorDecl &Destructor)
Definition: VirtualClassDestructorCheck.cpp:112
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:54
clang::tidy::readability::ContainerExprName
constexpr llvm::StringLiteral ContainerExprName
Definition: ContainerDataPointerCheck.cpp:20
clang::tidy::ClangTidyCheck::getLangOpts
const LangOptions & getLangOpts() const
Returns the language options from the context.
Definition: ClangTidyCheck.h:420
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::readability::ContainerDataPointerCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: ContainerDataPointerCheck.cpp:30
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:72
clang::tidy::readability::AddrOfContainerExprName
constexpr llvm::StringLiteral AddrOfContainerExprName
Definition: ContainerDataPointerCheck.cpp:22
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidyCheck.cpp:25
ContainerDataPointerCheck.h
clang::doc::serialize::isPublic
static bool isPublic(const clang::AccessSpecifier AS, const clang::Linkage Link)
Definition: Serialize.cpp:223
CE
CaptureExpr CE
Definition: AvoidBindCheck.cpp:67
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::doc::Record
llvm::SmallVector< uint64_t, 1024 > Record
Definition: BitcodeReader.cpp:18
clang::tidy::readability::ContainerDataPointerCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: ContainerDataPointerCheck.cpp:81
clang::tidy::readability::AddressOfName
constexpr llvm::StringLiteral AddressOfName
Definition: ContainerDataPointerCheck.cpp:24