Author: QuietMisdreavus
Date: 2025-03-26T17:46:21-06:00
New Revision: 3386156b1e8418083e99833d3d22420cf439c039

URL: 
https://github.com/llvm/llvm-project/commit/3386156b1e8418083e99833d3d22420cf439c039
DIFF: 
https://github.com/llvm/llvm-project/commit/3386156b1e8418083e99833d3d22420cf439c039.diff

LOG: [clang][ExtractAPI] fix a couple crashes when used via libclang (#132297)

This PR fixes two crashes in ExtractAPI that occur when decls are
requested via libclang:

- A null-dereference would sometimes happen in
`DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization`
when the template being processed was loaded indirectly via a typedef,
with parameters filled in. The first commit loads the template parameter
locations ahead of time to perform a null check before dereferencing.
- An assertion (or another null-dereference) was happening in
`CXXRecordDecl::bases` when processing a forward-declaration (i.e. a
record without a definition). The second commit guards the use of
`bases` in `ExtractAPIVisitorBase::getBases` by first checking that the
decl in question has a complete definition.

The added test `extract-api-cursor-cpp` adds tests for these two
scenarios to protect against the crash in the future.

Fixes rdar://140592475, fixes rdar://123430367

Added: 
    clang/test/Index/extract-api-cursor-cpp.cpp

Modified: 
    clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
    clang/lib/ExtractAPI/DeclarationFragments.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h 
b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index e60440e14a9fe..9ea664f57f828 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -173,6 +173,10 @@ class ExtractAPIVisitorBase : public 
RecursiveASTVisitor<Derived> {
 
 protected:
   SmallVector<SymbolReference> getBases(const CXXRecordDecl *Decl) {
+    if (!Decl->isCompleteDefinition()) {
+      return {};
+    }
+
     // FIXME: store AccessSpecifier given by inheritance
     SmallVector<SymbolReference> Bases;
     for (const auto &BaseSpecifier : Decl->bases()) {

diff  --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp 
b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 66c03863293c2..480e33f607bb0 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -1225,6 +1225,10 @@ DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
     const ClassTemplateSpecializationDecl *Decl) {
   DeclarationFragments Fragments;
+  std::optional<ArrayRef<TemplateArgumentLoc>> TemplateArgumentLocs = {};
+  if (auto *TemplateArgs = Decl->getTemplateArgsAsWritten()) {
+    TemplateArgumentLocs = TemplateArgs->arguments();
+  }
   return Fragments
       .append("template", DeclarationFragments::FragmentKind::Keyword)
       .appendSpace()
@@ -1237,7 +1241,7 @@ 
DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization(
       .append("<", DeclarationFragments::FragmentKind::Text)
       .append(getFragmentsForTemplateArguments(
           Decl->getTemplateArgs().asArray(), Decl->getASTContext(),
-          Decl->getTemplateArgsAsWritten()->arguments()))
+          TemplateArgumentLocs))
       .append(">", DeclarationFragments::FragmentKind::Text)
       .appendSemicolon();
 }

diff  --git a/clang/test/Index/extract-api-cursor-cpp.cpp 
b/clang/test/Index/extract-api-cursor-cpp.cpp
new file mode 100644
index 0000000000000..b47bc065ec159
--- /dev/null
+++ b/clang/test/Index/extract-api-cursor-cpp.cpp
@@ -0,0 +1,41 @@
+// Test is line- and column-sensitive. Run lines are below
+
+template <typename T>
+class basic_vector {
+public:
+    T x;
+    T y;
+};
+
+using my_vec = basic_vector<int>;
+
+class MyClass {
+    my_vec myVec;
+};
+
+struct OuterStruct {
+    struct InnerStruct;
+    int outer_field;
+};
+
+// RUN: c-index-test -single-symbol-sgf-at=%s:13:7 local %s | FileCheck 
--check-prefix=CHECK-VEC-TYPE %s
+// CHECK-VEC-TYPE: 
"parentContexts":[{"kind":"c++.typealias","name":"my_vec","usr":"c:@my_vec"}]
+// CHECK-VEC-TYPE: 
"declarationFragments":[{"kind":"keyword","spelling":"typedef"},{"kind":"text","spelling":"
 
"},{"kind":"typeIdentifier","preciseIdentifier":"c:@ST>1#T@basic_vector","spelling":"basic_vector"},{"kind":"text","spelling":"<"},{"kind":"typeIdentifier","preciseIdentifier":"c:I","spelling":"int"},{"kind":"text","spelling":">
 "},{"kind":"identifier","spelling":"my_vec"},{"kind":"text","spelling":";"}]
+// CHECK-VEC-TYPE: 
"identifier":{"interfaceLanguage":"c++","precise":"c:@my_vec"}
+// CHECK-VEC-TYPE: "kind":{"displayName":"Type 
Alias","identifier":"c++.typealias"}
+// CHECK-VEC-TYPE: "title":"my_vec"
+// CHECK-VEC-TYPE: "pathComponents":["my_vec"]
+
+// RUN: c-index-test -single-symbol-sgf-at=%s:13:13 local %s | FileCheck 
--check-prefix=CHECK-MYVEC %s
+// CHECK-MYVEC: 
"parentContexts":[{"kind":"c++.class","name":"MyClass","usr":"c:@S@MyClass"},{"kind":"c++.property","name":"myVec","usr":"c:@S@MyClass@FI@myVec"}]
+// CHECK-MYVEC: 
"identifier":{"interfaceLanguage":"c++","precise":"c:@S@MyClass@FI@myVec"}
+// CHECK-MYVEC: "kind":{"displayName":"Instance 
Property","identifier":"c++.property"}
+// CHECK-MYVEC: "title":"myVec"
+// CHECK-MYVEC: "pathComponents":["MyClass","myVec"]
+
+// RUN: c-index-test -single-symbol-sgf-at=%s:17:17 local %s | FileCheck 
--check-prefix=CHECK-INNER %s
+// CHECK-INNER: 
"parentContexts":[{"kind":"c++.struct","name":"OuterStruct","usr":"c:@S@OuterStruct"},{"kind":"c++.struct","name":"InnerStruct","usr":"c:@S@OuterStruct@S@InnerStruct"}]
+// CHECK-INNER: 
"identifier":{"interfaceLanguage":"c++","precise":"c:@S@OuterStruct@S@InnerStruct"}
+// CHECK-INNER: "kind":{"displayName":"Structure","identifier":"c++.struct"}
+// CHECK-INNER: "title":"InnerStruct"
+// CHECK-INNER: "pathComponents":["OuterStruct","InnerStruct"]


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

Reply via email to