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 9 #include "ContainerDataPointerCheck.h" 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 30 void ContainerDataPointerCheck::registerMatchers(MatchFinder *Finder) { 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)))) 57 .bind(AddrOfContainerExprName))) 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 119