1 //===--- SimplifySubscriptExprCheck.cpp - clang-tidy-----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "SimplifySubscriptExprCheck.h" 11 #include "../utils/OptionsUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace readability { 20 21 static const char kDefaultTypes[] = 22 "::std::basic_string;::std::basic_string_view;::std::vector;::std::array"; 23 24 SimplifySubscriptExprCheck::SimplifySubscriptExprCheck( 25 StringRef Name, ClangTidyContext *Context) 26 : ClangTidyCheck(Name, Context), Types(utils::options::parseStringList( 27 Options.get("Types", kDefaultTypes))) { 28 } 29 30 void SimplifySubscriptExprCheck::registerMatchers(MatchFinder *Finder) { 31 if (!getLangOpts().CPlusPlus) 32 return; 33 34 const auto TypesMatcher = hasUnqualifiedDesugaredType( 35 recordType(hasDeclaration(cxxRecordDecl(hasAnyName( 36 llvm::SmallVector<StringRef, 8>(Types.begin(), Types.end())))))); 37 38 Finder->addMatcher( 39 arraySubscriptExpr(hasBase(ignoringParenImpCasts( 40 cxxMemberCallExpr( 41 has(memberExpr().bind("member")), 42 on(hasType(qualType( 43 unless(anyOf(substTemplateTypeParmType(), 44 hasDescendant(substTemplateTypeParmType()))), 45 anyOf(TypesMatcher, pointerType(pointee(TypesMatcher)))))), 46 callee(namedDecl(hasName("data")))) 47 .bind("call")))), 48 this); 49 } 50 51 void SimplifySubscriptExprCheck::check(const MatchFinder::MatchResult &Result) { 52 const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call"); 53 if (Result.Context->getSourceManager().isMacroBodyExpansion( 54 Call->getExprLoc())) 55 return; 56 57 const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member"); 58 auto DiagBuilder = 59 diag(Member->getMemberLoc(), 60 "accessing an element of the container does not require a call to " 61 "'data()'; did you mean to use 'operator[]'?"); 62 if (Member->isArrow()) 63 DiagBuilder << FixItHint::CreateInsertion(Member->getLocStart(), "(*") 64 << FixItHint::CreateInsertion(Member->getOperatorLoc(), ")"); 65 DiagBuilder << FixItHint::CreateRemoval( 66 {Member->getOperatorLoc(), Call->getLocEnd()}); 67 } 68 69 void SimplifySubscriptExprCheck::storeOptions( 70 ClangTidyOptions::OptionMap &Opts) { 71 Options.store(Opts, "Types", utils::options::serializeStringList(Types)); 72 } 73 74 } // namespace readability 75 } // namespace tidy 76 } // namespace clang 77