blob: ee4681883964499433d8f6bfc76e3896d822fc38 [file] [log] [blame]
abelkocsis0f4c70d2020-03-21 12:02:00 +01001//===--- 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 {
16namespace tidy {
17namespace bugprone {
18
19void 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(
Nathan James41bbb872020-07-07 14:30:52 +010057 callExpr(callee(functionDecl(hasAnyName("cnd_wait", "cnd_timedwait"))))
abelkocsis0f4c70d2020-03-21 12:02:00 +010058 .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
96void 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