10 #include "clang/ASTMatchers/ASTMatchFinder.h" 11 #include "clang/Lex/Lexer.h" 17 namespace readability {
20 internal::Matcher<Expr> callToGet(
const internal::Matcher<Decl> &OnClass) {
21 return cxxMemberCallExpr(
22 on(expr(anyOf(hasType(OnClass),
24 pointsTo(decl(OnClass).bind(
"ptr_to_ptr"))))))
25 .bind(
"smart_pointer")),
26 unless(callee(memberExpr(hasObjectExpression(cxxThisExpr())))),
29 returns(qualType(pointsTo(type().bind(
"getType")))))))
30 .bind(
"redundant_get");
33 internal::Matcher<Decl> knownSmartptr() {
34 return recordDecl(hasAnyName(
"::std::unique_ptr",
"::std::shared_ptr"));
37 void registerMatchersForGetArrowStart(MatchFinder *Finder,
38 MatchFinder::MatchCallback *
Callback) {
39 const auto QuacksLikeASmartptr = recordDecl(
40 recordDecl().bind(
"duck_typing"),
41 has(cxxMethodDecl(hasName(
"operator->"),
42 returns(qualType(pointsTo(type().bind(
"op->Type")))))),
43 has(cxxMethodDecl(hasName(
"operator*"), returns(qualType(references(
44 type().bind(
"op*Type")))))));
47 const auto Smartptr = anyOf(knownSmartptr(), QuacksLikeASmartptr);
51 memberExpr(expr().bind(
"memberExpr"), isArrow(),
52 hasObjectExpression(ignoringImpCasts(callToGet(Smartptr)))),
57 unaryOperator(hasOperatorName(
"*"), hasUnaryOperand(callToGet(Smartptr))),
61 const auto CallToGetAsBool = ignoringParenImpCasts(callToGet(
62 recordDecl(Smartptr, has(cxxConversionDecl(returns(booleanType()))))));
64 unaryOperator(hasOperatorName(
"!"), hasUnaryOperand(CallToGetAsBool)),
68 Finder->addMatcher(ifStmt(hasCondition(CallToGetAsBool)), Callback);
71 Finder->addMatcher(conditionalOperator(hasCondition(CallToGetAsBool)),
75 void registerMatchersForGetEquals(MatchFinder *Finder,
76 MatchFinder::MatchCallback *Callback) {
84 binaryOperator(anyOf(hasOperatorName(
"=="), hasOperatorName(
"!=")),
85 hasEitherOperand(ignoringImpCasts(
86 anyOf(cxxNullPtrLiteralExpr(), gnuNullExpr(),
87 integerLiteral(equals(0))))),
88 hasEitherOperand(callToGet(knownSmartptr()))),
96 void RedundantSmartptrGetCheck::storeOptions(
98 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
101 void RedundantSmartptrGetCheck::registerMatchers(MatchFinder *Finder) {
104 if (!getLangOpts().CPlusPlus)
107 registerMatchersForGetArrowStart(Finder,
this);
108 registerMatchersForGetEquals(Finder,
this);
112 bool allReturnTypesMatch(
const MatchFinder::MatchResult &
Result) {
113 if (Result.Nodes.getNodeAs<Decl>(
"duck_typing") ==
nullptr)
119 const Type *OpArrowType =
120 Result.Nodes.getNodeAs<
Type>(
"op->Type")->getUnqualifiedDesugaredType();
121 const Type *OpStarType =
122 Result.Nodes.getNodeAs<
Type>(
"op*Type")->getUnqualifiedDesugaredType();
123 const Type *GetType =
124 Result.Nodes.getNodeAs<
Type>(
"getType")->getUnqualifiedDesugaredType();
125 return OpArrowType == OpStarType && OpArrowType == GetType;
129 void RedundantSmartptrGetCheck::check(
const MatchFinder::MatchResult &
Result) {
130 if (!allReturnTypesMatch(Result))
133 bool IsPtrToPtr = Result.Nodes.getNodeAs<Decl>(
"ptr_to_ptr") !=
nullptr;
134 bool IsMemberExpr = Result.Nodes.getNodeAs<Expr>(
"memberExpr") !=
nullptr;
135 const auto *GetCall = Result.Nodes.getNodeAs<Expr>(
"redundant_get");
136 if (GetCall->getBeginLoc().isMacroID() && IgnoreMacros)
139 const auto *Smartptr = Result.Nodes.getNodeAs<Expr>(
"smart_pointer");
141 if (IsPtrToPtr && IsMemberExpr) {
146 StringRef SmartptrText = Lexer::getSourceText(
148 *Result.SourceManager, getLangOpts());
150 std::string Replacement = Twine(IsPtrToPtr ?
"*" :
"", SmartptrText).str();
151 diag(GetCall->getBeginLoc(),
"redundant get() call on smart pointer")
152 << FixItHint::CreateReplacement(GetCall->getSourceRange(), Replacement);
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
std::map< std::string, std::string > OptionMap
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result