blob: ec060f8637838538f4d90faef08ec4da9c834325 [file] [log] [blame]
Aaron Ballmancc740ae2018-05-16 20:12:06 +00001//===--- SimplifySubscriptExprCheck.cpp - clang-tidy-----------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Aaron Ballmancc740ae2018-05-16 20:12:06 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "SimplifySubscriptExprCheck.h"
10#include "../utils/OptionsUtils.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
16namespace clang {
17namespace tidy {
18namespace readability {
19
20static const char kDefaultTypes[] =
21 "::std::basic_string;::std::basic_string_view;::std::vector;::std::array";
22
23SimplifySubscriptExprCheck::SimplifySubscriptExprCheck(
24 StringRef Name, ClangTidyContext *Context)
25 : ClangTidyCheck(Name, Context), Types(utils::options::parseStringList(
26 Options.get("Types", kDefaultTypes))) {
27}
28
29void SimplifySubscriptExprCheck::registerMatchers(MatchFinder *Finder) {
30 if (!getLangOpts().CPlusPlus)
31 return;
32
33 const auto TypesMatcher = hasUnqualifiedDesugaredType(
34 recordType(hasDeclaration(cxxRecordDecl(hasAnyName(
35 llvm::SmallVector<StringRef, 8>(Types.begin(), Types.end()))))));
36
37 Finder->addMatcher(
38 arraySubscriptExpr(hasBase(ignoringParenImpCasts(
39 cxxMemberCallExpr(
40 has(memberExpr().bind("member")),
41 on(hasType(qualType(
42 unless(anyOf(substTemplateTypeParmType(),
43 hasDescendant(substTemplateTypeParmType()))),
44 anyOf(TypesMatcher, pointerType(pointee(TypesMatcher)))))),
45 callee(namedDecl(hasName("data"))))
46 .bind("call")))),
47 this);
48}
49
50void SimplifySubscriptExprCheck::check(const MatchFinder::MatchResult &Result) {
51 const auto *Call = Result.Nodes.getNodeAs<CXXMemberCallExpr>("call");
52 if (Result.Context->getSourceManager().isMacroBodyExpansion(
53 Call->getExprLoc()))
54 return;
55
56 const auto *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
57 auto DiagBuilder =
58 diag(Member->getMemberLoc(),
59 "accessing an element of the container does not require a call to "
60 "'data()'; did you mean to use 'operator[]'?");
61 if (Member->isArrow())
Stephen Kelly43465bf2018-08-09 22:42:26 +000062 DiagBuilder << FixItHint::CreateInsertion(Member->getBeginLoc(), "(*")
Aaron Ballmancc740ae2018-05-16 20:12:06 +000063 << FixItHint::CreateInsertion(Member->getOperatorLoc(), ")");
64 DiagBuilder << FixItHint::CreateRemoval(
Stephen Kellyc09197e2018-08-09 22:43:02 +000065 {Member->getOperatorLoc(), Call->getEndLoc()});
Aaron Ballmancc740ae2018-05-16 20:12:06 +000066}
67
68void SimplifySubscriptExprCheck::storeOptions(
69 ClangTidyOptions::OptionMap &Opts) {
70 Options.store(Opts, "Types", utils::options::serializeStringList(Types));
71}
72
73} // namespace readability
74} // namespace tidy
75} // namespace clang