clang-tools 23.0.0git
UseVectorUtilsCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include "../utils/LexerUtils.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang::ast_matchers;
15
17
19 ClangTidyContext *Context)
20 : ClangTidyCheck(Name, Context),
21 Inserter(utils::IncludeSorter::IS_LLVM, areDiagsSelfContained()) {}
22
23void UseVectorUtilsCheck::registerPPCallbacks(const SourceManager &SM,
24 Preprocessor *PP,
25 Preprocessor *ModuleExpanderPP) {
26 Inserter.registerPreprocessor(PP);
27}
28
29void UseVectorUtilsCheck::registerMatchers(MatchFinder *Finder) {
30 // Match `llvm::to_vector(llvm::map_range(X, F))` or
31 // `llvm::to_vector(llvm::make_filter_range(X, Pred))`.
32 Finder->addMatcher(
33 callExpr(callee(functionDecl(hasName("::llvm::to_vector"))),
34 hasArgument(0, callExpr(callee(functionDecl(hasAnyName(
35 "::llvm::map_range",
36 "::llvm::make_filter_range"))),
37 argumentCountIs(2))
38 .bind("inner_call")),
39 argumentCountIs(1))
40 .bind("outer_call"),
41 this);
42}
43
44void UseVectorUtilsCheck::check(const MatchFinder::MatchResult &Result) {
45 const auto *OuterCall = Result.Nodes.getNodeAs<CallExpr>("outer_call");
46 assert(OuterCall);
47
48 const auto *InnerCall = Result.Nodes.getNodeAs<CallExpr>("inner_call");
49 assert(InnerCall);
50
51 const auto *OuterCallee =
52 cast<DeclRefExpr>(OuterCall->getCallee()->IgnoreImplicit());
53
54 const StringRef InnerFuncName =
55 cast<NamedDecl>(InnerCall->getCalleeDecl())->getName();
56
57 // Determine the replacement function name (unqualified).
58 const llvm::SmallDenseMap<StringRef, StringRef, 2>
59 InnerFuncNameToReplacementFuncName = {
60 {"map_range", "map_to_vector"},
61 {"make_filter_range", "filter_to_vector"},
62 };
63 const StringRef ReplacementFuncName =
64 InnerFuncNameToReplacementFuncName.lookup(InnerFuncName);
65 assert(!ReplacementFuncName.empty() && "Unhandled function?");
66
67 auto Diag = diag(OuterCall->getBeginLoc(), "use '%0'") << ReplacementFuncName;
68
69 // Replace the outer function name (preserving qualifier and template args),
70 // and then remove the inner call's callee and opening paren and closing
71 // paren. Example:
72 // ```
73 // llvm::to_vector<4>(llvm::map_range(X, F))
74 // ^replace~^ ^----remove-----^ ^
75 // remove
76 // ```
77 const SourceManager &SM = *Result.SourceManager;
78 const std::optional<Token> InnerLParen =
80 InnerCall->getCallee()->getEndLoc(), SM, getLangOpts());
81 if (!InnerLParen || InnerLParen->isNot(tok::l_paren))
82 return; // Unexpected token, possibly a macro?
83
84 Diag << FixItHint::CreateReplacement(
85 OuterCallee->getNameInfo().getSourceRange(), ReplacementFuncName)
86 << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
87 InnerCall->getBeginLoc(), InnerLParen->getEndLoc()))
88 << FixItHint::CreateRemoval(InnerCall->getRParenLoc());
89
90 // Add include for `SmallVectorExtras.h` if needed.
91 if (auto IncludeFixit = Inserter.createIncludeInsertion(
92 SM.getFileID(OuterCall->getBeginLoc()),
93 "llvm/ADT/SmallVectorExtras.h"))
94 Diag << *IncludeFixit;
95}
96
97} // namespace clang::tidy::llvm_check
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
UseVectorUtilsCheck(StringRef Name, ClangTidyContext *Context)
std::optional< Token > findNextTokenSkippingComments(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
Definition LexerUtils.h:101