1 //===--- SpuriouslyWakeUpFunctionsCheck.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 "SpuriouslyWakeUpFunctionsCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::bugprone
{
17 void SpuriouslyWakeUpFunctionsCheck::registerMatchers(MatchFinder
*Finder
) {
19 auto HasUniqueLock
= hasDescendant(declRefExpr(
20 hasDeclaration(varDecl(hasType(recordDecl(classTemplateSpecializationDecl(
21 hasName("::std::unique_lock"),
23 0, templateArgument(refersToType(qualType(hasDeclaration(
24 cxxRecordDecl(hasName("::std::mutex"))))))))))))));
26 auto HasWaitDescendantCpp
= hasDescendant(
28 anyOf(allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
29 hasName("::std::condition_variable::wait"),
30 parameterCountIs(1))))),
31 onImplicitObjectArgument(
32 declRefExpr(to(varDecl(hasType(references(recordDecl(
33 hasName("::std::condition_variable")))))))),
35 allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
36 hasName("::std::condition_variable::wait_for"),
37 parameterCountIs(2))))),
38 onImplicitObjectArgument(
39 declRefExpr(to(varDecl(hasType(references(recordDecl(
40 hasName("::std::condition_variable")))))))),
42 allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
43 hasName("::std::condition_variable::wait_until"),
44 parameterCountIs(2))))),
45 onImplicitObjectArgument(
46 declRefExpr(to(varDecl(hasType(references(recordDecl(
47 hasName("::std::condition_variable")))))))),
53 auto HasWaitDescendantC
= hasDescendant(
54 callExpr(callee(functionDecl(hasAnyName("cnd_wait", "cnd_timedwait"))))
56 if (getLangOpts().CPlusPlus
) {
57 // Check for `CON54-CPP`
59 ifStmt(HasWaitDescendantCpp
,
60 unless(hasDescendant(mapAnyOf(ifStmt
, whileStmt
, forStmt
, doStmt
)
61 .with(HasWaitDescendantCpp
)))),
64 // Check for `CON36-C`
66 ifStmt(HasWaitDescendantC
,
68 hasDescendant(mapAnyOf(ifStmt
, whileStmt
, forStmt
, doStmt
)
69 .with(HasWaitDescendantC
)),
70 hasParent(mapAnyOf(whileStmt
, forStmt
, doStmt
)),
71 hasParent(compoundStmt(
72 hasParent(mapAnyOf(whileStmt
, forStmt
, doStmt
))))))),
77 void SpuriouslyWakeUpFunctionsCheck::check(
78 const MatchFinder::MatchResult
&Result
) {
79 const auto *MatchedWait
= Result
.Nodes
.getNodeAs
<CallExpr
>("wait");
80 StringRef WaitName
= MatchedWait
->getDirectCallee()->getName();
81 diag(MatchedWait
->getExprLoc(),
82 "'%0' should be placed inside a while statement %select{|or used with a "
83 "conditional parameter}1")
84 << WaitName
<< (WaitName
!= "cnd_wait" && WaitName
!= "cnd_timedwait");
86 } // namespace clang::tidy::bugprone