SpuriouslyWakeUpFunctionsCheck.cpp 3.8 KB

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