1 //===--- UnusedReturnValueCheck.cpp - clang-tidy---------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "UnusedReturnValueCheck.h"
10 #include "../utils/Matchers.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 using namespace clang::ast_matchers
;
16 using namespace clang::ast_matchers::internal
;
18 namespace clang::tidy::bugprone
{
22 // Matches functions that are instantiated from a class template member function
23 // matching InnerMatcher. Functions not instantiated from a class template
24 // member function are matched directly with InnerMatcher.
25 AST_MATCHER_P(FunctionDecl
, isInstantiatedFrom
, Matcher
<FunctionDecl
>,
27 FunctionDecl
*InstantiatedFrom
= Node
.getInstantiatedFromMemberFunction();
28 return InnerMatcher
.matches(InstantiatedFrom
? *InstantiatedFrom
: Node
,
33 UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name
,
34 ClangTidyContext
*Context
)
35 : ClangTidyCheck(Name
, Context
),
36 CheckedFunctions(Options
.get("CheckedFunctions",
42 "::std::unique_ptr::release;"
43 "::std::basic_string::empty;"
44 "::std::vector::empty;"
45 "::std::back_inserter;"
54 "::std::map::lower_bound;"
55 "::std::multimap::equal_range;"
56 "::std::multimap::upper_bound;"
60 "::std::setprecision;"
113 "::pthread_getspecific;"
114 "::pthread_mutex_trylock;"
128 CheckedReturnTypes(utils::options::parseStringList(
129 Options
.get("CheckedReturnTypes", "::std::error_code;"
130 "::std::error_condition;"
133 "::boost::system::error_code"))) {}
135 void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
136 Options
.store(Opts
, "CheckedFunctions", CheckedFunctions
);
137 Options
.store(Opts
, "CheckedReturnTypes",
138 utils::options::serializeStringList(CheckedReturnTypes
));
141 void UnusedReturnValueCheck::registerMatchers(MatchFinder
*Finder
) {
142 auto FunVec
= utils::options::parseStringList(CheckedFunctions
);
144 auto MatchedCallExpr
= expr(ignoringImplicit(ignoringParenImpCasts(
145 callExpr(callee(functionDecl(
146 // Don't match void overloads of checked functions.
147 unless(returns(voidType())),
148 anyOf(isInstantiatedFrom(hasAnyName(FunVec
)),
149 returns(hasCanonicalType(hasDeclaration(
150 namedDecl(matchers::matchesAnyListedName(
151 CheckedReturnTypes
)))))))))
154 auto UnusedInCompoundStmt
=
155 compoundStmt(forEach(MatchedCallExpr
),
156 // The checker can't currently differentiate between the
157 // return statement and other statements inside GNU statement
158 // expressions, so disable the checker inside them to avoid
160 unless(hasParent(stmtExpr())));
161 auto UnusedInIfStmt
=
162 ifStmt(eachOf(hasThen(MatchedCallExpr
), hasElse(MatchedCallExpr
)));
163 auto UnusedInWhileStmt
= whileStmt(hasBody(MatchedCallExpr
));
164 auto UnusedInDoStmt
= doStmt(hasBody(MatchedCallExpr
));
165 auto UnusedInForStmt
=
166 forStmt(eachOf(hasLoopInit(MatchedCallExpr
),
167 hasIncrement(MatchedCallExpr
), hasBody(MatchedCallExpr
)));
168 auto UnusedInRangeForStmt
= cxxForRangeStmt(hasBody(MatchedCallExpr
));
169 auto UnusedInCaseStmt
= switchCase(forEach(MatchedCallExpr
));
172 stmt(anyOf(UnusedInCompoundStmt
, UnusedInIfStmt
, UnusedInWhileStmt
,
173 UnusedInDoStmt
, UnusedInForStmt
, UnusedInRangeForStmt
,
178 void UnusedReturnValueCheck::check(const MatchFinder::MatchResult
&Result
) {
179 if (const auto *Matched
= Result
.Nodes
.getNodeAs
<CallExpr
>("match")) {
180 diag(Matched
->getBeginLoc(),
181 "the value returned by this function should be used")
182 << Matched
->getSourceRange();
183 diag(Matched
->getBeginLoc(),
184 "cast the expression to void to silence this warning",
185 DiagnosticIDs::Note
);
189 } // namespace clang::tidy::bugprone