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