[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc0725865b188: [clang][dataflow] Generalize custom comparison 
to return tri-value result. (authored by ymandel).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137334/new/

https://reviews.llvm.org/D137334

Files:
  clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
  
clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
  clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
  clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
  clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
===
--- clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -351,24 +351,27 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 const auto *Decl = Type->getAsCXXRecordDecl();
 if (Decl == nullptr || Decl->getIdentifier() == nullptr ||
 Decl->getName() != "SpecialBool")
-  return false;
+  return ComparisonResult::Unknown;
 
 auto *IsSet1 = cast_or_null(Val1.getProperty("is_set"));
+auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet1 == nullptr)
-  return true;
+  return IsSet2 == nullptr ? ComparisonResult::Same
+   : ComparisonResult::Different;
 
-auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet2 == nullptr)
-  return false;
+  return ComparisonResult::Different;
 
 return Env1.flowConditionImplies(*IsSet1) ==
-   Env2.flowConditionImplies(*IsSet2);
+   Env2.flowConditionImplies(*IsSet2)
+   ? ComparisonResult::Same
+   : ComparisonResult::Different;
   }
 
   // Always returns `true` to accept the `MergedVal`.
@@ -509,18 +512,19 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 // Nothing to say about a value that does not model an `OptionalInt`.
 if (!Type->isRecordType() ||
 Type->getAsCXXRecordDecl()->getQualifiedNameAsString() != "OptionalInt")
-  return false;
+  return ComparisonResult::Unknown;
 
 auto *Prop1 = Val1.getProperty("has_value");
 auto *Prop2 = Val2.getProperty("has_value");
 assert(Prop1 != nullptr && Prop2 != nullptr);
-return areEquivalentValues(*Prop1, *Prop2);
+return areEquivalentValues(*Prop1, *Prop2) ? ComparisonResult::Same
+   : ComparisonResult::Different;
   }
 
   bool merge(QualType Type, const Value , const Environment ,
@@ -1182,12 +1186,12 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 // Changes to a sound approximation, which allows us to test whether we can
 // (soundly) converge for some loops.
-return false;
+return ComparisonResult::Unknown;
   }
 };
 
Index: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
===
--- clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -208,7 +208,7 @@
 }
 
 /// Returns true if and only if `Type` is an optional type.
-bool IsOptionalType(QualType Type) {
+bool isOptionalType(QualType Type) {
   if (!Type->isRecordType())
 return false;
   // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
@@ -222,7 +222,7 @@
 /// For example, if `Type` is `optional>`, the result of this
 /// function will be 2.
 int countOptionalWrappers(const ASTContext , QualType Type) {
-  if (!IsOptionalType(Type))
+  if (!isOptionalType(Type))
 return 0;
   return 1 + countOptionalWrappers(
  ASTCtx,
@@ -720,12 

[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 472978.
ymandel added a comment.

address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137334/new/

https://reviews.llvm.org/D137334

Files:
  clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
  
clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
  clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
  clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
  clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
===
--- clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -351,24 +351,27 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 const auto *Decl = Type->getAsCXXRecordDecl();
 if (Decl == nullptr || Decl->getIdentifier() == nullptr ||
 Decl->getName() != "SpecialBool")
-  return false;
+  return ComparisonResult::Unknown;
 
 auto *IsSet1 = cast_or_null(Val1.getProperty("is_set"));
+auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet1 == nullptr)
-  return true;
+  return IsSet2 == nullptr ? ComparisonResult::Same
+   : ComparisonResult::Different;
 
-auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet2 == nullptr)
-  return false;
+  return ComparisonResult::Different;
 
 return Env1.flowConditionImplies(*IsSet1) ==
-   Env2.flowConditionImplies(*IsSet2);
+   Env2.flowConditionImplies(*IsSet2)
+   ? ComparisonResult::Same
+   : ComparisonResult::Different;
   }
 
   // Always returns `true` to accept the `MergedVal`.
@@ -509,18 +512,19 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 // Nothing to say about a value that does not model an `OptionalInt`.
 if (!Type->isRecordType() ||
 Type->getAsCXXRecordDecl()->getQualifiedNameAsString() != "OptionalInt")
-  return false;
+  return ComparisonResult::Unknown;
 
 auto *Prop1 = Val1.getProperty("has_value");
 auto *Prop2 = Val2.getProperty("has_value");
 assert(Prop1 != nullptr && Prop2 != nullptr);
-return areEquivalentValues(*Prop1, *Prop2);
+return areEquivalentValues(*Prop1, *Prop2) ? ComparisonResult::Same
+   : ComparisonResult::Different;
   }
 
   bool merge(QualType Type, const Value , const Environment ,
@@ -1182,12 +1186,12 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 // Changes to a sound approximation, which allows us to test whether we can
 // (soundly) converge for some loops.
-return false;
+return ComparisonResult::Unknown;
   }
 };
 
Index: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
===
--- clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -208,7 +208,7 @@
 }
 
 /// Returns true if and only if `Type` is an optional type.
-bool IsOptionalType(QualType Type) {
+bool isOptionalType(QualType Type) {
   if (!Type->isRecordType())
 return false;
   // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
@@ -222,7 +222,7 @@
 /// For example, if `Type` is `optional>`, the result of this
 /// function will be 2.
 int countOptionalWrappers(const ASTContext , QualType Type) {
-  if (!IsOptionalType(Type))
+  if (!isOptionalType(Type))
 return 0;
   return 1 + countOptionalWrappers(
  ASTCtx,
@@ -720,12 +720,14 @@
   TransferMatchSwitch(*Elt, getASTContext(), State);
 }
 
-bool UncheckedOptionalAccessModel::compareEquivalent(QualType Type,
-   

[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Dmitri Gribenko via Phabricator via cfe-commits
gribozavr2 accepted this revision.
gribozavr2 added inline comments.
This revision is now accepted and ready to land.



Comment at: 
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h:73-74
+/// Returns:
+///   `Same`:`Val1` is equivalent to `Val2`, according to the model.
+///   `Different`:`Val1` is distinct from `Val2`, according to the model.
+///   `Unknown`: The model does not determine a relationship between `Val1`





Comment at: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:1189-1191
+  ComparisonResult compare(QualType Type, const Value ,
  const Environment , const Value ,
  const Environment ) override {




Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137334/new/

https://reviews.llvm.org/D137334

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel marked 2 inline comments as done.
ymandel added inline comments.



Comment at: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:365
 if (IsSet1 == nullptr)
-  return true;
+  return IsSet2 ? ComparisonStatus::Same : ComparisonStatus::Different;
 

sgatev wrote:
> Why is it same if `IsSet1` is null and `IsSet2` isn't null?
Fixed. that was a mistake.



Comment at: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:1185
-
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,

sgatev wrote:
> Why remove this? It's not the same as the default implementation, right?
Correct -- that was a mistake (I think my first version had a sound default, 
which I later put back as unsound to keep this NFC).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137334/new/

https://reviews.llvm.org/D137334

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 472975.
ymandel marked 2 inline comments as done.
ymandel added a comment.

address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137334/new/

https://reviews.llvm.org/D137334

Files:
  clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
  
clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
  clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
  clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
  clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
===
--- clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -351,24 +351,27 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 const auto *Decl = Type->getAsCXXRecordDecl();
 if (Decl == nullptr || Decl->getIdentifier() == nullptr ||
 Decl->getName() != "SpecialBool")
-  return false;
+  return ComparisonResult::Unknown;
 
 auto *IsSet1 = cast_or_null(Val1.getProperty("is_set"));
+auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet1 == nullptr)
-  return true;
+  return IsSet2 == nullptr ? ComparisonResult::Same
+   : ComparisonResult::Different;
 
-auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet2 == nullptr)
-  return false;
+  return ComparisonResult::Different;
 
 return Env1.flowConditionImplies(*IsSet1) ==
-   Env2.flowConditionImplies(*IsSet2);
+   Env2.flowConditionImplies(*IsSet2)
+   ? ComparisonResult::Same
+   : ComparisonResult::Different;
   }
 
   // Always returns `true` to accept the `MergedVal`.
@@ -509,18 +512,19 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonResult compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 // Nothing to say about a value that does not model an `OptionalInt`.
 if (!Type->isRecordType() ||
 Type->getAsCXXRecordDecl()->getQualifiedNameAsString() != "OptionalInt")
-  return false;
+  return ComparisonResult::Unknown;
 
 auto *Prop1 = Val1.getProperty("has_value");
 auto *Prop2 = Val2.getProperty("has_value");
 assert(Prop1 != nullptr && Prop2 != nullptr);
-return areEquivalentValues(*Prop1, *Prop2);
+return areEquivalentValues(*Prop1, *Prop2) ? ComparisonResult::Same
+   : ComparisonResult::Different;
   }
 
   bool merge(QualType Type, const Value , const Environment ,
@@ -1182,12 +1186,12 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
+  ComparisonResult compare(QualType Type, const Value ,
  const Environment , const Value ,
  const Environment ) override {
 // Changes to a sound approximation, which allows us to test whether we can
 // (soundly) converge for some loops.
-return false;
+return ComparisonResult::Unknown;
   }
 };
 
Index: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
===
--- clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -208,7 +208,7 @@
 }
 
 /// Returns true if and only if `Type` is an optional type.
-bool IsOptionalType(QualType Type) {
+bool isOptionalType(QualType Type) {
   if (!Type->isRecordType())
 return false;
   // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
@@ -222,7 +222,7 @@
 /// For example, if `Type` is `optional>`, the result of this
 /// function will be 2.
 int countOptionalWrappers(const ASTContext , QualType Type) {
-  if (!IsOptionalType(Type))
+  if (!isOptionalType(Type))
 return 0;
   return 1 + countOptionalWrappers(
  ASTCtx,
@@ -720,12 +720,14 @@
   TransferMatchSwitch(*Elt, getASTContext(), State);
 }
 
-bool UncheckedOptionalAccessModel::compareEquivalent(QualType Type,
- const Value ,
-  

[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Stanislav Gatev via Phabricator via cfe-commits
sgatev added inline comments.



Comment at: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h:52
+/// Indicates the result of a tentative comparison.
+enum class ComparisonStatus {
+  Same,

Alternative that I slightly prefer - `ComparisonResult`.



Comment at: clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h:75
+///   `Different`:`Val1` is distinct from `Val2`, according to the model.
+///   `Unknown`: The model does not determine a relationship between `Val1`
+///and `Val2`.

Perhaps replace "does not" with "can't"?



Comment at: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:365
 if (IsSet1 == nullptr)
-  return true;
+  return IsSet2 ? ComparisonStatus::Same : ComparisonStatus::Different;
 

Why is it same if `IsSet1` is null and `IsSet2` isn't null?



Comment at: 
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp:1185
-
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,

Why remove this? It's not the same as the default implementation, right?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137334/new/

https://reviews.llvm.org/D137334

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D137334: [clang][dataflow] Generalize custom comparison to return tri-value result.

2022-11-03 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel created this revision.
ymandel added reviewers: xazax.hun, sgatev, gribozavr2.
Herald added subscribers: martong, rnkovacs.
Herald added a reviewer: NoQ.
Herald added a project: All.
ymandel requested review of this revision.
Herald added a project: clang.

Currently, the API for a model's custom value comparison returns a
boolean. Therefore, models cannot distinguish between situations where the
values are recognized by the model and different and those where the values are
just not recognized.  This patch changes the return value to a tri-valued enum,
allowing models to express "don't know".

This patch is essentially a NFC -- no practical differences result from this
change in this patch. But, it prepares for future patches (particularly,
upcoming patches for widening) which will take advantage of the new flexibility.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D137334

Files:
  clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
  
clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h
  clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
  clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
  clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
===
--- clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+++ clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
@@ -351,24 +351,26 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonStatus compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 const auto *Decl = Type->getAsCXXRecordDecl();
 if (Decl == nullptr || Decl->getIdentifier() == nullptr ||
 Decl->getName() != "SpecialBool")
-  return false;
+  return ComparisonStatus::Unknown;
 
 auto *IsSet1 = cast_or_null(Val1.getProperty("is_set"));
+auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet1 == nullptr)
-  return true;
+  return IsSet2 ? ComparisonStatus::Same : ComparisonStatus::Different;
 
-auto *IsSet2 = cast_or_null(Val2.getProperty("is_set"));
 if (IsSet2 == nullptr)
-  return false;
+  return ComparisonStatus::Different;
 
 return Env1.flowConditionImplies(*IsSet1) ==
-   Env2.flowConditionImplies(*IsSet2);
+   Env2.flowConditionImplies(*IsSet2)
+   ? ComparisonStatus::Same
+   : ComparisonStatus::Different;
   }
 
   // Always returns `true` to accept the `MergedVal`.
@@ -509,18 +511,19 @@
 }
   }
 
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
+  ComparisonStatus compare(QualType Type, const Value ,
+   const Environment , const Value ,
+   const Environment ) override {
 // Nothing to say about a value that does not model an `OptionalInt`.
 if (!Type->isRecordType() ||
 Type->getAsCXXRecordDecl()->getQualifiedNameAsString() != "OptionalInt")
-  return false;
+  return ComparisonStatus::Unknown;
 
 auto *Prop1 = Val1.getProperty("has_value");
 auto *Prop2 = Val2.getProperty("has_value");
 assert(Prop1 != nullptr && Prop2 != nullptr);
-return areEquivalentValues(*Prop1, *Prop2);
+return areEquivalentValues(*Prop1, *Prop2) ? ComparisonStatus::Same
+   : ComparisonStatus::Different;
   }
 
   bool merge(QualType Type, const Value , const Environment ,
@@ -1181,14 +1184,6 @@
   Env.setStorageLocation(*E, Loc);
 }
   }
-
-  bool compareEquivalent(QualType Type, const Value ,
- const Environment , const Value ,
- const Environment ) override {
-// Changes to a sound approximation, which allows us to test whether we can
-// (soundly) converge for some loops.
-return false;
-  }
 };
 
 class TopTest : public Test {
Index: clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
===
--- clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -208,7 +208,7 @@
 }
 
 /// Returns true if and only if `Type` is an optional type.
-bool IsOptionalType(QualType Type) {
+bool isOptionalType(QualType Type) {
   if (!Type->isRecordType())
 return false;
   // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
@@