CallDescription.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //===- CallDescription.cpp - function/method call matching --*- C++ -*-===//
  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. /// \file This file defines a generic mechanism for matching for function and
  10. /// method calls of C, C++, and Objective-C languages. Instances of these
  11. /// classes are frequently used together with the CallEvent classes.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
  15. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  16. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  17. #include "llvm/ADT/ArrayRef.h"
  18. #include "llvm/ADT/Optional.h"
  19. #include <iterator>
  20. using namespace llvm;
  21. using namespace clang;
  22. using MaybeCount = Optional<unsigned>;
  23. // A constructor helper.
  24. static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
  25. MaybeCount RequiredParams) {
  26. if (RequiredParams)
  27. return RequiredParams;
  28. if (RequiredArgs)
  29. return RequiredArgs;
  30. return None;
  31. }
  32. ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
  33. ArrayRef<const char *> QualifiedName,
  34. MaybeCount RequiredArgs /*= None*/,
  35. MaybeCount RequiredParams /*= None*/)
  36. : RequiredArgs(RequiredArgs),
  37. RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
  38. Flags(Flags) {
  39. assert(!QualifiedName.empty());
  40. this->QualifiedName.reserve(QualifiedName.size());
  41. llvm::copy(QualifiedName, std::back_inserter(this->QualifiedName));
  42. }
  43. /// Construct a CallDescription with default flags.
  44. ento::CallDescription::CallDescription(ArrayRef<const char *> QualifiedName,
  45. MaybeCount RequiredArgs /*= None*/,
  46. MaybeCount RequiredParams /*= None*/)
  47. : CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
  48. bool ento::CallDescription::matches(const CallEvent &Call) const {
  49. // FIXME: Add ObjC Message support.
  50. if (Call.getKind() == CE_ObjCMessage)
  51. return false;
  52. const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  53. if (!FD)
  54. return false;
  55. if (Flags & CDF_MaybeBuiltin) {
  56. return CheckerContext::isCLibraryFunction(FD, getFunctionName()) &&
  57. (!RequiredArgs || *RequiredArgs <= Call.getNumArgs()) &&
  58. (!RequiredParams || *RequiredParams <= Call.parameters().size());
  59. }
  60. if (!II.hasValue()) {
  61. II = &Call.getState()->getStateManager().getContext().Idents.get(
  62. getFunctionName());
  63. }
  64. const auto MatchNameOnly = [](const CallDescription &CD,
  65. const NamedDecl *ND) -> bool {
  66. DeclarationName Name = ND->getDeclName();
  67. if (const auto *II = Name.getAsIdentifierInfo())
  68. return II == CD.II.getValue(); // Fast case.
  69. // Fallback to the slow stringification and comparison for:
  70. // C++ overloaded operators, constructors, destructors, etc.
  71. // FIXME This comparison is way SLOWER than comparing pointers.
  72. // At some point in the future, we should compare FunctionDecl pointers.
  73. return Name.getAsString() == CD.getFunctionName();
  74. };
  75. const auto ExactMatchArgAndParamCounts =
  76. [](const CallEvent &Call, const CallDescription &CD) -> bool {
  77. const bool ArgsMatch =
  78. !CD.RequiredArgs || *CD.RequiredArgs == Call.getNumArgs();
  79. const bool ParamsMatch =
  80. !CD.RequiredParams || *CD.RequiredParams == Call.parameters().size();
  81. return ArgsMatch && ParamsMatch;
  82. };
  83. const auto MatchQualifiedNameParts = [](const CallDescription &CD,
  84. const Decl *D) -> bool {
  85. const auto FindNextNamespaceOrRecord =
  86. [](const DeclContext *Ctx) -> const DeclContext * {
  87. while (Ctx && !isa<NamespaceDecl, RecordDecl>(Ctx))
  88. Ctx = Ctx->getParent();
  89. return Ctx;
  90. };
  91. auto QualifierPartsIt = CD.begin_qualified_name_parts();
  92. const auto QualifierPartsEndIt = CD.end_qualified_name_parts();
  93. // Match namespace and record names. Skip unrelated names if they don't
  94. // match.
  95. const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
  96. for (; Ctx && QualifierPartsIt != QualifierPartsEndIt;
  97. Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
  98. // If not matched just continue and try matching for the next one.
  99. if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
  100. continue;
  101. ++QualifierPartsIt;
  102. }
  103. // We matched if we consumed all expected qualifier segments.
  104. return QualifierPartsIt == QualifierPartsEndIt;
  105. };
  106. // Let's start matching...
  107. if (!ExactMatchArgAndParamCounts(Call, *this))
  108. return false;
  109. if (!MatchNameOnly(*this, FD))
  110. return false;
  111. if (!hasQualifiedNameParts())
  112. return true;
  113. return MatchQualifiedNameParts(*this, FD);
  114. }
  115. ento::CallDescriptionSet::CallDescriptionSet(
  116. std::initializer_list<CallDescription> &&List) {
  117. Impl.LinearMap.reserve(List.size());
  118. for (const CallDescription &CD : List)
  119. Impl.LinearMap.push_back({CD, /*unused*/ true});
  120. }
  121. bool ento::CallDescriptionSet::contains(const CallEvent &Call) const {
  122. return static_cast<bool>(Impl.lookup(Call));
  123. }