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"))),
134 AllowCastToVoid(Options
.get("AllowCastToVoid", false)) {}
136 void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
137 Options
.store(Opts
, "CheckedFunctions", CheckedFunctions
);
138 Options
.store(Opts
, "CheckedReturnTypes",
139 utils::options::serializeStringList(CheckedReturnTypes
));
140 Options
.store(Opts
, "AllowCastToVoid", AllowCastToVoid
);
143 void UnusedReturnValueCheck::registerMatchers(MatchFinder
*Finder
) {
144 auto FunVec
= utils::options::parseStringList(CheckedFunctions
);
146 auto MatchedDirectCallExpr
=
147 expr(callExpr(callee(functionDecl(
148 // Don't match void overloads of checked functions.
149 unless(returns(voidType())),
150 anyOf(isInstantiatedFrom(hasAnyName(FunVec
)),
151 returns(hasCanonicalType(hasDeclaration(
152 namedDecl(matchers::matchesAnyListedName(
153 CheckedReturnTypes
)))))))))
156 auto CheckCastToVoid
=
157 AllowCastToVoid
? castExpr(unless(hasCastKind(CK_ToVoid
))) : castExpr();
158 auto MatchedCallExpr
= expr(
159 anyOf(MatchedDirectCallExpr
,
160 explicitCastExpr(unless(cxxFunctionalCastExpr()), CheckCastToVoid
,
161 hasSourceExpression(MatchedDirectCallExpr
))));
163 auto UnusedInCompoundStmt
=
164 compoundStmt(forEach(MatchedCallExpr
),
165 // The checker can't currently differentiate between the
166 // return statement and other statements inside GNU statement
167 // expressions, so disable the checker inside them to avoid
169 unless(hasParent(stmtExpr())));
170 auto UnusedInIfStmt
=
171 ifStmt(eachOf(hasThen(MatchedCallExpr
), hasElse(MatchedCallExpr
)));
172 auto UnusedInWhileStmt
= whileStmt(hasBody(MatchedCallExpr
));
173 auto UnusedInDoStmt
= doStmt(hasBody(MatchedCallExpr
));
174 auto UnusedInForStmt
=
175 forStmt(eachOf(hasLoopInit(MatchedCallExpr
),
176 hasIncrement(MatchedCallExpr
), hasBody(MatchedCallExpr
)));
177 auto UnusedInRangeForStmt
= cxxForRangeStmt(hasBody(MatchedCallExpr
));
178 auto UnusedInCaseStmt
= switchCase(forEach(MatchedCallExpr
));
181 stmt(anyOf(UnusedInCompoundStmt
, UnusedInIfStmt
, UnusedInWhileStmt
,
182 UnusedInDoStmt
, UnusedInForStmt
, UnusedInRangeForStmt
,
187 void UnusedReturnValueCheck::check(const MatchFinder::MatchResult
&Result
) {
188 if (const auto *Matched
= Result
.Nodes
.getNodeAs
<CallExpr
>("match")) {
189 diag(Matched
->getBeginLoc(),
190 "the value returned by this function should not be disregarded; "
191 "neglecting it may lead to errors")
192 << Matched
->getSourceRange();
194 if (!AllowCastToVoid
)
197 diag(Matched
->getBeginLoc(),
198 "cast the expression to void to silence this warning",
199 DiagnosticIDs::Note
);
203 } // namespace clang::tidy::bugprone