blob: f4c306e9c428e33d74b082883030aa493b7bf66c [file] [log] [blame]
Aaron Ballmancc740ae2018-05-16 20:12:06 +00001//===--- 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
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace tidy {
19namespace readability {
20
21static const char kDefaultTypes[] =
22 "::std::basic_string;::std::basic_string_view;::std::vector;::std::array";
23
24SimplifySubscriptExprCheck::SimplifySubscriptExprCheck(
25 StringRef Name, ClangTidyContext *Context)
26 : ClangTidyCheck(Name, Context), Types(utils::options::parseStringList(
27 Options.get("Types", kDefaultTypes))) {
28}
29
30void 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
51void 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())
Stephen Kelly43465bf2018-08-09 22:42:26 +000063 DiagBuilder << FixItHint::CreateInsertion(Member->getBeginLoc(), "(*")
Aaron Ballmancc740ae2018-05-16 20:12:06 +000064 << FixItHint::CreateInsertion(Member->getOperatorLoc(), ")");
65 DiagBuilder << FixItHint::CreateRemoval(
Stephen Kellyc09197e2018-08-09 22:43:02 +000066 {Member->getOperatorLoc(), Call->getEndLoc()});
Aaron Ballmancc740ae2018-05-16 20:12:06 +000067}
68
69void 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