diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-27 23:34:35 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2024-10-23 18:26:01 +0000 |
| commit | 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch) | |
| tree | 6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/clang/lib/ExtractAPI | |
| parent | 6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff) | |
| parent | ac9a064cb179f3425b310fa2847f8764ac970a4d (diff) | |
Diffstat (limited to 'contrib/llvm-project/clang/lib/ExtractAPI')
6 files changed, 820 insertions, 1277 deletions
diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/API.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/API.cpp index aa7a1e9360f4..ab1108f663de 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/API.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/API.cpp @@ -13,514 +13,87 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/API.h" -#include "clang/AST/CommentCommandTraits.h" -#include "clang/AST/CommentLexer.h" #include "clang/AST/RawCommentList.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include <memory> using namespace clang::extractapi; using namespace llvm; -namespace { +SymbolReference::SymbolReference(const APIRecord *R) + : Name(R->Name), USR(R->USR), Record(R) {} -template <typename RecordTy, typename... CtorArgsTy> -RecordTy *addTopLevelRecord(DenseMap<StringRef, APIRecord *> &USRLookupTable, - APISet::RecordMap<RecordTy> &RecordMap, - StringRef USR, CtorArgsTy &&...CtorArgs) { - auto Result = RecordMap.insert({USR, nullptr}); - - // Create the record if it does not already exist - if (Result.second) - Result.first->second = - std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...); - - auto *Record = Result.first->second.get(); - USRLookupTable.insert({USR, Record}); - return Record; -} - -} // namespace - -NamespaceRecord * -APISet::addNamespace(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, Namespaces, USR, Name, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader); - - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -GlobalVariableRecord * -APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Fragments, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc, - std::move(Availability), Linkage, Comment, Fragments, - SubHeading, IsFromSystemHeader); -} - -GlobalVariableTemplateRecord *APISet::addGlobalVariableTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalVariableTemplates, USR, - Name, Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Template, - IsFromSystemHeader); -} - -GlobalFunctionRecord *APISet::addGlobalFunction( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Fragments, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, - std::move(Availability), Linkage, Comment, Fragments, - SubHeading, Signature, IsFromSystemHeader); -} - -GlobalFunctionTemplateRecord *APISet::addGlobalFunctionTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - Template Template, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalFunctionTemplates, USR, - Name, Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Signature, Template, - IsFromSystemHeader); -} - -GlobalFunctionTemplateSpecializationRecord * -APISet::addGlobalFunctionTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader) { - return addTopLevelRecord( - USRBasedLookupTable, GlobalFunctionTemplateSpecializations, USR, Name, - Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, - Signature, IsFromSystemHeader); -} - -EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, - StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - auto Record = std::make_unique<EnumConstantRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Enum->USR, Enum->Name, Enum->getKind(), Enum); - USRBasedLookupTable.insert({USR, Record.get()}); - return Enum->Constants.emplace_back(std::move(Record)).get(); -} - -EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader); -} - -RecordFieldRecord *APISet::addRecordField( - RecordRecord *Record, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, bool IsFromSystemHeader) { - auto RecordField = std::make_unique<RecordFieldRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - Kind, IsFromSystemHeader); - RecordField->ParentInformation = APIRecord::HierarchyInformation( - Record->USR, Record->Name, Record->getKind(), Record); - USRBasedLookupTable.insert({USR, RecordField.get()}); - return Record->Fields.emplace_back(std::move(RecordField)).get(); -} - -RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Kind, IsFromSystemHeader); -} - -StaticFieldRecord * -APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference Context, - AccessControl Access, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc, - std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Context, Access, - IsFromSystemHeader); -} - -CXXFieldRecord * -APISet::addCXXField(APIRecord *CXXClass, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, AccessControl Access, - bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXFields, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass); - return Record; -} - -CXXFieldTemplateRecord *APISet::addCXXFieldTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, Template Template, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, CXXFieldTemplates, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Access, Template, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -CXXClassRecord * -APISet::addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, APIRecord::RecordKind Kind, - AccessControl Access, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXClasses, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Kind, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplateRecord *APISet::addClassTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Template, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations, USR, - Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplatePartialSpecializationRecord * -APISet::addClassTemplatePartialSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, ClassTemplatePartialSpecializations, USR, Name, Loc, - std::move(Availability), Comment, Declaration, SubHeading, Template, - Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -GlobalVariableTemplateSpecializationRecord * -APISet::addGlobalVariableTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, - GlobalVariableTemplateSpecializations, USR, Name, - Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, IsFromSystemHeader); -} - -GlobalVariableTemplatePartialSpecializationRecord * -APISet::addGlobalVariableTemplatePartialSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader) { - return addTopLevelRecord( - USRBasedLookupTable, GlobalVariableTemplatePartialSpecializations, USR, - Name, Loc, std::move(Availability), Linkage, Comment, Declaration, - SubHeading, Template, IsFromSystemHeader); -} - -ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR, - PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - Template Template, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Concepts, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Template, IsFromSystemHeader); -} - -CXXMethodRecord *APISet::addCXXInstanceMethod( - APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - CXXMethodRecord *Record = - addTopLevelRecord(USRBasedLookupTable, CXXInstanceMethods, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), - CXXClassRecord); - return Record; -} - -CXXMethodRecord *APISet::addCXXStaticMethod( - APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - CXXMethodRecord *Record = - addTopLevelRecord(USRBasedLookupTable, CXXStaticMethods, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), - CXXClassRecord); - return Record; -} - -CXXMethodTemplateRecord *APISet::addCXXMethodTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, Template Template, - bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord(USRBasedLookupTable, CXXMethodTemplates, USR, - Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, Signature, Access, - Template, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -CXXMethodTemplateSpecializationRecord *APISet::addCXXMethodTemplateSpec( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXMethodTemplateSpecializations, USR, Name, Loc, - std::move(Availability), Comment, Declaration, SubHeading, Signature, - Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; +APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { + switch (Ctx->getKind()) { +#define RECORD_CONTEXT(CLASS, KIND) \ + case KIND: \ + return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx)); +#include "clang/ExtractAPI/APIRecords.inc" + default: + return nullptr; + // llvm_unreachable("RecordContext derived class isn't propertly + // implemented"); + } } -ObjCCategoryRecord *APISet::addObjCCategory( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - SymbolReference Interface, bool IsFromSystemHeader, - bool IsFromExternalModule) { - // Create the category record. - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Interface, IsFromSystemHeader); - - Record->IsFromExternalModule = IsFromExternalModule; - - auto It = ObjCInterfaces.find(Interface.USR); - if (It != ObjCInterfaces.end()) - It->second->Categories.push_back(Record); - - return Record; +RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { + if (!Record) + return nullptr; + switch (Record->getKind()) { +#define RECORD_CONTEXT(CLASS, KIND) \ + case KIND: \ + return static_cast<CLASS *>(const_cast<APIRecord *>(Record)); +#include "clang/ExtractAPI/APIRecords.inc" + default: + return nullptr; + // llvm_unreachable("RecordContext derived class isn't propertly + // implemented"); + } } -ObjCInterfaceRecord * -APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - SymbolReference SuperClass, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, - std::move(Availability), Linkage, Comment, - Declaration, SubHeading, SuperClass, - IsFromSystemHeader); +bool RecordContext::IsWellFormed() const { + // Check that First and Last are both null or both non-null. + return (First == nullptr) == (Last == nullptr); } -ObjCMethodRecord *APISet::addObjCMethod( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, bool IsInstanceMethod, - bool IsFromSystemHeader) { - std::unique_ptr<ObjCMethodRecord> Record; - if (IsInstanceMethod) - Record = std::make_unique<ObjCInstanceMethodRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, IsFromSystemHeader); +void RecordContext::stealRecordChain(RecordContext &Other) { + assert(IsWellFormed()); + // If we don't have an empty chain append Other's chain into ours. + if (First) + Last->NextInContext = Other.First; else - Record = std::make_unique<ObjCClassMethodRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, IsFromSystemHeader); + First = Other.First; - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Methods.emplace_back(std::move(Record)).get(); -} + Last = Other.Last; -ObjCPropertyRecord *APISet::addObjCProperty( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, - StringRef SetterName, bool IsOptional, bool IsInstanceProperty, - bool IsFromSystemHeader) { - std::unique_ptr<ObjCPropertyRecord> Record; - if (IsInstanceProperty) - Record = std::make_unique<ObjCInstancePropertyRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Attributes, GetterName, SetterName, IsOptional, - IsFromSystemHeader); - else - Record = std::make_unique<ObjCClassPropertyRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Attributes, GetterName, SetterName, IsOptional, - IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Properties.emplace_back(std::move(Record)).get(); + // Delete Other's chain to ensure we don't accidentally traverse it. + Other.First = nullptr; + Other.Last = nullptr; } -ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { - auto Record = std::make_unique<ObjCInstanceVariableRecord>( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Ivars.emplace_back(std::move(Record)).get(); -} +void RecordContext::addToRecordChain(APIRecord *Record) const { + assert(IsWellFormed()); + if (!First) { + First = Record; + Last = Record; + return; + } -ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, - PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader); -} - -MacroDefinitionRecord * -APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, - Declaration, SubHeading, IsFromSystemHeader); -} - -TypedefRecord * -APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - SymbolReference UnderlyingType, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, UnderlyingType, IsFromSystemHeader); + Last->NextInContext = Record; + Last = Record; } APIRecord *APISet::findRecordForUSR(StringRef USR) const { if (USR.empty()) return nullptr; - return USRBasedLookupTable.lookup(USR); -} + auto FindIt = USRBasedLookupTable.find(USR); + if (FindIt != USRBasedLookupTable.end()) + return FindIt->getSecond().get(); -StringRef APISet::recordUSR(const Decl *D) { - SmallString<128> USR; - index::generateUSRForDecl(D, USR); - return copyString(USR); -} - -StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, - const SourceManager &SM) { - SmallString<128> USR; - index::generateUSRForMacro(Name, SL, SM, USR); - return copyString(USR); + return nullptr; } StringRef APISet::copyString(StringRef String) { @@ -528,15 +101,23 @@ StringRef APISet::copyString(StringRef String) { return {}; // No need to allocate memory and copy if the string has already been stored. - if (StringAllocator.identifyObject(String.data())) + if (Allocator.identifyObject(String.data())) return String; - void *Ptr = StringAllocator.Allocate(String.size(), 1); + void *Ptr = Allocator.Allocate(String.size(), 1); memcpy(Ptr, String.data(), String.size()); return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); } +SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, + StringRef Source) { + return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); +} + APIRecord::~APIRecord() {} +TagRecord::~TagRecord() {} +RecordRecord::~RecordRecord() {} +RecordFieldRecord::~RecordFieldRecord() {} ObjCContainerRecord::~ObjCContainerRecord() {} ObjCMethodRecord::~ObjCMethodRecord() {} ObjCPropertyRecord::~ObjCPropertyRecord() {} @@ -546,8 +127,10 @@ void GlobalFunctionRecord::anchor() {} void GlobalVariableRecord::anchor() {} void EnumConstantRecord::anchor() {} void EnumRecord::anchor() {} -void RecordFieldRecord::anchor() {} -void RecordRecord::anchor() {} +void StructFieldRecord::anchor() {} +void StructRecord::anchor() {} +void UnionFieldRecord::anchor() {} +void UnionRecord::anchor() {} void CXXFieldRecord::anchor() {} void CXXClassRecord::anchor() {} void CXXConstructorRecord::anchor() {} diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/AvailabilityInfo.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/AvailabilityInfo.cpp deleted file mode 100644 index 18e4d16b45bb..000000000000 --- a/contrib/llvm-project/clang/lib/ExtractAPI/AvailabilityInfo.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "clang/ExtractAPI/AvailabilityInfo.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Attr.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/ADT/STLExtras.h" - -using namespace clang::extractapi; -using namespace llvm; - -AvailabilityInfo AvailabilityInfo::createFromDecl(const Decl *Decl) { - ASTContext &Context = Decl->getASTContext(); - StringRef PlatformName = Context.getTargetInfo().getPlatformName(); - AvailabilityInfo Availability; - - // Collect availability attributes from all redeclarations. - for (const auto *RD : Decl->redecls()) { - for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) { - if (A->getPlatform()->getName() != PlatformName) - continue; - Availability = - AvailabilityInfo(A->getPlatform()->getName(), A->getIntroduced(), - A->getDeprecated(), A->getObsoleted(), false, false); - break; - } - - if (const auto *A = RD->getAttr<UnavailableAttr>()) - if (!A->isImplicit()) - Availability.UnconditionallyUnavailable = true; - - if (const auto *A = RD->getAttr<DeprecatedAttr>()) - if (!A->isImplicit()) - Availability.UnconditionallyDeprecated = true; - } - return Availability; -} diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp index 56c1f5bf5eab..6b85c7db9034 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -12,16 +12,19 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/DeclarationFragments.h" +#include "clang/AST/ASTFwd.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/QualTypeNames.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" -#include "clang/Basic/OperatorKinds.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringSwitch.h" -#include <typeinfo> +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <optional> using namespace clang::extractapi; using namespace llvm; @@ -60,23 +63,44 @@ void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo, } // namespace -DeclarationFragments &DeclarationFragments::appendSpace() { +DeclarationFragments & +DeclarationFragments::appendUnduplicatedTextCharacter(char Character) { if (!Fragments.empty()) { Fragment &Last = Fragments.back(); if (Last.Kind == FragmentKind::Text) { // Merge the extra space into the last fragment if the last fragment is // also text. - if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. - Last.Spelling.push_back(' '); + if (Last.Spelling.back() != Character) { // avoid duplicates at end + Last.Spelling.push_back(Character); } } else { - append(" ", FragmentKind::Text); + append("", FragmentKind::Text); + Fragments.back().Spelling.push_back(Character); } } return *this; } +DeclarationFragments &DeclarationFragments::appendSpace() { + return appendUnduplicatedTextCharacter(' '); +} + +DeclarationFragments &DeclarationFragments::appendSemicolon() { + return appendUnduplicatedTextCharacter(';'); +} + +DeclarationFragments &DeclarationFragments::removeTrailingSemicolon() { + if (Fragments.empty()) + return *this; + + Fragment &Last = Fragments.back(); + if (Last.Kind == FragmentKind::Text && Last.Spelling.back() == ';') + Last.Spelling.pop_back(); + + return *this; +} + StringRef DeclarationFragments::getFragmentKindString( DeclarationFragments::FragmentKind Kind) { switch (Kind) { @@ -368,6 +392,25 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( getFragmentsForType(AT->getElementType(), Context, After)); } + if (const TemplateSpecializationType *TemplSpecTy = + dyn_cast<TemplateSpecializationType>(T)) { + const auto TemplName = TemplSpecTy->getTemplateName(); + std::string Str; + raw_string_ostream Stream(Str); + TemplName.print(Stream, Context.getPrintingPolicy(), + TemplateName::Qualified::AsWritten); + SmallString<64> USR(""); + if (const auto *TemplDecl = TemplName.getAsTemplateDecl()) + index::generateUSRForDecl(TemplDecl, USR); + + return Fragments + .append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, USR) + .append("<", DeclarationFragments::FragmentKind::Text) + .append(getFragmentsForTemplateArguments( + TemplSpecTy->template_arguments(), Context, std::nullopt)) + .append(">", DeclarationFragments::FragmentKind::Text); + } + // Everything we care about has been handled now, reduce to the canonical // unqualified base type. QualType Base = T->getCanonicalTypeUnqualified(); @@ -378,7 +421,8 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( const TagDecl *Decl = TagTy->getDecl(); // Anonymous decl, skip this fragment. if (Decl->getName().empty()) - return Fragments; + return Fragments.append("{ ... }", + DeclarationFragments::FragmentKind::Text); SmallString<128> TagUSR; clang::index::generateUSRForDecl(Decl, TagUSR); return Fragments.append(Decl->getName(), @@ -469,7 +513,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNamespace( if (!Decl->isAnonymousNamespace()) Fragments.appendSpace().append( Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -511,7 +555,7 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { return Fragments .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -533,17 +577,15 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) { DeclarationFragments After; DeclarationFragments ArgumentFragment = getFragmentsForType(T, Var->getASTContext(), After); - if (ArgumentFragment.begin()->Spelling.substr(0, 14).compare( - "type-parameter") == 0) { - std::string ProperArgName = getNameForTemplateArgument( - Var->getDescribedVarTemplate()->getTemplateParameters()->asArray(), - ArgumentFragment.begin()->Spelling); + if (StringRef(ArgumentFragment.begin()->Spelling) + .starts_with("type-parameter")) { + std::string ProperArgName = T.getAsString(); ArgumentFragment.begin()->Spelling.swap(ProperArgName); } Fragments.append(std::move(ArgumentFragment)) .appendSpace() .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); return Fragments; } @@ -568,14 +610,9 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { else TypeFragments.append(getFragmentsForType(T, Param->getASTContext(), After)); - if (TypeFragments.begin()->Spelling.substr(0, 14).compare("type-parameter") == - 0) { - std::string ProperArgName = getNameForTemplateArgument( - dyn_cast<FunctionDecl>(Param->getDeclContext()) - ->getDescribedFunctionTemplate() - ->getTemplateParameters() - ->asArray(), - TypeFragments.begin()->Spelling); + if (StringRef(TypeFragments.begin()->Spelling) + .starts_with("type-parameter")) { + std::string ProperArgName = Param->getOriginalType().getAsString(); TypeFragments.begin()->Spelling.swap(ProperArgName); } @@ -638,7 +675,6 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForBlock( DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { DeclarationFragments Fragments; - // FIXME: Handle template specialization switch (Func->getStorageClass()) { case SC_None: case SC_PrivateExtern: @@ -666,19 +702,16 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { DeclarationFragments After; auto ReturnValueFragment = getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After); - if (ReturnValueFragment.begin()->Spelling.substr(0, 14).compare( - "type-parameter") == 0) { - std::string ProperArgName = - getNameForTemplateArgument(Func->getDescribedFunctionTemplate() - ->getTemplateParameters() - ->asArray(), - ReturnValueFragment.begin()->Spelling); + if (StringRef(ReturnValueFragment.begin()->Spelling) + .starts_with("type-parameter")) { + std::string ProperArgName = Func->getReturnType().getAsString(); ReturnValueFragment.begin()->Spelling.swap(ProperArgName); } Fragments.append(std::move(ReturnValueFragment)) .appendSpace() - .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier); + .append(Func->getNameAsString(), + DeclarationFragments::FragmentKind::Identifier); if (Func->getTemplateSpecializationInfo()) { Fragments.append("<", DeclarationFragments::FragmentKind::Text); @@ -712,7 +745,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { Fragments.append(DeclarationFragments::getExceptionSpecificationString( Func->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( @@ -736,12 +769,17 @@ DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { QualType IntegerType = EnumDecl->getIntegerType(); if (!IntegerType.isNull()) - Fragments.append(": ", DeclarationFragments::FragmentKind::Text) + Fragments.appendSpace() + .append(": ", DeclarationFragments::FragmentKind::Text) .append( getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) .append(std::move(After)); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + if (EnumDecl->getName().empty()) + Fragments.appendSpace().append("{ ... }", + DeclarationFragments::FragmentKind::Text); + + return Fragments.appendSemicolon(); } DeclarationFragments @@ -757,7 +795,7 @@ DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { .appendSpace() .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( @@ -771,11 +809,14 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( else Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword); + Fragments.appendSpace(); if (!Record->getName().empty()) - Fragments.appendSpace().append( - Record->getName(), DeclarationFragments::FragmentKind::Identifier); + Fragments.append(Record->getName(), + DeclarationFragments::FragmentKind::Identifier); + else + Fragments.append("{ ... }", DeclarationFragments::FragmentKind::Text); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( @@ -790,7 +831,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -820,7 +861,7 @@ DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( @@ -860,7 +901,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -891,7 +932,7 @@ DeclarationFragmentsBuilder::getFragmentsForConversionFunction( Fragments.appendSpace().append("const", DeclarationFragments::FragmentKind::Keyword); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -923,7 +964,7 @@ DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } // Get fragments for template parameters, e.g. T in tempalte<typename T> ... @@ -936,50 +977,89 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters( Fragments.append(",", DeclarationFragments::FragmentKind::Text) .appendSpace(); - const auto *TemplateParam = - dyn_cast<TemplateTypeParmDecl>(ParameterArray[i]); - if (!TemplateParam) - continue; - if (TemplateParam->hasTypeConstraint()) - Fragments.append(TemplateParam->getTypeConstraint() - ->getNamedConcept() - ->getName() - .str(), - DeclarationFragments::FragmentKind::TypeIdentifier); - else if (TemplateParam->wasDeclaredWithTypename()) - Fragments.append("typename", DeclarationFragments::FragmentKind::Keyword); - else - Fragments.append("class", DeclarationFragments::FragmentKind::Keyword); - - if (TemplateParam->isParameterPack()) - Fragments.append("...", DeclarationFragments::FragmentKind::Text); - - Fragments.appendSpace().append( - TemplateParam->getName(), - DeclarationFragments::FragmentKind::GenericParameter); + if (const auto *TemplateParam = + dyn_cast<TemplateTypeParmDecl>(ParameterArray[i])) { + if (TemplateParam->hasTypeConstraint()) + Fragments.append(TemplateParam->getTypeConstraint() + ->getNamedConcept() + ->getName() + .str(), + DeclarationFragments::FragmentKind::TypeIdentifier); + else if (TemplateParam->wasDeclaredWithTypename()) + Fragments.append("typename", + DeclarationFragments::FragmentKind::Keyword); + else + Fragments.append("class", DeclarationFragments::FragmentKind::Keyword); + + if (TemplateParam->isParameterPack()) + Fragments.append("...", DeclarationFragments::FragmentKind::Text); + + if (!TemplateParam->getName().empty()) + Fragments.appendSpace().append( + TemplateParam->getName(), + DeclarationFragments::FragmentKind::GenericParameter); + + if (TemplateParam->hasDefaultArgument()) { + const auto Default = TemplateParam->getDefaultArgument(); + Fragments.append(" = ", DeclarationFragments::FragmentKind::Text) + .append(getFragmentsForTemplateArguments( + {Default.getArgument()}, TemplateParam->getASTContext(), + {Default})); + } + } else if (const auto *NTP = + dyn_cast<NonTypeTemplateParmDecl>(ParameterArray[i])) { + DeclarationFragments After; + const auto TyFragments = + getFragmentsForType(NTP->getType(), NTP->getASTContext(), After); + Fragments.append(std::move(TyFragments)).append(std::move(After)); + + if (NTP->isParameterPack()) + Fragments.append("...", DeclarationFragments::FragmentKind::Text); + + if (!NTP->getName().empty()) + Fragments.appendSpace().append( + NTP->getName(), + DeclarationFragments::FragmentKind::GenericParameter); + + if (NTP->hasDefaultArgument()) { + SmallString<8> ExprStr; + raw_svector_ostream Output(ExprStr); + NTP->getDefaultArgument().getArgument().print( + NTP->getASTContext().getPrintingPolicy(), Output, + /*IncludeType=*/false); + Fragments.append(" = ", DeclarationFragments::FragmentKind::Text) + .append(ExprStr, DeclarationFragments::FragmentKind::Text); + } + } else if (const auto *TTP = + dyn_cast<TemplateTemplateParmDecl>(ParameterArray[i])) { + Fragments.append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() + .append("<", DeclarationFragments::FragmentKind::Text) + .append(getFragmentsForTemplateParameters( + TTP->getTemplateParameters()->asArray())) + .append(">", DeclarationFragments::FragmentKind::Text) + .appendSpace() + .append(TTP->wasDeclaredWithTypename() ? "typename" : "class", + DeclarationFragments::FragmentKind::Keyword); + + if (TTP->isParameterPack()) + Fragments.append("...", DeclarationFragments::FragmentKind::Text); + + if (!TTP->getName().empty()) + Fragments.appendSpace().append( + TTP->getName(), + DeclarationFragments::FragmentKind::GenericParameter); + if (TTP->hasDefaultArgument()) { + const auto Default = TTP->getDefaultArgument(); + Fragments.append(" = ", DeclarationFragments::FragmentKind::Text) + .append(getFragmentsForTemplateArguments( + {Default.getArgument()}, TTP->getASTContext(), {Default})); + } + } } return Fragments; } -// Find the name of a template argument from the template's parameters. -std::string DeclarationFragmentsBuilder::getNameForTemplateArgument( - const ArrayRef<NamedDecl *> TemplateParameters, std::string TypeParameter) { - // The arg is a generic parameter from a partial spec, e.g. - // T in template<typename T> Foo<T, int>. - // - // Those names appear as "type-parameter-<index>-<depth>", so we must find its - // name from the template's parameter list. - for (unsigned i = 0; i < TemplateParameters.size(); ++i) { - const auto *Parameter = - dyn_cast<TemplateTypeParmDecl>(TemplateParameters[i]); - if (TypeParameter.compare("type-parameter-" + - std::to_string(Parameter->getDepth()) + "-" + - std::to_string(Parameter->getIndex())) == 0) - return std::string(TemplateParameters[i]->getName()); - } - llvm_unreachable("Could not find the name of a template argument."); -} - // Get fragments for template arguments, e.g. int in template<typename T> // Foo<int>; // @@ -989,28 +1069,102 @@ std::string DeclarationFragmentsBuilder::getNameForTemplateArgument( DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTemplateArguments( const ArrayRef<TemplateArgument> TemplateArguments, ASTContext &Context, - const std::optional<ArrayRef<NamedDecl *>> TemplateParameters) { + const std::optional<ArrayRef<TemplateArgumentLoc>> TemplateArgumentLocs) { DeclarationFragments Fragments; for (unsigned i = 0, end = TemplateArguments.size(); i != end; ++i) { if (i) Fragments.append(",", DeclarationFragments::FragmentKind::Text) .appendSpace(); - std::string Type = TemplateArguments[i].getAsType().getAsString(); - DeclarationFragments After; - DeclarationFragments ArgumentFragment = - getFragmentsForType(TemplateArguments[i].getAsType(), Context, After); + const auto &CTA = TemplateArguments[i]; + switch (CTA.getKind()) { + case TemplateArgument::Type: { + DeclarationFragments After; + DeclarationFragments ArgumentFragment = + getFragmentsForType(CTA.getAsType(), Context, After); + + if (StringRef(ArgumentFragment.begin()->Spelling) + .starts_with("type-parameter")) { + if (TemplateArgumentLocs.has_value() && + TemplateArgumentLocs->size() > i) { + std::string ProperArgName = TemplateArgumentLocs.value()[i] + .getTypeSourceInfo() + ->getType() + .getAsString(); + ArgumentFragment.begin()->Spelling.swap(ProperArgName); + } else { + auto &Spelling = ArgumentFragment.begin()->Spelling; + Spelling.clear(); + raw_string_ostream OutStream(Spelling); + CTA.print(Context.getPrintingPolicy(), OutStream, false); + OutStream.flush(); + } + } - if (ArgumentFragment.begin()->Spelling.substr(0, 14).compare( - "type-parameter") == 0) { - std::string ProperArgName = getNameForTemplateArgument( - TemplateParameters.value(), ArgumentFragment.begin()->Spelling); - ArgumentFragment.begin()->Spelling.swap(ProperArgName); + Fragments.append(std::move(ArgumentFragment)); + break; } - Fragments.append(std::move(ArgumentFragment)); + case TemplateArgument::Declaration: { + const auto *VD = CTA.getAsDecl(); + SmallString<128> USR; + index::generateUSRForDecl(VD, USR); + Fragments.append(VD->getNameAsString(), + DeclarationFragments::FragmentKind::Identifier, USR); + break; + } + case TemplateArgument::NullPtr: + Fragments.append("nullptr", DeclarationFragments::FragmentKind::Keyword); + break; - if (TemplateArguments[i].isPackExpansion()) - Fragments.append("...", DeclarationFragments::FragmentKind::Text); + case TemplateArgument::Integral: { + SmallString<4> Str; + CTA.getAsIntegral().toString(Str); + Fragments.append(Str, DeclarationFragments::FragmentKind::Text); + break; + } + + case TemplateArgument::StructuralValue: { + const auto SVTy = CTA.getStructuralValueType(); + Fragments.append(CTA.getAsStructuralValue().getAsString(Context, SVTy), + DeclarationFragments::FragmentKind::Text); + break; + } + + case TemplateArgument::TemplateExpansion: + case TemplateArgument::Template: { + std::string Str; + raw_string_ostream Stream(Str); + CTA.getAsTemplate().print(Stream, Context.getPrintingPolicy()); + SmallString<64> USR(""); + if (const auto *TemplDecl = + CTA.getAsTemplateOrTemplatePattern().getAsTemplateDecl()) + index::generateUSRForDecl(TemplDecl, USR); + Fragments.append(Str, DeclarationFragments::FragmentKind::TypeIdentifier, + USR); + if (CTA.getKind() == TemplateArgument::TemplateExpansion) + Fragments.append("...", DeclarationFragments::FragmentKind::Text); + break; + } + + case TemplateArgument::Pack: + Fragments.append("<", DeclarationFragments::FragmentKind::Text) + .append(getFragmentsForTemplateArguments(CTA.pack_elements(), Context, + {})) + .append(">", DeclarationFragments::FragmentKind::Text); + break; + + case TemplateArgument::Expression: { + SmallString<8> ExprStr; + raw_svector_ostream Output(ExprStr); + CTA.getAsExpr()->printPretty(Output, nullptr, + Context.getPrintingPolicy()); + Fragments.append(ExprStr, DeclarationFragments::FragmentKind::Text); + break; + } + + case TemplateArgument::Null: + break; + } } return Fragments; } @@ -1020,15 +1174,17 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateParameters( Concept->getTemplateParameters()->asArray())) .append("> ", DeclarationFragments::FragmentKind::Text) + .appendSpace() .append("concept", DeclarationFragments::FragmentKind::Keyword) .appendSpace() .append(Concept->getName().str(), DeclarationFragments::FragmentKind::Identifier) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1036,6 +1192,7 @@ DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate( const RedeclarableTemplateDecl *RedeclarableTemplate) { DeclarationFragments Fragments; Fragments.append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateParameters( RedeclarableTemplate->getTemplateParameters()->asArray())) @@ -1058,6 +1215,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) .append(">", DeclarationFragments::FragmentKind::Text) .appendSpace() @@ -1065,11 +1223,11 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( cast<CXXRecordDecl>(Decl))) .pop_back() // there is an extra semicolon now .append("<", DeclarationFragments::FragmentKind::Text) - .append( - getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), - Decl->getASTContext(), std::nullopt)) + .append(getFragmentsForTemplateArguments( + Decl->getTemplateArgs().asArray(), Decl->getASTContext(), + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1078,6 +1236,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateParameters( Decl->getTemplateParameters()->asArray())) @@ -1089,9 +1248,9 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization( .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateArguments( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), - Decl->getTemplateParameters()->asArray())) + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1100,17 +1259,18 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) .append(">", DeclarationFragments::FragmentKind::Text) .appendSpace() .append(DeclarationFragmentsBuilder::getFragmentsForVarTemplate(Decl)) .pop_back() // there is an extra semicolon now .append("<", DeclarationFragments::FragmentKind::Text) - .append( - getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), - Decl->getASTContext(), std::nullopt)) + .append(getFragmentsForTemplateArguments( + Decl->getTemplateArgs().asArray(), Decl->getASTContext(), + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1119,6 +1279,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) // Partial specs may have new params. .append(getFragmentsForTemplateParameters( @@ -1130,9 +1291,9 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization( .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateArguments( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), - Decl->getTemplateParameters()->asArray())) + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1141,6 +1302,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<", DeclarationFragments::FragmentKind::Text) // Partial specs may have new params. .append(getFragmentsForTemplateParameters( @@ -1157,6 +1319,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunctionTemplateSpecialization( DeclarationFragments Fragments; return Fragments .append("template", DeclarationFragments::FragmentKind::Keyword) + .appendSpace() .append("<>", DeclarationFragments::FragmentKind::Text) .appendSpace() .append(DeclarationFragmentsBuilder::getFragmentsForFunction(Decl)); @@ -1203,7 +1366,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory( Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) .appendSpace() - .append(Category->getClassInterface()->getName(), + .append(Interface->getName(), DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR, Interface) .append(" (", DeclarationFragments::FragmentKind::Text) @@ -1277,7 +1440,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( Fragments.append(getFragmentsForParam(Param)); } - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( @@ -1378,7 +1541,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( .append(Property->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( @@ -1422,7 +1585,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef( .appendSpace() .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } // Instantiate template for FunctionDecl. @@ -1448,9 +1611,12 @@ DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) { cast<CXXMethodDecl>(Decl)->isOverloadedOperator()) { Fragments.append(Decl->getNameAsString(), DeclarationFragments::FragmentKind::Identifier); - } else if (!Decl->getName().empty()) + } else if (Decl->getIdentifier()) { Fragments.append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); + } else + Fragments.append(Decl->getDeclName().getAsString(), + DeclarationFragments::FragmentKind::Identifier); return Fragments; } diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index fd62d841197d..d6335854cbf2 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -30,6 +30,8 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Index/USRGeneration.h" +#include "clang/InstallAPI/HeaderFile.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" @@ -38,6 +40,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -61,9 +64,6 @@ std::optional<std::string> getRelativeIncludeName(const CompilerInstance &CI, "CompilerInstance does not have a FileNamager!"); using namespace llvm::sys; - // Matches framework include patterns - const llvm::Regex Rule("/(.+)\\.framework/(.+)?Headers/(.+)"); - const auto &FS = CI.getVirtualFileSystem(); SmallString<128> FilePath(File.begin(), File.end()); @@ -147,7 +147,8 @@ std::optional<std::string> getRelativeIncludeName(const CompilerInstance &CI, // include name `<Framework/Header.h>` if (Entry.IsFramework) { SmallVector<StringRef, 4> Matches; - Rule.match(File, &Matches); + clang::installapi::HeaderFile::getFrameworkIncludeRule().match( + File, &Matches); // Returned matches are always in stable order. if (Matches.size() != 4) return std::nullopt; @@ -328,11 +329,12 @@ public: StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); - StringRef USR = - API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); + SmallString<128> USR; + index::generateUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM, + USR); - API.addMacroDefinition( - Name, USR, Loc, + API.createRecord<extractapi::MacroDefinitionRecord>( + USR, Name, SymbolReference(), Loc, DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), DeclarationFragmentsBuilder::getSubHeadingForMacro(Name), SM.isInSystemHeader(PM.MacroNameToken.getLocation())); @@ -373,40 +375,57 @@ private: LocationFileChecker &LCF; }; +std::unique_ptr<llvm::raw_pwrite_stream> +createAdditionalSymbolGraphFile(CompilerInstance &CI, Twine BaseName) { + auto OutputDirectory = CI.getFrontendOpts().SymbolGraphOutputDir; + + SmallString<256> FileName; + llvm::sys::path::append(FileName, OutputDirectory, + BaseName + ".symbols.json"); + return CI.createOutputFile( + FileName, /*Binary*/ false, /*RemoveFileOnSignal*/ false, + /*UseTemporary*/ true, /*CreateMissingDirectories*/ true); +} + } // namespace -void ExtractAPIActionBase::ImplEndSourceFileAction() { - if (!OS) - return; +void ExtractAPIActionBase::ImplEndSourceFileAction(CompilerInstance &CI) { + SymbolGraphSerializerOption SerializationOptions; + SerializationOptions.Compact = !CI.getFrontendOpts().EmitPrettySymbolGraphs; + SerializationOptions.EmitSymbolLabelsForTesting = + CI.getFrontendOpts().EmitSymbolGraphSymbolLabelsForTesting; + + if (CI.getFrontendOpts().EmitExtensionSymbolGraphs) { + auto ConstructOutputFile = [&CI](Twine BaseName) { + return createAdditionalSymbolGraphFile(CI, BaseName); + }; + + SymbolGraphSerializer::serializeWithExtensionGraphs( + *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions); + } else { + SymbolGraphSerializer::serializeMainSymbolGraph(*OS, *API, IgnoresList, + SerializationOptions); + } - // Setup a SymbolGraphSerializer to write out collected API information in - // the Symbol Graph format. - // FIXME: Make the kind of APISerializer configurable. - SymbolGraphSerializer SGSerializer(*API, IgnoresList); - SGSerializer.serialize(*OS); + // Flush the stream and close the main output stream. OS.reset(); } -std::unique_ptr<raw_pwrite_stream> -ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { - std::unique_ptr<raw_pwrite_stream> OS; - OS = CI.createDefaultOutputFile(/*Binary=*/false, InFile, - /*Extension=*/"json", - /*RemoveFileOnSignal=*/false); - if (!OS) - return nullptr; - return OS; -} - std::unique_ptr<ASTConsumer> ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - OS = CreateOutputFile(CI, InFile); + auto ProductName = CI.getFrontendOpts().ProductName; + + if (CI.getFrontendOpts().SymbolGraphOutputDir.empty()) + OS = CI.createDefaultOutputFile(/*Binary*/ false, InFile, + /*Extension*/ "symbols.json", + /*RemoveFileOnSignal*/ false, + /*CreateMissingDirectories*/ true); + else + OS = createAdditionalSymbolGraphFile(CI, ProductName); if (!OS) return nullptr; - auto ProductName = CI.getFrontendOpts().ProductName; - // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. API = std::make_unique<APISet>( @@ -496,7 +515,9 @@ bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { return true; } -void ExtractAPIAction::EndSourceFileAction() { ImplEndSourceFileAction(); } +void ExtractAPIAction::EndSourceFileAction() { + ImplEndSourceFileAction(getCompilerInstance()); +} std::unique_ptr<ASTConsumer> WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, @@ -507,11 +528,9 @@ WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, CreatedASTConsumer = true; - OS = CreateOutputFile(CI, InFile); - if (!OS) - return nullptr; - - auto ProductName = CI.getFrontendOpts().ProductName; + ProductName = CI.getFrontendOpts().ProductName; + auto InputFilename = llvm::sys::path::filename(InFile); + OS = createAdditionalSymbolGraphFile(CI, InputFilename); // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. @@ -553,32 +572,6 @@ void WrappingExtractAPIAction::EndSourceFileAction() { WrapperFrontendAction::EndSourceFileAction(); if (CreatedASTConsumer) { - ImplEndSourceFileAction(); + ImplEndSourceFileAction(getCompilerInstance()); } } - -std::unique_ptr<raw_pwrite_stream> -WrappingExtractAPIAction::CreateOutputFile(CompilerInstance &CI, - StringRef InFile) { - std::unique_ptr<raw_pwrite_stream> OS; - std::string OutputDir = CI.getFrontendOpts().SymbolGraphOutputDir; - - // The symbol graphs need to be generated as a side effect of regular - // compilation so the output should be dumped in the directory provided with - // the command line option. - llvm::SmallString<128> OutFilePath(OutputDir); - auto Seperator = llvm::sys::path::get_separator(); - auto Infilename = llvm::sys::path::filename(InFile); - OutFilePath.append({Seperator, Infilename}); - llvm::sys::path::replace_extension(OutFilePath, "json"); - // StringRef outputFilePathref = *OutFilePath; - - // don't use the default output file - OS = CI.createOutputFile(/*OutputPath=*/OutFilePath, /*Binary=*/false, - /*RemoveFileOnSignal=*/true, - /*UseTemporary=*/true, - /*CreateMissingDirectories=*/true); - if (!OS) - return nullptr; - return OS; -} diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 349b93e2a232..6e56ee5b573f 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -14,45 +14,49 @@ #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Version.h" +#include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/DeclarationFragments.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" +#include <iterator> #include <optional> #include <type_traits> using namespace clang; using namespace clang::extractapi; using namespace llvm; -using namespace llvm::json; namespace { /// Helper function to inject a JSON object \p Obj into another object \p Paren /// at position \p Key. -void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) { +void serializeObject(Object &Paren, StringRef Key, + std::optional<Object> &&Obj) { if (Obj) Paren[Key] = std::move(*Obj); } -/// Helper function to inject a StringRef \p String into an object \p Paren at -/// position \p Key -void serializeString(Object &Paren, StringRef Key, - std::optional<std::string> String) { - if (String) - Paren[Key] = std::move(*String); -} - /// Helper function to inject a JSON array \p Array into object \p Paren at /// position \p Key. -void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) { +void serializeArray(Object &Paren, StringRef Key, + std::optional<Array> &&Array) { if (Array) Paren[Key] = std::move(*Array); } +/// Helper function to inject a JSON array composed of the values in \p C into +/// object \p Paren at position \p Key. +template <typename ContainerTy> +void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { + Paren[Key] = Array(C); +} + /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version /// format. /// @@ -159,27 +163,29 @@ std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) { if (Avail.isDefault()) return std::nullopt; - Object Availability; Array AvailabilityArray; - Availability["domain"] = Avail.Domain; - serializeObject(Availability, "introduced", - serializeSemanticVersion(Avail.Introduced)); - serializeObject(Availability, "deprecated", - serializeSemanticVersion(Avail.Deprecated)); - serializeObject(Availability, "obsoleted", - serializeSemanticVersion(Avail.Obsoleted)); + if (Avail.isUnconditionallyDeprecated()) { Object UnconditionallyDeprecated; UnconditionallyDeprecated["domain"] = "*"; UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); } - if (Avail.isUnconditionallyUnavailable()) { - Object UnconditionallyUnavailable; - UnconditionallyUnavailable["domain"] = "*"; - UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true; - AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable)); + Object Availability; + + Availability["domain"] = Avail.Domain; + + if (Avail.isUnavailable()) { + Availability["isUnconditionallyUnavailable"] = true; + } else { + serializeObject(Availability, "introduced", + serializeSemanticVersion(Avail.Introduced)); + serializeObject(Availability, "deprecated", + serializeSemanticVersion(Avail.Deprecated)); + serializeObject(Availability, "obsoleted", + serializeSemanticVersion(Avail.Obsoleted)); } + AvailabilityArray.emplace_back(std::move(Availability)); return AvailabilityArray; } @@ -208,6 +214,7 @@ StringRef getLanguageName(Language Lang) { case Language::Unknown: case Language::Asm: case Language::LLVM_IR: + case Language::CIR: llvm_unreachable("Unsupported language kind"); } @@ -247,6 +254,7 @@ std::optional<Object> serializeDocComment(const DocComment &Comment) { return std::nullopt; Object DocComment; + Array LinesArray; for (const auto &CommentLine : Comment) { Object Line; @@ -255,7 +263,8 @@ std::optional<Object> serializeDocComment(const DocComment &Comment) { serializeSourceRange(CommentLine.Begin, CommentLine.End)); LinesArray.emplace_back(std::move(Line)); } - serializeArray(DocComment, "lines", LinesArray); + + serializeArray(DocComment, "lines", std::move(LinesArray)); return DocComment; } @@ -321,19 +330,14 @@ serializeDeclarationFragments(const DeclarationFragments &DF) { /// - \c subHeading : An array of declaration fragments that provides tags, /// and potentially more tokens (for example the \c +/- symbol for /// Objective-C methods). Can be used as sub-headings for documentation. -Object serializeNames(const APIRecord &Record) { +Object serializeNames(const APIRecord *Record) { Object Names; - if (auto *CategoryRecord = - dyn_cast_or_null<const ObjCCategoryRecord>(&Record)) - Names["title"] = - (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); - else - Names["title"] = Record.Name; + Names["title"] = Record->Name; serializeArray(Names, "subHeading", - serializeDeclarationFragments(Record.SubHeading)); + serializeDeclarationFragments(Record->SubHeading)); DeclarationFragments NavigatorFragments; - NavigatorFragments.append(Record.Name, + NavigatorFragments.append(Record->Name, DeclarationFragments::FragmentKind::Identifier, /*PreciseIdentifier*/ ""); serializeArray(Names, "navigator", @@ -350,7 +354,8 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Object Kind; switch (RK) { case APIRecord::RK_Unknown: - llvm_unreachable("Records should have an explicit kind"); + Kind["identifier"] = AddLangPrefix("unknown"); + Kind["displayName"] = "Unknown"; break; case APIRecord::RK_Namespace: Kind["identifier"] = AddLangPrefix("namespace"); @@ -483,10 +488,6 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("class.extension"); Kind["displayName"] = "Class Extension"; break; - case APIRecord::RK_ObjCCategoryModule: - Kind["identifier"] = AddLangPrefix("module.extension"); - Kind["displayName"] = "Module Extension"; - break; case APIRecord::RK_ObjCProtocol: Kind["identifier"] = AddLangPrefix("protocol"); Kind["displayName"] = "Protocol"; @@ -499,6 +500,8 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("typealias"); Kind["displayName"] = "Type Alias"; break; + default: + llvm_unreachable("API Record with uninstantiable kind"); } return Kind; @@ -510,15 +513,21 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { /// which is prefixed by the source language name, useful for tooling to parse /// the kind, and a \c displayName for rendering human-readable names. Object serializeSymbolKind(const APIRecord &Record, Language Lang) { - return serializeSymbolKind(Record.getKind(), Lang); + return serializeSymbolKind(Record.KindForDisplay, Lang); } +/// Serialize the function signature field, as specified by the +/// Symbol Graph format. +/// +/// The Symbol Graph function signature property contains two arrays. +/// - The \c returns array is the declaration fragments of the return type; +/// - The \c parameters array contains names and declaration fragments of the +/// parameters. template <typename RecordTy> -std::optional<Object> -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { +void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { const auto &FS = Record.Signature; if (FS.empty()) - return std::nullopt; + return; Object Signature; serializeArray(Signature, "returns", @@ -536,63 +545,14 @@ serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { if (!Parameters.empty()) Signature["parameters"] = std::move(Parameters); - return Signature; + serializeObject(Paren, "functionSignature", std::move(Signature)); } template <typename RecordTy> -std::optional<Object> -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { - return std::nullopt; -} - -/// Serialize the function signature field, as specified by the -/// Symbol Graph format. -/// -/// The Symbol Graph function signature property contains two arrays. -/// - The \c returns array is the declaration fragments of the return type; -/// - The \c parameters array contains names and declaration fragments of the -/// parameters. -/// -/// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the -/// formatted function signature. -template <typename RecordTy> -void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "functionSignature", - serializeFunctionSignatureMixinImpl( - Record, has_function_signature<RecordTy>())); -} - -template <typename RecordTy> -std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, - std::true_type) { - const auto &AccessControl = Record.Access; - std::string Access; - if (AccessControl.empty()) - return std::nullopt; - Access = AccessControl.getAccess(); - return Access; -} - -template <typename RecordTy> -std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, - std::false_type) { - return std::nullopt; -} - -template <typename RecordTy> -void serializeAccessMixin(Object &Paren, const RecordTy &Record) { - auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>()); - if (!accessLevel.has_value()) - accessLevel = "public"; - serializeString(Paren, "accessLevel", accessLevel); -} - -template <typename RecordTy> -std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, - std::true_type) { +void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { const auto &Template = Record.Templ; if (Template.empty()) - return std::nullopt; + return; Object Generics; Array GenericParameters; @@ -618,97 +578,66 @@ std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, if (!GenericConstraints.empty()) Generics["constraints"] = std::move(GenericConstraints); - return Generics; + serializeObject(Paren, "swiftGenerics", Generics); } -template <typename RecordTy> -std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, - std::false_type) { - return std::nullopt; -} - -template <typename RecordTy> -void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "swiftGenerics", - serializeTemplateMixinImpl(Record, has_template<RecordTy>())); -} +Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents, + Language Lang) { + Array ParentContexts; -struct PathComponent { - StringRef USR; - StringRef Name; - APIRecord::RecordKind Kind; + for (const auto &Parent : Parents) { + Object Elem; + Elem["usr"] = Parent.USR; + Elem["name"] = Parent.Name; + if (Parent.Record) + Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay, + Lang)["identifier"]; + else + Elem["kind"] = + serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; + ParentContexts.emplace_back(std::move(Elem)); + } - PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) - : USR(USR), Name(Name), Kind(Kind) {} -}; + return ParentContexts; +} -template <typename RecordTy> -bool generatePathComponents( - const RecordTy &Record, const APISet &API, - function_ref<void(const PathComponent &)> ComponentTransformer) { - SmallVector<PathComponent, 4> ReverseComponenents; - ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); - const auto *CurrentParent = &Record.ParentInformation; - bool FailedToFindParent = false; - while (CurrentParent && !CurrentParent->empty()) { - PathComponent CurrentParentComponent(CurrentParent->ParentUSR, - CurrentParent->ParentName, - CurrentParent->ParentKind); - - auto *ParentRecord = CurrentParent->ParentRecord; - // Slow path if we don't have a direct reference to the ParentRecord - if (!ParentRecord) - ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); - - // If the parent is a category extended from internal module then we need to - // pretend this belongs to the associated interface. - if (auto *CategoryRecord = - dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { - if (!CategoryRecord->IsFromExternalModule) { - ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); - CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, - CategoryRecord->Interface.Name, - APIRecord::RK_ObjCInterface); - } - } - - // The parent record doesn't exist which means the symbol shouldn't be - // treated as part of the current product. - if (!ParentRecord) { - FailedToFindParent = true; - break; - } - - ReverseComponenents.push_back(std::move(CurrentParentComponent)); - CurrentParent = &ParentRecord->ParentInformation; +/// Walk the records parent information in reverse to generate a hierarchy +/// suitable for serialization. +SmallVector<SymbolReference, 8> +generateHierarchyFromRecord(const APIRecord *Record) { + SmallVector<SymbolReference, 8> ReverseHierarchy; + for (const auto *Current = Record; Current != nullptr; + Current = Current->Parent.Record) + ReverseHierarchy.emplace_back(Current); + + return SmallVector<SymbolReference, 8>( + std::make_move_iterator(ReverseHierarchy.rbegin()), + std::make_move_iterator(ReverseHierarchy.rend())); +} + +SymbolReference getHierarchyReference(const APIRecord *Record, + const APISet &API) { + // If the parent is a category extended from internal module then we need to + // pretend this belongs to the associated interface. + if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) { + return CategoryRecord->Interface; + // FIXME: TODO generate path components correctly for categories extending + // an external module. } - for (const auto &PC : reverse(ReverseComponenents)) - ComponentTransformer(PC); - - return FailedToFindParent; + return SymbolReference(Record); } -Object serializeParentContext(const PathComponent &PC, Language Lang) { - Object ParentContextElem; - ParentContextElem["usr"] = PC.USR; - ParentContextElem["name"] = PC.Name; - ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; - return ParentContextElem; -} +} // namespace -template <typename RecordTy> -Array generateParentContexts(const RecordTy &Record, const APISet &API, - Language Lang) { - Array ParentContexts; - generatePathComponents( - Record, API, [Lang, &ParentContexts](const PathComponent &PC) { - ParentContexts.push_back(serializeParentContext(PC, Lang)); - }); +Object *ExtendedModule::addSymbol(Object &&Symbol) { + Symbols.emplace_back(std::move(Symbol)); + return Symbols.back().getAsObject(); +} - return ParentContexts; +void ExtendedModule::addRelationship(Object &&Relationship) { + Relationships.emplace_back(std::move(Relationship)); } -} // namespace /// Defines the format version emitted by SymbolGraphSerializer. const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; @@ -721,84 +650,52 @@ Object SymbolGraphSerializer::serializeMetadata() const { return Metadata; } -Object SymbolGraphSerializer::serializeModule() const { +Object +SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { Object Module; - // The user is expected to always pass `--product-name=` on the command line - // to populate this field. - Module["name"] = API.ProductName; + Module["name"] = ModuleName; serializeObject(Module, "platform", serializePlatform(API.getTarget())); return Module; } -bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { - // Skip explicitly ignored symbols. - if (IgnoresList.shouldIgnore(Record.Name)) +bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { + if (!Record) return true; // Skip unconditionally unavailable symbols - if (Record.Availability.isUnconditionallyUnavailable()) + if (Record->Availability.isUnconditionallyUnavailable()) return true; + // Filter out symbols without a name as we can generate correct symbol graphs + // for them. In practice these are anonymous record types that aren't attached + // to a declaration. + if (auto *Tag = dyn_cast<TagRecord>(Record)) { + if (Tag->IsEmbeddedInVarDeclarator) + return true; + } + // Filter out symbols prefixed with an underscored as they are understood to // be symbols clients should not use. - if (Record.Name.starts_with("_")) + if (Record->Name.starts_with("_")) + return true; + + // Skip explicitly ignored symbols. + if (IgnoresList.shouldIgnore(Record->Name)) return true; return false; } -template <typename RecordTy> -std::optional<Object> -SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { - if (shouldSkip(Record)) - return std::nullopt; +ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { + if (!ForceEmitToMainModule && ModuleForCurrentSymbol) + return *ModuleForCurrentSymbol; - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); - serializeObject(Obj, "names", serializeNames(Record)); - serializeObject( - Obj, "location", - serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); - serializeArray(Obj, "availability", - serializeAvailability(Record.Availability)); - serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); - serializeArray(Obj, "declarationFragments", - serializeDeclarationFragments(Record.Declaration)); - SmallVector<StringRef, 4> PathComponentsNames; - // If this returns true it indicates that we couldn't find a symbol in the - // hierarchy. - if (generatePathComponents(Record, API, - [&PathComponentsNames](const PathComponent &PC) { - PathComponentsNames.push_back(PC.Name); - })) - return {}; - - serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); - - serializeFunctionSignatureMixin(Obj, Record); - serializeAccessMixin(Obj, Record); - serializeTemplateMixin(Obj, Record); - - return Obj; + return MainModule; } -template <typename MemberTy> -void SymbolGraphSerializer::serializeMembers( - const APIRecord &Record, - const SmallVector<std::unique_ptr<MemberTy>> &Members) { - // Members should not be serialized if we aren't recursing. - if (!ShouldRecurse) - return; - for (const auto &Member : Members) { - auto MemberRecord = serializeAPIRecord(*Member); - if (!MemberRecord) - continue; - - Symbols.emplace_back(std::move(*MemberRecord)); - serializeRelationship(RelationshipKind::MemberOf, *Member, Record); - } +Array SymbolGraphSerializer::serializePathComponents( + const APIRecord *Record) const { + return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); } StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { @@ -815,6 +712,33 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { llvm_unreachable("Unhandled relationship kind"); } +void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, + const SymbolReference &Source, + const SymbolReference &Target, + ExtendedModule &Into) { + Object Relationship; + SmallString<64> TestRelLabel; + if (EmitSymbolLabelsForTesting) { + llvm::raw_svector_ostream OS(TestRelLabel); + OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " + << Source.USR << " $ "; + if (Target.USR.empty()) + OS << Target.Name; + else + OS << Target.USR; + Relationship["!testRelLabel"] = TestRelLabel; + } + Relationship["source"] = Source.USR; + Relationship["target"] = Target.USR; + Relationship["targetFallback"] = Target.Name; + Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); + + if (ForceEmitToMainModule) + MainModule.addRelationship(std::move(Relationship)); + else + Into.addRelationship(std::move(Relationship)); +} + StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { switch (Kind) { case ConstraintKind::Conformance: @@ -825,430 +749,331 @@ StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { llvm_unreachable("Unhandled constraint kind"); } -void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, - SymbolReference Source, - SymbolReference Target) { - Object Relationship; - Relationship["source"] = Source.USR; - Relationship["target"] = Target.USR; - Relationship["targetFallback"] = Target.Name; - Relationship["kind"] = getRelationshipString(Kind); - - Relationships.emplace_back(std::move(Relationship)); -} +void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { + Object Obj; -void SymbolGraphSerializer::visitNamespaceRecord( - const NamespaceRecord &Record) { - auto Namespace = serializeAPIRecord(Record); - if (!Namespace) - return; - Symbols.emplace_back(std::move(*Namespace)); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} + // If we need symbol labels for testing emit the USR as the value and the key + // starts with '!'' to ensure it ends up at the top of the object. + if (EmitSymbolLabelsForTesting) + Obj["!testLabel"] = Record->USR; -void SymbolGraphSerializer::visitGlobalFunctionRecord( - const GlobalFunctionRecord &Record) { - auto Obj = serializeAPIRecord(Record); - if (!Obj) - return; + serializeObject(Obj, "identifier", + serializeIdentifier(*Record, API.getLanguage())); + serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); + serializeObject(Obj, "names", serializeNames(Record)); + serializeObject( + Obj, "location", + serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); + serializeArray(Obj, "availability", + serializeAvailability(Record->Availability)); + serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); + serializeArray(Obj, "declarationFragments", + serializeDeclarationFragments(Record->Declaration)); - Symbols.emplace_back(std::move(*Obj)); -} + Obj["pathComponents"] = serializePathComponents(Record); + Obj["accessLevel"] = Record->Access.getAccess(); -void SymbolGraphSerializer::visitGlobalVariableRecord( - const GlobalVariableRecord &Record) { - auto Obj = serializeAPIRecord(Record); - if (!Obj) - return; + ExtendedModule &Module = getModuleForCurrentSymbol(); + // If the hierarchy has at least one parent and child. + if (Hierarchy.size() >= 2) + serializeRelationship(MemberOf, Hierarchy.back(), + Hierarchy[Hierarchy.size() - 2], Module); - Symbols.emplace_back(std::move(*Obj)); + CurrentSymbol = Module.addSymbol(std::move(Obj)); } -void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { - auto Enum = serializeAPIRecord(Record); - if (!Enum) - return; - - Symbols.emplace_back(std::move(*Enum)); - serializeMembers(Record, Record.Constants); +bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { + if (!Record) + return true; + if (shouldSkip(Record)) + return true; + Hierarchy.push_back(getHierarchyReference(Record, API)); + // Defer traversal mechanics to APISetVisitor base implementation + auto RetVal = Base::traverseAPIRecord(Record); + Hierarchy.pop_back(); + return RetVal; } -void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) { - auto SerializedRecord = serializeAPIRecord(Record); - if (!SerializedRecord) - return; - - Symbols.emplace_back(std::move(*SerializedRecord)); - serializeMembers(Record, Record.Fields); +bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { + serializeAPIRecord(Record); + return true; } -void SymbolGraphSerializer::visitStaticFieldRecord( - const StaticFieldRecord &Record) { - auto StaticField = serializeAPIRecord(Record); - if (!StaticField) - return; - Symbols.emplace_back(std::move(*StaticField)); - serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); +bool SymbolGraphSerializer::visitGlobalFunctionRecord( + const GlobalFunctionRecord *Record) { + if (!CurrentSymbol) + return true; + + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; +bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Class)); - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + for (const auto &Base : Record->Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, + getModuleForCurrentSymbol()); + return true; } -void SymbolGraphSerializer::visitClassTemplateRecord( - const ClassTemplateRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; +bool SymbolGraphSerializer::visitClassTemplateRecord( + const ClassTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Class)); - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( - const ClassTemplateSpecializationRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; - - Symbols.emplace_back(std::move(*Class)); +bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord *Record) { + if (!CurrentSymbol) + return true; - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; - - Symbols.emplace_back(std::move(*Class)); +bool SymbolGraphSerializer::visitCXXMethodRecord( + const CXXMethodRecord *Record) { + if (!CurrentSymbol) + return true; - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXInstanceMethodRecord( - const CXXInstanceMethodRecord &Record) { - auto InstanceMethod = serializeAPIRecord(Record); - if (!InstanceMethod) - return; +bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( + const CXXMethodTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*InstanceMethod)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXStaticMethodRecord( - const CXXStaticMethodRecord &Record) { - auto StaticMethod = serializeAPIRecord(Record); - if (!StaticMethod) - return; +bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( + const CXXFieldTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*StaticMethod)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitMethodTemplateRecord( - const CXXMethodTemplateRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto MethodTemplate = serializeAPIRecord(Record); - if (!MethodTemplate) - return; - Symbols.emplace_back(std::move(*MethodTemplate)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} +bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( - const CXXMethodTemplateSpecializationRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto MethodTemplateSpecialization = serializeAPIRecord(Record); - if (!MethodTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { - if (!ShouldRecurse) - return; - auto CXXField = serializeAPIRecord(Record); - if (!CXXField) - return; - Symbols.emplace_back(std::move(*CXXField)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} +bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitCXXFieldTemplateRecord( - const CXXFieldTemplateRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto CXXFieldTemplate = serializeAPIRecord(Record); - if (!CXXFieldTemplate) - return; - Symbols.emplace_back(std::move(*CXXFieldTemplate)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { - auto Concept = serializeAPIRecord(Record); - if (!Concept) - return; +bool SymbolGraphSerializer:: + visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Concept)); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( - const GlobalVariableTemplateRecord &Record) { - auto GlobalVariableTemplate = serializeAPIRecord(Record); - if (!GlobalVariableTemplate) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplate)); -} +bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( - const GlobalVariableTemplateSpecializationRecord &Record) { - auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); - if (!GlobalVariableTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer:: - visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord &Record) { - auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); - if (!GlobalVariableTemplatePartialSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); -} +bool SymbolGraphSerializer::visitObjCContainerRecord( + const ObjCContainerRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( - const GlobalFunctionTemplateRecord &Record) { - auto GlobalFunctionTemplate = serializeAPIRecord(Record); - if (!GlobalFunctionTemplate) - return; - Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); -} + for (const auto &Protocol : Record->Protocols) + serializeRelationship(ConformsTo, Record, Protocol, + getModuleForCurrentSymbol()); -void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( - const GlobalFunctionTemplateSpecializationRecord &Record) { - auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); - if (!GlobalFunctionTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); + return true; } -void SymbolGraphSerializer::visitObjCContainerRecord( - const ObjCContainerRecord &Record) { - auto ObjCContainer = serializeAPIRecord(Record); - if (!ObjCContainer) - return; +bool SymbolGraphSerializer::visitObjCInterfaceRecord( + const ObjCInterfaceRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*ObjCContainer)); - - serializeMembers(Record, Record.Ivars); - serializeMembers(Record, Record.Methods); - serializeMembers(Record, Record.Properties); - - for (const auto &Protocol : Record.Protocols) - // Record that Record conforms to Protocol. - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); - - if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { - if (!ObjCInterface->SuperClass.empty()) - // If Record is an Objective-C interface record and it has a super class, - // record that Record is inherited from SuperClass. - serializeRelationship(RelationshipKind::InheritsFrom, Record, - ObjCInterface->SuperClass); - - // Members of categories extending an interface are serialized as members of - // the interface. - for (const auto *Category : ObjCInterface->Categories) { - serializeMembers(Record, Category->Ivars); - serializeMembers(Record, Category->Methods); - serializeMembers(Record, Category->Properties); - - // Surface the protocols of the category to the interface. - for (const auto &Protocol : Category->Protocols) - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); - } - } + if (!Record->SuperClass.empty()) + serializeRelationship(InheritsFrom, Record, Record->SuperClass, + getModuleForCurrentSymbol()); + return true; } -void SymbolGraphSerializer::visitObjCCategoryRecord( - const ObjCCategoryRecord &Record) { - if (!Record.IsFromExternalModule) - return; +bool SymbolGraphSerializer::traverseObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + if (SkipSymbolsInCategoriesToExternalTypes && + !API.findRecordForUSR(Record->Interface.USR)) + return true; - // Check if the current Category' parent has been visited before, if so skip. - if (!visitedCategories.contains(Record.Interface.Name)) { - visitedCategories.insert(Record.Interface.Name); - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject(Obj, "kind", - serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, - API.getLanguage())); - Obj["accessLevel"] = "public"; - Symbols.emplace_back(std::move(Obj)); - } + auto *CurrentModule = ModuleForCurrentSymbol; + if (Record->isExtendingExternalModule()) + ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; - Object Relationship; - Relationship["source"] = Record.USR; - Relationship["target"] = Record.Interface.USR; - Relationship["targetFallback"] = Record.Interface.Name; - Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); - Relationships.emplace_back(std::move(Relationship)); + if (!walkUpFromObjCCategoryRecord(Record)) + return false; - auto ObjCCategory = serializeAPIRecord(Record); + bool RetVal = traverseRecordContext(Record); + ModuleForCurrentSymbol = CurrentModule; + return RetVal; +} - if (!ObjCCategory) - return; +bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + return visitObjCCategoryRecord(Record); +} - Symbols.emplace_back(std::move(*ObjCCategory)); - serializeMembers(Record, Record.Methods); - serializeMembers(Record, Record.Properties); +bool SymbolGraphSerializer::visitObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + // If we need to create a record for the category in the future do so here, + // otherwise everything is set up to pretend that the category is in fact the + // interface it extends. + for (const auto &Protocol : Record->Protocols) + serializeRelationship(ConformsTo, Record->Interface, Protocol, + getModuleForCurrentSymbol()); - // Surface the protocols of the category to the interface. - for (const auto &Protocol : Record.Protocols) - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); + return true; } -void SymbolGraphSerializer::visitMacroDefinitionRecord( - const MacroDefinitionRecord &Record) { - auto Macro = serializeAPIRecord(Record); +bool SymbolGraphSerializer::visitObjCMethodRecord( + const ObjCMethodRecord *Record) { + if (!CurrentSymbol) + return true; - if (!Macro) - return; + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; +} - Symbols.emplace_back(std::move(*Macro)); +bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( + const ObjCInstanceVariableRecord *Record) { + // FIXME: serialize ivar access control here. + return true; } -void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { - switch (Record->getKind()) { - case APIRecord::RK_Unknown: - llvm_unreachable("Records should have a known kind!"); - case APIRecord::RK_GlobalFunction: - visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record)); - break; - case APIRecord::RK_GlobalVariable: - visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record)); - break; - case APIRecord::RK_Enum: - visitEnumRecord(*cast<EnumRecord>(Record)); - break; - case APIRecord::RK_Struct: - LLVM_FALLTHROUGH; - case APIRecord::RK_Union: - visitRecordRecord(*cast<RecordRecord>(Record)); - break; - case APIRecord::RK_StaticField: - visitStaticFieldRecord(*cast<StaticFieldRecord>(Record)); - break; - case APIRecord::RK_CXXClass: - visitCXXClassRecord(*cast<CXXClassRecord>(Record)); - break; - case APIRecord::RK_ObjCInterface: - visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record)); - break; - case APIRecord::RK_ObjCProtocol: - visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record)); - break; - case APIRecord::RK_ObjCCategory: - visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record)); - break; - case APIRecord::RK_MacroDefinition: - visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record)); - break; - case APIRecord::RK_Typedef: - visitTypedefRecord(*cast<TypedefRecord>(Record)); - break; - default: - if (auto Obj = serializeAPIRecord(*Record)) { - Symbols.emplace_back(std::move(*Obj)); - auto &ParentInformation = Record->ParentInformation; - if (!ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, *Record, - *ParentInformation.ParentRecord); - } - break; - } +bool SymbolGraphSerializer::walkUpFromTypedefRecord( + const TypedefRecord *Record) { + // Short-circuit walking up the class hierarchy and handle creating typedef + // symbol objects manually as there are additional symbol dropping rules to + // respect. + return visitTypedefRecord(Record); } -void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) { +bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { // Typedefs of anonymous types have their entries unified with the underlying // type. - bool ShouldDrop = Record.UnderlyingType.Name.empty(); + bool ShouldDrop = Record->UnderlyingType.Name.empty(); // enums declared with `NS_OPTION` have a named enum and a named typedef, with // the same name - ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); + ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); if (ShouldDrop) - return; + return true; - auto Typedef = serializeAPIRecord(Record); - if (!Typedef) - return; + // Create the symbol record if the other symbol droppping rules permit it. + serializeAPIRecord(Record); + if (!CurrentSymbol) + return true; - (*Typedef)["type"] = Record.UnderlyingType.USR; + (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; - Symbols.emplace_back(std::move(*Typedef)); + return true; } -Object SymbolGraphSerializer::serialize() { - traverseAPISet(); - return serializeCurrentGraph(); +void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { + switch (Record->getKind()) { + // dispatch to the relevant walkUpFromMethod +#define CONCRETE_RECORD(CLASS, BASE, KIND) \ + case APIRecord::KIND: { \ + walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \ + break; \ + } +#include "clang/ExtractAPI/APIRecords.inc" + // otherwise fallback on the only behavior we can implement safely. + case APIRecord::RK_Unknown: + visitAPIRecord(Record); + break; + default: + llvm_unreachable("API Record with uninstantiable kind"); + } } -Object SymbolGraphSerializer::serializeCurrentGraph() { +Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, + ExtendedModule &&EM) { Object Root; serializeObject(Root, "metadata", serializeMetadata()); - serializeObject(Root, "module", serializeModule()); + serializeObject(Root, "module", serializeModuleObject(ModuleName)); - Root["symbols"] = std::move(Symbols); - Root["relationships"] = std::move(Relationships); + Root["symbols"] = std::move(EM.Symbols); + Root["relationships"] = std::move(EM.Relationships); return Root; } -void SymbolGraphSerializer::serialize(raw_ostream &os) { - Object root = serialize(); +void SymbolGraphSerializer::serializeGraphToStream( + raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, + ExtendedModule &&EM) { + Object Root = serializeGraph(ModuleName, std::move(EM)); if (Options.Compact) - os << formatv("{0}", Value(std::move(root))) << "\n"; + OS << formatv("{0}", json::Value(std::move(Root))) << "\n"; else - os << formatv("{0:2}", Value(std::move(root))) << "\n"; + OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n"; +} + +void SymbolGraphSerializer::serializeMainSymbolGraph( + raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, + SymbolGraphSerializerOption Options) { + SymbolGraphSerializer Serializer( + API, IgnoresList, Options.EmitSymbolLabelsForTesting, + /*ForceEmitToMainModule=*/true, + /*SkipSymbolsInCategoriesToExternalTypes=*/true); + + Serializer.traverseAPISet(); + Serializer.serializeGraphToStream(OS, Options, API.ProductName, + std::move(Serializer.MainModule)); + // FIXME: TODO handle extended modules here +} + +void SymbolGraphSerializer::serializeWithExtensionGraphs( + raw_ostream &MainOutput, const APISet &API, + const APIIgnoresList &IgnoresList, + llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)> + CreateOutputStream, + SymbolGraphSerializerOption Options) { + SymbolGraphSerializer Serializer(API, IgnoresList, + Options.EmitSymbolLabelsForTesting); + Serializer.traverseAPISet(); + + Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, + std::move(Serializer.MainModule)); + + for (auto &ExtensionSGF : Serializer.ExtendedModules) { + if (auto ExtensionOS = + CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) + Serializer.serializeGraphToStream(*ExtensionOS, Options, + ExtensionSGF.getKey(), + std::move(ExtensionSGF.getValue())); + } } std::optional<Object> @@ -1261,14 +1086,20 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object Root; APIIgnoresList EmptyIgnores; SymbolGraphSerializer Serializer(API, EmptyIgnores, - /*Options.Compact*/ {true}, - /*ShouldRecurse*/ false); + /*EmitSymbolLabelsForTesting*/ false, + /*ForceEmitToMainModule*/ true); + + // Set up serializer parent chain + Serializer.Hierarchy = generateHierarchyFromRecord(Record); + Serializer.serializeSingleRecord(Record); - serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); + serializeObject(Root, "symbolGraph", + Serializer.serializeGraph(API.ProductName, + std::move(Serializer.MainModule))); Language Lang = API.getLanguage(); serializeArray(Root, "parentContexts", - generateParentContexts(*Record, API, Lang)); + generateParentContexts(Serializer.Hierarchy, Lang)); Array RelatedSymbols; @@ -1286,14 +1117,15 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object RelatedSymbol; RelatedSymbol["usr"] = RelatedRecord->USR; RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); - // TODO: once we record this properly let's serialize it right. - RelatedSymbol["accessLevel"] = "public"; + RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); RelatedSymbol["moduleName"] = API.ProductName; RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; serializeArray(RelatedSymbol, "parentContexts", - generateParentContexts(*RelatedRecord, API, Lang)); + generateParentContexts( + generateHierarchyFromRecord(RelatedRecord), Lang)); + RelatedSymbols.push_back(std::move(RelatedSymbol)); } diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp index 3a5f62c9b2e6..41e4e0cf1795 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" +#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" using namespace clang; @@ -50,17 +51,20 @@ TypedefUnderlyingTypeResolver::getSymbolReferenceForType(QualType Type, SmallString<128> TypeUSR; const NamedDecl *TypeDecl = getUnderlyingTypeDecl(Type); const TypedefType *TypedefTy = Type->getAs<TypedefType>(); + StringRef OwningModuleName; if (TypeDecl) { if (!TypedefTy) TypeName = TypeDecl->getName().str(); clang::index::generateUSRForDecl(TypeDecl, TypeUSR); + if (auto *OwningModule = TypeDecl->getImportedOwningModule()) + OwningModuleName = OwningModule->Name; } else { clang::index::generateUSRForType(Type, Context, TypeUSR); } - return {API.copyString(TypeName), API.copyString(TypeUSR)}; + return API.createSymbolReference(TypeName, TypeUSR, OwningModuleName); } std::string TypedefUnderlyingTypeResolver::getUSRForType(QualType Type) const { |
