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