clang 18.0.0git
CallDescription.cpp
Go to the documentation of this file.
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
16#include "clang/AST/Decl.h"
19#include "llvm/ADT/ArrayRef.h"
20#include <iterator>
21#include <optional>
22
23using namespace llvm;
24using namespace clang;
25
26using MaybeCount = std::optional<unsigned>;
27
28// A constructor helper.
30 MaybeCount RequiredParams) {
31 if (RequiredParams)
32 return RequiredParams;
33 if (RequiredArgs)
34 return RequiredArgs;
35 return std::nullopt;
36}
37
39 ArrayRef<StringRef> QualifiedName,
40 MaybeCount RequiredArgs /*= None*/,
41 MaybeCount RequiredParams /*= None*/)
42 : RequiredArgs(RequiredArgs),
43 RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
44 Flags(Flags) {
45 assert(!QualifiedName.empty());
46 this->QualifiedName.reserve(QualifiedName.size());
47 llvm::transform(QualifiedName, std::back_inserter(this->QualifiedName),
48 [](StringRef From) { return From.str(); });
49}
50
51/// Construct a CallDescription with default flags.
53 MaybeCount RequiredArgs /*= None*/,
54 MaybeCount RequiredParams /*= None*/)
55 : CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
56
58 // FIXME: Add ObjC Message support.
59 if (Call.getKind() == CE_ObjCMessage)
60 return false;
61
62 const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
63 if (!FD)
64 return false;
65
66 return matchesImpl(FD, Call.getNumArgs(), Call.parameters().size());
67}
68
70 const auto *FD = dyn_cast_or_null<FunctionDecl>(CE.getCalleeDecl());
71 if (!FD)
72 return false;
73
74 return matchesImpl(FD, CE.getNumArgs(), FD->param_size());
75}
76
77bool ento::CallDescription::matchesImpl(const FunctionDecl *Callee,
78 size_t ArgCount,
79 size_t ParamCount) const {
80 const auto *FD = Callee;
81 if (!FD)
82 return false;
83
84 if (Flags & CDF_MaybeBuiltin) {
85 return CheckerContext::isCLibraryFunction(FD, getFunctionName()) &&
86 (!RequiredArgs || *RequiredArgs <= ArgCount) &&
87 (!RequiredParams || *RequiredParams <= ParamCount);
88 }
89
90 if (!II) {
91 II = &FD->getASTContext().Idents.get(getFunctionName());
92 }
93
94 const auto MatchNameOnly = [](const CallDescription &CD,
95 const NamedDecl *ND) -> bool {
96 DeclarationName Name = ND->getDeclName();
97 if (const auto *II = Name.getAsIdentifierInfo())
98 return II == *CD.II; // Fast case.
99
100 // Fallback to the slow stringification and comparison for:
101 // C++ overloaded operators, constructors, destructors, etc.
102 // FIXME This comparison is way SLOWER than comparing pointers.
103 // At some point in the future, we should compare FunctionDecl pointers.
104 return Name.getAsString() == CD.getFunctionName();
105 };
106
107 const auto ExactMatchArgAndParamCounts =
108 [](size_t ArgCount, size_t ParamCount,
109 const CallDescription &CD) -> bool {
110 const bool ArgsMatch = !CD.RequiredArgs || *CD.RequiredArgs == ArgCount;
111 const bool ParamsMatch =
112 !CD.RequiredParams || *CD.RequiredParams == ParamCount;
113 return ArgsMatch && ParamsMatch;
114 };
115
116 const auto MatchQualifiedNameParts = [](const CallDescription &CD,
117 const Decl *D) -> bool {
118 const auto FindNextNamespaceOrRecord =
119 [](const DeclContext *Ctx) -> const DeclContext * {
120 while (Ctx && !isa<NamespaceDecl, RecordDecl>(Ctx))
121 Ctx = Ctx->getParent();
122 return Ctx;
123 };
124
125 auto QualifierPartsIt = CD.begin_qualified_name_parts();
126 const auto QualifierPartsEndIt = CD.end_qualified_name_parts();
127
128 // Match namespace and record names. Skip unrelated names if they don't
129 // match.
130 const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
131 for (; Ctx && QualifierPartsIt != QualifierPartsEndIt;
132 Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
133 // If not matched just continue and try matching for the next one.
134 if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
135 continue;
136 ++QualifierPartsIt;
137 }
138
139 // We matched if we consumed all expected qualifier segments.
140 return QualifierPartsIt == QualifierPartsEndIt;
141 };
142
143 // Let's start matching...
144 if (!ExactMatchArgAndParamCounts(ArgCount, ParamCount, *this))
145 return false;
146
147 if (!MatchNameOnly(*this, FD))
148 return false;
149
150 if (!hasQualifiedNameParts())
151 return true;
152
153 return MatchQualifiedNameParts(*this, FD);
154}
155
157 std::initializer_list<CallDescription> &&List) {
158 Impl.LinearMap.reserve(List.size());
159 for (const CallDescription &CD : List)
160 Impl.LinearMap.push_back({CD, /*unused*/ true});
161}
162
164 return static_cast<bool>(Impl.lookup(Call));
165}
166
168 return static_cast<bool>(Impl.lookupAsWritten(CE));
169}
static MaybeCount readRequiredParams(MaybeCount RequiredArgs, MaybeCount RequiredParams)
std::optional< unsigned > MaybeCount
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2847
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3025
Decl * getCalleeDecl()
Definition: Expr.h:3011
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1435
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:2065
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
The name of a declaration.
Represents a function declaration or definition.
Definition: Decl.h:1957
This represents a decl that may have a name.
Definition: Decl.h:248
CallDescriptionSet(std::initializer_list< CallDescription > &&List)
bool containsAsWritten(const CallExpr &CE) const
When available, always prefer lookup with a CallEvent! This function exists only when that is not ava...
bool contains(const CallEvent &Call) const
This class represents a description of a function call using the number of arguments and the name of ...
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
bool matchesAsWritten(const CallExpr &CE) const
Returns true if the CallExpr is a call to a function that matches the CallDescription.
CallDescription(CallDescriptionFlags Flags, ArrayRef< StringRef > QualifiedName, MaybeCount RequiredArgs=std::nullopt, MaybeCount RequiredParams=std::nullopt)
Constructs a CallDescription object.
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:152
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the callee is an externally-visible function in the top-level namespace,...
@ CDF_MaybeBuiltin
Describes a C standard function that is sometimes implemented as a macro that expands to a compiler b...
@ CE_ObjCMessage
Definition: CallEvent.h:76
@ List
New-expression has a C++11 list-initializer.
YAML serialization mapping.
Definition: Dominators.h:30