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