[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clang-tidy / readability / ContainerDataPointerCheck.cpp
bloba05e228520c9ef1b05aaa55087d7baa7f7564cd8
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 //===----------------------------------------------------------------------===//
9 #include "ContainerDataPointerCheck.h"
11 #include "../utils/Matchers.h"
12 #include "../utils/OptionsUtils.h"
13 #include "clang/Lex/Lexer.h"
14 #include "llvm/ADT/StringRef.h"
16 using namespace clang::ast_matchers;
18 namespace clang::tidy::readability {
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";
26 void ContainerDataPointerCheck::storeOptions(
27 ClangTidyOptions::OptionMap &Opts) {
28 Options.store(Opts, "IgnoredContainers",
29 utils::options::serializeStringList(IgnoredContainers));
32 ContainerDataPointerCheck::ContainerDataPointerCheck(StringRef Name,
33 ClangTidyContext *Context)
34 : ClangTidyCheck(Name, Context),
35 IgnoredContainers(utils::options::parseStringList(
36 Options.get("IgnoredContainers", ""))) {}
38 void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) {
39 const auto Record =
40 cxxRecordDecl(
41 unless(matchers::matchesAnyListedName(IgnoredContainers)),
42 isSameOrDerivedFrom(
43 namedDecl(
44 has(cxxMethodDecl(isPublic(), hasName("data")).bind("data")))
45 .bind("container")))
46 .bind("record");
48 const auto NonTemplateContainerType =
49 qualType(hasUnqualifiedDesugaredType(recordType(hasDeclaration(Record))));
50 const auto TemplateContainerType =
51 qualType(hasUnqualifiedDesugaredType(templateSpecializationType(
52 hasDeclaration(classTemplateDecl(has(Record))))));
54 const auto Container =
55 qualType(anyOf(NonTemplateContainerType, TemplateContainerType));
57 const auto ContainerExpr = anyOf(
58 unaryOperator(
59 hasOperatorName("*"),
60 hasUnaryOperand(
61 expr(hasType(pointsTo(Container))).bind(DerefContainerExprName)))
62 .bind(ContainerExprName),
63 unaryOperator(hasOperatorName("&"),
64 hasUnaryOperand(expr(anyOf(hasType(Container),
65 hasType(references(Container))))
66 .bind(AddrOfContainerExprName)))
67 .bind(ContainerExprName),
68 expr(anyOf(hasType(Container), hasType(pointsTo(Container)),
69 hasType(references(Container))))
70 .bind(ContainerExprName));
72 const auto Zero = integerLiteral(equals(0));
74 const auto SubscriptOperator = callee(cxxMethodDecl(hasName("operator[]")));
76 Finder->addMatcher(
77 unaryOperator(
78 unless(isExpansionInSystemHeader()), hasOperatorName("&"),
79 hasUnaryOperand(expr(
80 anyOf(cxxOperatorCallExpr(SubscriptOperator, argumentCountIs(2),
81 hasArgument(0, ContainerExpr),
82 hasArgument(1, Zero)),
83 cxxMemberCallExpr(SubscriptOperator, on(ContainerExpr),
84 argumentCountIs(1), hasArgument(0, Zero)),
85 arraySubscriptExpr(hasLHS(ContainerExpr), hasRHS(Zero))))))
86 .bind(AddressOfName),
87 this);
90 void ContainerDataPointerCheck::check(const MatchFinder::MatchResult &Result) {
91 const auto *UO = Result.Nodes.getNodeAs<UnaryOperator>(AddressOfName);
92 const auto *CE = Result.Nodes.getNodeAs<Expr>(ContainerExprName);
93 const auto *DCE = Result.Nodes.getNodeAs<Expr>(DerefContainerExprName);
94 const auto *ACE = Result.Nodes.getNodeAs<Expr>(AddrOfContainerExprName);
96 if (!UO || !CE)
97 return;
99 if (DCE && !CE->getType()->isPointerType())
100 CE = DCE;
101 else if (ACE)
102 CE = ACE;
104 SourceRange SrcRange = CE->getSourceRange();
106 std::string ReplacementText{
107 Lexer::getSourceText(CharSourceRange::getTokenRange(SrcRange),
108 *Result.SourceManager, getLangOpts())};
110 if (!isa<DeclRefExpr, ArraySubscriptExpr, CXXOperatorCallExpr, CallExpr,
111 MemberExpr>(CE))
112 ReplacementText = "(" + ReplacementText + ")";
114 if (CE->getType()->isPointerType())
115 ReplacementText += "->data()";
116 else
117 ReplacementText += ".data()";
119 FixItHint Hint =
120 FixItHint::CreateReplacement(UO->getSourceRange(), ReplacementText);
121 diag(UO->getBeginLoc(),
122 "'data' should be used for accessing the data pointer instead of taking "
123 "the address of the 0-th element")
124 << Hint;
126 } // namespace clang::tidy::readability