1//===--- SpuriouslyWakeUpFunctionsCheck.cpp - clang-tidy ------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "SpuriouslyWakeUpFunctionsCheck.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12
13using namespace clang::ast_matchers;
14
15namespace clang::tidy::bugprone {
16
17void SpuriouslyWakeUpFunctionsCheck::registerMatchers(MatchFinder *Finder) {
18
19 auto HasUniqueLock = hasDescendant(declRefExpr(
20 hasDeclaration(InnerMatcher: varDecl(hasType(InnerMatcher: recordDecl(classTemplateSpecializationDecl(
21 hasName(Name: "::std::unique_lock"),
22 hasTemplateArgument(
23 N: 0, InnerMatcher: templateArgument(refersToType(InnerMatcher: qualType(hasDeclaration(
24 InnerMatcher: cxxRecordDecl(hasName(Name: "::std::mutex"))))))))))))));
25
26 auto HasWaitDescendantCpp = hasDescendant(
27 cxxMemberCallExpr(
28 anyOf(allOf(hasDescendant(memberExpr(hasDeclaration(InnerMatcher: functionDecl(
29 hasName(Name: "::std::condition_variable::wait"),
30 parameterCountIs(N: 1))))),
31 onImplicitObjectArgument(
32 InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasType(InnerMatcher: references(InnerMatcher: recordDecl(
33 hasName(Name: "::std::condition_variable")))))))),
34 HasUniqueLock),
35 allOf(hasDescendant(memberExpr(hasDeclaration(InnerMatcher: functionDecl(
36 hasName(Name: "::std::condition_variable::wait_for"),
37 parameterCountIs(N: 2))))),
38 onImplicitObjectArgument(
39 InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasType(InnerMatcher: references(InnerMatcher: recordDecl(
40 hasName(Name: "::std::condition_variable")))))))),
41 HasUniqueLock),
42 allOf(hasDescendant(memberExpr(hasDeclaration(InnerMatcher: functionDecl(
43 hasName(Name: "::std::condition_variable::wait_until"),
44 parameterCountIs(N: 2))))),
45 onImplicitObjectArgument(
46 InnerMatcher: declRefExpr(to(InnerMatcher: varDecl(hasType(InnerMatcher: references(InnerMatcher: recordDecl(
47 hasName(Name: "::std::condition_variable")))))))),
48 HasUniqueLock)
49
50 ))
51 .bind(ID: "wait"));
52
53 auto HasWaitDescendantC = hasDescendant(
54 callExpr(callee(InnerMatcher: functionDecl(hasAnyName("cnd_wait", "cnd_timedwait"))))
55 .bind(ID: "wait"));
56 if (getLangOpts().CPlusPlus) {
57 // Check for `CON54-CPP`
58 Finder->addMatcher(
59 NodeMatch: ifStmt(HasWaitDescendantCpp,
60 unless(hasDescendant(mapAnyOf(ifStmt, whileStmt, forStmt, doStmt)
61 .with(HasWaitDescendantCpp)))),
62 Action: this);
63 } else {
64 // Check for `CON36-C`
65 Finder->addMatcher(
66 NodeMatch: ifStmt(HasWaitDescendantC,
67 unless(anyOf(
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))))))),
73 Action: this);
74 }
75}
76
77void SpuriouslyWakeUpFunctionsCheck::check(
78 const MatchFinder::MatchResult &Result) {
79 const auto *MatchedWait = Result.Nodes.getNodeAs<CallExpr>(ID: "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");
85}
86} // namespace clang::tidy::bugprone
87

source code of clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp