aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
diff options
context:
space:
mode:
authorYitzhak Mandelbaum <yitzhakm@google.com>2023-04-14 14:21:41 +0000
committerYitzhak Mandelbaum <yitzhakm@google.com>2023-04-17 18:02:51 +0000
commitcd22e0dc9d0b5487eb2d54dd028a2aa439627159 (patch)
treed3664f0512d53ffc72d879814ed411a569ebe187 /clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
parent774703ec08f62d702d40e1f97cd35ae5f732c544 (diff)
downloadllvm-cd22e0dc9d0b5487eb2d54dd028a2aa439627159.zip
llvm-cd22e0dc9d0b5487eb2d54dd028a2aa439627159.tar.gz
llvm-cd22e0dc9d0b5487eb2d54dd028a2aa439627159.tar.bz2
[clang][dataflow] Refine matching of optional types to anchor at top level.
This patch refines the matching of the relevant optional types to anchor on the global namespace. Previously, we could match anything with the right name (e.g. `base::Optional`) even if nested within other namespaces. This over matching resulted in an assertion violation when _different_ `base::Optional` was encountered nested inside another namespace. Fixes issue #57036. Differential Revision: https://reviews.llvm.org/D148344
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp')
-rw-r--r--clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp34
1 files changed, 27 insertions, 7 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index 15120233..88f3488 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -43,9 +43,9 @@ using LatticeTransferState = TransferState<NoopLattice>;
DeclarationMatcher optionalClass() {
return classTemplateSpecializationDecl(
- anyOf(hasName("std::optional"), hasName("std::__optional_storage_base"),
- hasName("__optional_destruct_base"), hasName("absl::optional"),
- hasName("base::Optional")),
+ hasAnyName("::std::optional", "::std::__optional_storage_base",
+ "::std::__optional_destruct_base", "::absl::optional",
+ "::base::Optional"),
hasTemplateArgument(0, refersToType(type().bind("T"))));
}
@@ -251,14 +251,34 @@ QualType stripReference(QualType Type) {
return Type->isReferenceType() ? Type->getPointeeType() : Type;
}
+bool isTopLevelNamespaceWithName(const NamespaceDecl &NS,
+ llvm::StringRef Name) {
+ return NS.getDeclName().isIdentifier() && NS.getName() == Name &&
+ NS.getParent() != nullptr && NS.getParent()->isTranslationUnit();
+}
+
/// Returns true if and only if `Type` is an optional type.
bool isOptionalType(QualType Type) {
if (!Type->isRecordType())
return false;
- // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
- auto TypeName = Type->getAsCXXRecordDecl()->getQualifiedNameAsString();
- return TypeName == "std::optional" || TypeName == "absl::optional" ||
- TypeName == "base::Optional";
+ const CXXRecordDecl *D = Type->getAsCXXRecordDecl();
+ if (D == nullptr || !D->getDeclName().isIdentifier())
+ return false;
+ if (D->getName() == "optional") {
+ if (const auto *N =
+ dyn_cast_or_null<NamespaceDecl>(D->getDeclContext()))
+ return N->isStdNamespace() || isTopLevelNamespaceWithName(*N, "absl");
+ return false;
+ }
+
+ if (D->getName() == "Optional") {
+ // Check whether namespace is "::base".
+ const auto *N =
+ dyn_cast_or_null<NamespaceDecl>(D->getDeclContext());
+ return N != nullptr && isTopLevelNamespaceWithName(*N, "base");
+ }
+
+ return false;
}
/// Returns the number of optional wrappers in `Type`.