84 lines · cpp
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-exception6//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 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 74void SpuriouslyWakeUpFunctionsCheck::check(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::bugprone84