Author: Paul Kirth
Date: 2026-04-01T23:17:42-07:00
New Revision: 802d4631e02b35a5890802a83459607d42cf4e98

URL: 
https://github.com/llvm/llvm-project/commit/802d4631e02b35a5890802a83459607d42cf4e98
DIFF: 
https://github.com/llvm/llvm-project/commit/802d4631e02b35a5890802a83459607d42cf4e98.diff

LOG: [clang-doc] Update lookup routines for consistency (#190043)

When filtering is enabled, its possible an Info doesn't have a 
Parent USR. Use `find()` to safely handle that case.

Additionally, I noticed the comparison code for the index
poorly reimplemented the existing comparison from StringRef.
We can just use the one from ADT.

Added: 
    

Modified: 
    clang-tools-extra/clang-doc/JSONGenerator.cpp
    clang-tools-extra/clang-doc/Representation.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp 
b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index a9223cb9c3e8a..d7d7e99d0ba48 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -922,7 +922,12 @@ static void serializeContexts(Info *I, 
StringMap<OwnedPtr<Info>> &Infos) {
   auto ParentUSR = I->ParentUSR;
 
   while (true) {
-    auto &ParentInfo = Infos.at(llvm::toHex(ParentUSR));
+    // Infos may not have the ParentUSR, if its been filtered (public or path),
+    // so we can't use at() for the lookup, since it would abort.
+    auto Iter = Infos.find(llvm::toHex(ParentUSR));
+    if (Iter == Infos.end())
+      break;
+    auto &ParentInfo = Iter->second;
 
     if (ParentInfo && ParentInfo->USR == GlobalNamespaceID) {
       Context GlobalRef(ParentInfo->USR, "Global Namespace",

diff  --git a/clang-tools-extra/clang-doc/Representation.cpp 
b/clang-tools-extra/clang-doc/Representation.cpp
index c92fe1e3ec45d..503cefc7ec040 100644
--- a/clang-tools-extra/clang-doc/Representation.cpp
+++ b/clang-tools-extra/clang-doc/Representation.cpp
@@ -452,22 +452,16 @@ llvm::SmallString<16> Info::extractName() const {
 
 // Order is based on the Name attribute: case insensitive order
 bool Index::operator<(const Index &Other) const {
-  // Loop through each character of both strings
-  for (unsigned I = 0; I < Name.size() && I < Other.Name.size(); ++I) {
-    // Compare them after converting both to lower case
-    int D = tolower(Name[I]) - tolower(Other.Name[I]);
-    if (D == 0)
-      continue;
-    return D < 0;
-  }
-  // If both strings have the size it means they would be equal if changed to
-  // lower case. In here, lower case will be smaller than upper case
-  // Example: string < stRing = true
-  // This is the opposite of how operator < handles strings
-  if (Name.size() == Other.Name.size())
-    return Name > Other.Name;
-  // If they are not the same size; the shorter string is smaller
-  return Name.size() < Other.Name.size();
+  // Start with case-insensitive (e.g., 'apple' < 'Zebra').
+  // This prevents 'Zebra' from appearing before 'apple' due to ASCII values,
+  // where uppercase letters have a lower numeric value than lowercase.
+  int Cmp = Name.compare_insensitive(Other.Name);
+  if (Cmp != 0)
+    return Cmp < 0;
+
+  // If names are identical, we fall back to standard string comparison where
+  // uppercase precedes lowercase (e.g., 'Apple' < 'apple').
+  return Name < Other.Name;
 }
 
 OwningVec<const Index *> Index::getSortedChildren() const {


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to