10#include "../utils/Matchers.h"
11#include "../utils/OptionsUtils.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/ASTMatchers/ASTMatchers.h"
15#include "clang/Basic/OperatorKinds.h"
18using namespace clang::ast_matchers::internal;
27AST_MATCHER_P(FunctionDecl, isInstantiatedFrom, Matcher<FunctionDecl>,
29 FunctionDecl *InstantiatedFrom =
Node.getInstantiatedFromMemberFunction();
30 return InnerMatcher.matches(InstantiatedFrom ? *InstantiatedFrom : Node,
34constexpr std::initializer_list<OverloadedOperatorKind>
35 AssignmentOverloadedOperatorKinds = {
36 OO_Equal, OO_PlusEqual, OO_MinusEqual, OO_StarEqual,
37 OO_SlashEqual, OO_PercentEqual, OO_CaretEqual, OO_AmpEqual,
38 OO_PipeEqual, OO_LessLessEqual, OO_GreaterGreaterEqual, OO_PlusPlus,
41AST_MATCHER(FunctionDecl, isAssignmentOverloadedOperator) {
42 return llvm::is_contained(AssignmentOverloadedOperatorKinds,
43 Node.getOverloadedOperator());
48 ClangTidyContext *Context)
49 : ClangTidyCheck(
Name, Context),
51 Options.get(
"CheckedFunctions",
"^::std::async$;"
56 "^::std::unique_ptr::release$;"
57 "^::std::basic_string::empty$;"
58 "^::std::vector::empty$;"
59 "^::std::back_inserter$;"
64 "^::std::lower_bound$;"
66 "^::std::map::count$;"
68 "^::std::map::lower_bound$;"
69 "^::std::multimap::equal_range$;"
70 "^::std::multimap::upper_bound$;"
71 "^::std::set::count$;"
74 "^::std::setprecision$;"
76 "^::std::upper_bound$;"
77 "^::std::vector::at$;"
127 "^::pthread_getspecific$;"
128 "^::pthread_mutex_trylock$;"
143 Options.get(
"CheckedReturnTypes",
"^::std::error_code$;"
144 "^::std::error_condition$;"
147 "^::boost::system::error_code$"))),
148 AllowCastToVoid(Options.get(
"AllowCastToVoid", false)) {}
150UnusedReturnValueCheck::UnusedReturnValueCheck(
151 llvm::StringRef
Name, ClangTidyContext *Context,
152 std::vector<StringRef> CheckedFunctions)
153 : UnusedReturnValueCheck(
Name, Context, std::move(CheckedFunctions), {},
156UnusedReturnValueCheck::UnusedReturnValueCheck(
157 llvm::StringRef
Name, ClangTidyContext *Context,
158 std::vector<StringRef> CheckedFunctions,
159 std::vector<StringRef> CheckedReturnTypes,
bool AllowCastToVoid)
160 : ClangTidyCheck(
Name, Context),
161 CheckedFunctions(std::move(CheckedFunctions)),
162 CheckedReturnTypes(std::move(CheckedReturnTypes)),
163 AllowCastToVoid(AllowCastToVoid) {}
166 Options.store(Opts,
"CheckedFunctions",
167 utils::options::serializeStringList(CheckedFunctions));
168 Options.store(Opts,
"CheckedReturnTypes",
169 utils::options::serializeStringList(CheckedReturnTypes));
170 Options.store(Opts,
"AllowCastToVoid", AllowCastToVoid);
173void UnusedReturnValueCheck::registerMatchers(MatchFinder *Finder) {
174 auto MatchedDirectCallExpr =
175 expr(callExpr(callee(functionDecl(
177 unless(isAssignmentOverloadedOperator()),
179 unless(returns(voidType())),
180 anyOf(isInstantiatedFrom(matchers::matchesAnyListedName(
182 returns(hasCanonicalType(hasDeclaration(
183 namedDecl(matchers::matchesAnyListedName(
184 CheckedReturnTypes)))))))))
187 auto CheckCastToVoid =
188 AllowCastToVoid ? castExpr(unless(hasCastKind(CK_ToVoid))) : castExpr();
189 auto MatchedCallExpr = expr(
190 anyOf(MatchedDirectCallExpr,
191 explicitCastExpr(unless(cxxFunctionalCastExpr()), CheckCastToVoid,
192 hasSourceExpression(MatchedDirectCallExpr))));
194 auto UnusedInCompoundStmt =
195 compoundStmt(forEach(MatchedCallExpr),
200 unless(hasParent(stmtExpr())));
201 auto UnusedInIfStmt =
202 ifStmt(eachOf(hasThen(MatchedCallExpr), hasElse(MatchedCallExpr)));
203 auto UnusedInWhileStmt = whileStmt(hasBody(MatchedCallExpr));
204 auto UnusedInDoStmt = doStmt(hasBody(MatchedCallExpr));
205 auto UnusedInForStmt =
206 forStmt(eachOf(hasLoopInit(MatchedCallExpr),
207 hasIncrement(MatchedCallExpr), hasBody(MatchedCallExpr)));
208 auto UnusedInRangeForStmt = cxxForRangeStmt(hasBody(MatchedCallExpr));
209 auto UnusedInCaseStmt = switchCase(forEach(MatchedCallExpr));
212 stmt(anyOf(UnusedInCompoundStmt, UnusedInIfStmt, UnusedInWhileStmt,
213 UnusedInDoStmt, UnusedInForStmt, UnusedInRangeForStmt,
218void UnusedReturnValueCheck::check(
const MatchFinder::MatchResult &Result) {
219 if (
const auto *Matched = Result.Nodes.getNodeAs<CallExpr>(
"match")) {
220 diag(Matched->getBeginLoc(),
221 "the value returned by this function should not be disregarded; "
222 "neglecting it may lead to errors")
223 << Matched->getSourceRange();
225 if (!AllowCastToVoid)
228 diag(Matched->getBeginLoc(),
229 "cast the expression to void to silence this warning",
230 DiagnosticIDs::Note);
llvm::SmallString< 256U > Name
CodeCompletionBuilder Builder
::clang::DynTypedNode Node
UnusedReturnValueCheck(StringRef Name, ClangTidyContext *Context)
AST_MATCHER_P(FunctionDecl, parameterCountGE, unsigned, N)
Matches functions that have at least the specified amount of parameters.
AST_MATCHER(clang::VarDecl, hasConstantDeclaration)
std::vector< StringRef > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
llvm::StringMap< ClangTidyValue > OptionMap