Skip to content

Commit 3ec7b91

Browse files
author
Balazs Benics
committed
[analyzer][NFC] Refactor CallEvent::isCalled()
Refactor the code to make it more readable. It will set up further changes, and improvements to this code in subsequent patches. This is a non-functional change. Reviewed By: martong Differential Revision: https://reviews.llvm.org/D111534
1 parent 5644d15 commit 3ec7b91

File tree

2 files changed

+68
-35
lines changed

2 files changed

+68
-35
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,9 +1237,7 @@ enum CallDescriptionFlags : int {
12371237
/// arguments and the name of the function.
12381238
class CallDescription {
12391239
friend CallEvent;
1240-
1241-
mutable IdentifierInfo *II = nullptr;
1242-
mutable bool IsLookupDone = false;
1240+
mutable Optional<const IdentifierInfo *> II;
12431241
// The list of the qualified names used to identify the specified CallEvent,
12441242
// e.g. "{a, b}" represent the qualified names, like "a::b".
12451243
std::vector<const char *> QualifiedName;
@@ -1273,7 +1271,9 @@ class CallDescription {
12731271
Optional<size_t> RequiredParams = None)
12741272
: QualifiedName(QualifiedName), RequiredArgs(RequiredArgs),
12751273
RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
1276-
Flags(Flags) {}
1274+
Flags(Flags) {
1275+
assert(!QualifiedName.empty());
1276+
}
12771277

12781278
/// Construct a CallDescription with default flags.
12791279
CallDescription(ArrayRef<const char *> QualifiedName,
@@ -1283,6 +1283,17 @@ class CallDescription {
12831283

12841284
/// Get the name of the function that this object matches.
12851285
StringRef getFunctionName() const { return QualifiedName.back(); }
1286+
1287+
/// Get the qualified name parts in reversed order.
1288+
/// E.g. { "std", "vector", "data" } -> "vector", "std"
1289+
auto begin_qualified_name_parts() const {
1290+
return std::next(QualifiedName.rbegin());
1291+
}
1292+
auto end_qualified_name_parts() const { return QualifiedName.rend(); }
1293+
1294+
/// It's false, if and only if we expect a single identifier, such as
1295+
/// `getenv`. It's true for `std::swap`, or `my::detail::container::data`.
1296+
bool hasQualifiedNameParts() const { return QualifiedName.size() > 1; }
12861297
};
12871298

12881299
/// An immutable map from CallDescriptions to arbitrary data. Provides a unified

clang/lib/StaticAnalyzer/Core/CallEvent.cpp

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,7 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
307307
if (getKind() == CE_ObjCMessage)
308308
return false;
309309

310-
const IdentifierInfo *II = getCalleeIdentifier();
311-
if (!II)
312-
return false;
313-
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
310+
const auto *FD = dyn_cast_or_null<FunctionDecl>(getDecl());
314311
if (!FD)
315312
return false;
316313

@@ -320,44 +317,69 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
320317
(!CD.RequiredParams || CD.RequiredParams <= parameters().size());
321318
}
322319

323-
if (!CD.IsLookupDone) {
324-
CD.IsLookupDone = true;
320+
if (!CD.II.hasValue()) {
325321
CD.II = &getState()->getStateManager().getContext().Idents.get(
326322
CD.getFunctionName());
327323
}
328324

329-
if (II != CD.II)
330-
return false;
325+
const auto MatchNameOnly = [](const CallDescription &CD,
326+
const NamedDecl *ND) -> bool {
327+
DeclarationName Name = ND->getDeclName();
328+
if (const auto *II = Name.getAsIdentifierInfo())
329+
return II == CD.II.getValue(); // Fast case.
331330

332-
// If CallDescription provides prefix names, use them to improve matching
333-
// accuracy.
334-
if (CD.QualifiedName.size() > 1 && FD) {
335-
const DeclContext *Ctx = FD->getDeclContext();
336-
// See if we'll be able to match them all.
337-
size_t NumUnmatched = CD.QualifiedName.size() - 1;
338-
for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
339-
if (NumUnmatched == 0)
340-
break;
331+
// Simply report mismatch for:
332+
// C++ overloaded operators, constructors, destructors, etc.
333+
return false;
334+
};
341335

342-
if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
343-
if (ND->getName() == CD.QualifiedName[NumUnmatched - 1])
344-
--NumUnmatched;
345-
continue;
346-
}
336+
const auto ExactMatchArgAndParamCounts =
337+
[](const CallEvent &Call, const CallDescription &CD) -> bool {
338+
const bool ArgsMatch =
339+
!CD.RequiredArgs || CD.RequiredArgs == Call.getNumArgs();
340+
const bool ParamsMatch =
341+
!CD.RequiredParams || CD.RequiredParams == Call.parameters().size();
342+
return ArgsMatch && ParamsMatch;
343+
};
347344

348-
if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) {
349-
if (RD->getName() == CD.QualifiedName[NumUnmatched - 1])
350-
--NumUnmatched;
345+
const auto MatchQualifiedNameParts = [](const CallDescription &CD,
346+
const Decl *D) -> bool {
347+
const auto FindNextNamespaceOrRecord =
348+
[](const DeclContext *Ctx) -> const DeclContext * {
349+
while (Ctx && !isa<NamespaceDecl, RecordDecl>(Ctx))
350+
Ctx = Ctx->getParent();
351+
return Ctx;
352+
};
353+
354+
auto QualifierPartsIt = CD.begin_qualified_name_parts();
355+
const auto QualifierPartsEndIt = CD.end_qualified_name_parts();
356+
357+
// Match namespace and record names. Skip unrelated names if they don't
358+
// match.
359+
const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext());
360+
for (; Ctx && QualifierPartsIt != QualifierPartsEndIt;
361+
Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) {
362+
// If not matched just continue and try matching for the next one.
363+
if (cast<NamedDecl>(Ctx)->getName() != *QualifierPartsIt)
351364
continue;
352-
}
365+
++QualifierPartsIt;
353366
}
354367

355-
if (NumUnmatched > 0)
356-
return false;
357-
}
368+
// We matched if we consumed all expected qualifier segments.
369+
return QualifierPartsIt == QualifierPartsEndIt;
370+
};
371+
372+
// Let's start matching...
373+
if (!ExactMatchArgAndParamCounts(*this, CD))
374+
return false;
375+
376+
if (!MatchNameOnly(CD, FD))
377+
return false;
378+
379+
if (!CD.hasQualifiedNameParts())
380+
return true;
358381

359-
return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) &&
360-
(!CD.RequiredParams || CD.RequiredParams == parameters().size());
382+
return MatchQualifiedNameParts(CD, FD);
361383
}
362384

363385
SVal CallEvent::getArgSVal(unsigned Index) const {

0 commit comments

Comments
 (0)