1ffe9f00cSFangrui Song //===-- Serialize.cpp - ClangDoc Serializer ---------------------*- C++ -*-===// 2e975a473SJulie Hockett // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e975a473SJulie Hockett // 7e975a473SJulie Hockett //===----------------------------------------------------------------------===// 8e975a473SJulie Hockett 9e975a473SJulie Hockett #include "Serialize.h" 10e975a473SJulie Hockett #include "BitcodeWriter.h" 11e975a473SJulie Hockett #include "clang/AST/Comment.h" 12e975a473SJulie Hockett #include "clang/Index/USRGeneration.h" 13e191086bSBrett Wilson #include "clang/Lex/Lexer.h" 14e975a473SJulie Hockett #include "llvm/ADT/Hashing.h" 15e975a473SJulie Hockett #include "llvm/ADT/StringExtras.h" 16e975a473SJulie Hockett #include "llvm/Support/SHA1.h" 17e975a473SJulie Hockett 18e975a473SJulie Hockett using clang::comments::FullComment; 19e975a473SJulie Hockett 20e975a473SJulie Hockett namespace clang { 21e975a473SJulie Hockett namespace doc { 22e975a473SJulie Hockett namespace serialize { 23e975a473SJulie Hockett 24e975a473SJulie Hockett SymbolID hashUSR(llvm::StringRef USR) { 25e975a473SJulie Hockett return llvm::SHA1::hash(arrayRefFromStringRef(USR)); 26e975a473SJulie Hockett } 27e975a473SJulie Hockett 282c1c9a24SJulie Hockett template <typename T> 292c1c9a24SJulie Hockett static void 302c1c9a24SJulie Hockett populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces, 312c1c9a24SJulie Hockett const T *D, bool &IsAnonymousNamespace); 322c1c9a24SJulie Hockett 3399baa10fSBrett Wilson static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D); 3499baa10fSBrett Wilson 352c1c9a24SJulie Hockett // A function to extract the appropriate relative path for a given info's 362c1c9a24SJulie Hockett // documentation. The path returned is a composite of the parent namespaces. 372c1c9a24SJulie Hockett // 38b7ecf1c1SKazuaki Ishizaki // Example: Given the below, the directory path for class C info will be 392c1c9a24SJulie Hockett // <root>/A/B 402c1c9a24SJulie Hockett // 412c1c9a24SJulie Hockett // namespace A { 42dd5571d5SKazuaki Ishizaki // namespace B { 432c1c9a24SJulie Hockett // 442c1c9a24SJulie Hockett // class C {}; 452c1c9a24SJulie Hockett // 462c1c9a24SJulie Hockett // } 472c1c9a24SJulie Hockett // } 482c1c9a24SJulie Hockett llvm::SmallString<128> 492c1c9a24SJulie Hockett getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces) { 502c1c9a24SJulie Hockett llvm::SmallString<128> Path; 512c1c9a24SJulie Hockett for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R) 522c1c9a24SJulie Hockett llvm::sys::path::append(Path, R->Name); 532c1c9a24SJulie Hockett return Path; 542c1c9a24SJulie Hockett } 552c1c9a24SJulie Hockett 562c1c9a24SJulie Hockett llvm::SmallString<128> getInfoRelativePath(const Decl *D) { 572c1c9a24SJulie Hockett llvm::SmallVector<Reference, 4> Namespaces; 582c1c9a24SJulie Hockett // The third arg in populateParentNamespaces is a boolean passed by reference, 592c1c9a24SJulie Hockett // its value is not relevant in here so it's not used anywhere besides the 602c1c9a24SJulie Hockett // function call 612c1c9a24SJulie Hockett bool B = true; 622c1c9a24SJulie Hockett populateParentNamespaces(Namespaces, D, B); 632c1c9a24SJulie Hockett return getInfoRelativePath(Namespaces); 642c1c9a24SJulie Hockett } 652c1c9a24SJulie Hockett 66e975a473SJulie Hockett class ClangDocCommentVisitor 67e975a473SJulie Hockett : public ConstCommentVisitor<ClangDocCommentVisitor> { 68e975a473SJulie Hockett public: 69e975a473SJulie Hockett ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {} 70e975a473SJulie Hockett 71e975a473SJulie Hockett void parseComment(const comments::Comment *C); 72e975a473SJulie Hockett 73e975a473SJulie Hockett void visitTextComment(const TextComment *C); 74e975a473SJulie Hockett void visitInlineCommandComment(const InlineCommandComment *C); 75e975a473SJulie Hockett void visitHTMLStartTagComment(const HTMLStartTagComment *C); 76e975a473SJulie Hockett void visitHTMLEndTagComment(const HTMLEndTagComment *C); 77e975a473SJulie Hockett void visitBlockCommandComment(const BlockCommandComment *C); 78e975a473SJulie Hockett void visitParamCommandComment(const ParamCommandComment *C); 79e975a473SJulie Hockett void visitTParamCommandComment(const TParamCommandComment *C); 80e975a473SJulie Hockett void visitVerbatimBlockComment(const VerbatimBlockComment *C); 81e975a473SJulie Hockett void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C); 82e975a473SJulie Hockett void visitVerbatimLineComment(const VerbatimLineComment *C); 83e975a473SJulie Hockett 84e975a473SJulie Hockett private: 85e975a473SJulie Hockett std::string getCommandName(unsigned CommandID) const; 86e975a473SJulie Hockett bool isWhitespaceOnly(StringRef S) const; 87e975a473SJulie Hockett 88e975a473SJulie Hockett CommentInfo &CurrentCI; 89e975a473SJulie Hockett }; 90e975a473SJulie Hockett 91e975a473SJulie Hockett void ClangDocCommentVisitor::parseComment(const comments::Comment *C) { 92e975a473SJulie Hockett CurrentCI.Kind = C->getCommentKindName(); 93e975a473SJulie Hockett ConstCommentVisitor<ClangDocCommentVisitor>::visit(C); 94e975a473SJulie Hockett for (comments::Comment *Child : 95e975a473SJulie Hockett llvm::make_range(C->child_begin(), C->child_end())) { 961c705d9cSJonas Devlieghere CurrentCI.Children.emplace_back(std::make_unique<CommentInfo>()); 97e975a473SJulie Hockett ClangDocCommentVisitor Visitor(*CurrentCI.Children.back()); 98e975a473SJulie Hockett Visitor.parseComment(Child); 99e975a473SJulie Hockett } 100e975a473SJulie Hockett } 101e975a473SJulie Hockett 102e975a473SJulie Hockett void ClangDocCommentVisitor::visitTextComment(const TextComment *C) { 103e975a473SJulie Hockett if (!isWhitespaceOnly(C->getText())) 104e975a473SJulie Hockett CurrentCI.Text = C->getText(); 105e975a473SJulie Hockett } 106e975a473SJulie Hockett 107e975a473SJulie Hockett void ClangDocCommentVisitor::visitInlineCommandComment( 108e975a473SJulie Hockett const InlineCommandComment *C) { 109e975a473SJulie Hockett CurrentCI.Name = getCommandName(C->getCommandID()); 110e975a473SJulie Hockett for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I) 111e975a473SJulie Hockett CurrentCI.Args.push_back(C->getArgText(I)); 112e975a473SJulie Hockett } 113e975a473SJulie Hockett 114e975a473SJulie Hockett void ClangDocCommentVisitor::visitHTMLStartTagComment( 115e975a473SJulie Hockett const HTMLStartTagComment *C) { 116e975a473SJulie Hockett CurrentCI.Name = C->getTagName(); 117e975a473SJulie Hockett CurrentCI.SelfClosing = C->isSelfClosing(); 118e975a473SJulie Hockett for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) { 119e975a473SJulie Hockett const HTMLStartTagComment::Attribute &Attr = C->getAttr(I); 120e975a473SJulie Hockett CurrentCI.AttrKeys.push_back(Attr.Name); 121e975a473SJulie Hockett CurrentCI.AttrValues.push_back(Attr.Value); 122e975a473SJulie Hockett } 123e975a473SJulie Hockett } 124e975a473SJulie Hockett 125e975a473SJulie Hockett void ClangDocCommentVisitor::visitHTMLEndTagComment( 126e975a473SJulie Hockett const HTMLEndTagComment *C) { 127e975a473SJulie Hockett CurrentCI.Name = C->getTagName(); 128e975a473SJulie Hockett CurrentCI.SelfClosing = true; 129e975a473SJulie Hockett } 130e975a473SJulie Hockett 131e975a473SJulie Hockett void ClangDocCommentVisitor::visitBlockCommandComment( 132e975a473SJulie Hockett const BlockCommandComment *C) { 133e975a473SJulie Hockett CurrentCI.Name = getCommandName(C->getCommandID()); 134e975a473SJulie Hockett for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I) 135e975a473SJulie Hockett CurrentCI.Args.push_back(C->getArgText(I)); 136e975a473SJulie Hockett } 137e975a473SJulie Hockett 138e975a473SJulie Hockett void ClangDocCommentVisitor::visitParamCommandComment( 139e975a473SJulie Hockett const ParamCommandComment *C) { 140e975a473SJulie Hockett CurrentCI.Direction = 141e975a473SJulie Hockett ParamCommandComment::getDirectionAsString(C->getDirection()); 142e975a473SJulie Hockett CurrentCI.Explicit = C->isDirectionExplicit(); 143e975a473SJulie Hockett if (C->hasParamName()) 144e975a473SJulie Hockett CurrentCI.ParamName = C->getParamNameAsWritten(); 145e975a473SJulie Hockett } 146e975a473SJulie Hockett 147e975a473SJulie Hockett void ClangDocCommentVisitor::visitTParamCommandComment( 148e975a473SJulie Hockett const TParamCommandComment *C) { 149e975a473SJulie Hockett if (C->hasParamName()) 150e975a473SJulie Hockett CurrentCI.ParamName = C->getParamNameAsWritten(); 151e975a473SJulie Hockett } 152e975a473SJulie Hockett 153e975a473SJulie Hockett void ClangDocCommentVisitor::visitVerbatimBlockComment( 154e975a473SJulie Hockett const VerbatimBlockComment *C) { 155e975a473SJulie Hockett CurrentCI.Name = getCommandName(C->getCommandID()); 156e975a473SJulie Hockett CurrentCI.CloseName = C->getCloseName(); 157e975a473SJulie Hockett } 158e975a473SJulie Hockett 159e975a473SJulie Hockett void ClangDocCommentVisitor::visitVerbatimBlockLineComment( 160e975a473SJulie Hockett const VerbatimBlockLineComment *C) { 161e975a473SJulie Hockett if (!isWhitespaceOnly(C->getText())) 162e975a473SJulie Hockett CurrentCI.Text = C->getText(); 163e975a473SJulie Hockett } 164e975a473SJulie Hockett 165e975a473SJulie Hockett void ClangDocCommentVisitor::visitVerbatimLineComment( 166e975a473SJulie Hockett const VerbatimLineComment *C) { 167e975a473SJulie Hockett if (!isWhitespaceOnly(C->getText())) 168e975a473SJulie Hockett CurrentCI.Text = C->getText(); 169e975a473SJulie Hockett } 170e975a473SJulie Hockett 171e975a473SJulie Hockett bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const { 1726d9cd919SKazu Hirata return llvm::all_of(S, isspace); 173e975a473SJulie Hockett } 174e975a473SJulie Hockett 175e975a473SJulie Hockett std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const { 176e975a473SJulie Hockett const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); 177e975a473SJulie Hockett if (Info) 178e975a473SJulie Hockett return Info->Name; 179e975a473SJulie Hockett // TODO: Add parsing for \file command. 180e975a473SJulie Hockett return "<not a builtin command>"; 181e975a473SJulie Hockett } 182e975a473SJulie Hockett 183e975a473SJulie Hockett // Serializing functions. 184e975a473SJulie Hockett 185eaa7b324SBrett Wilson std::string getSourceCode(const Decl *D, const SourceRange &R) { 186eaa7b324SBrett Wilson return Lexer::getSourceText(CharSourceRange::getTokenRange(R), 187eaa7b324SBrett Wilson D->getASTContext().getSourceManager(), 188eaa7b324SBrett Wilson D->getASTContext().getLangOpts()) 189eaa7b324SBrett Wilson .str(); 190eaa7b324SBrett Wilson } 191eaa7b324SBrett Wilson 192e975a473SJulie Hockett template <typename T> static std::string serialize(T &I) { 193e975a473SJulie Hockett SmallString<2048> Buffer; 194e975a473SJulie Hockett llvm::BitstreamWriter Stream(Buffer); 195e975a473SJulie Hockett ClangDocBitcodeWriter Writer(Stream); 196e975a473SJulie Hockett Writer.emitBlock(I); 197e975a473SJulie Hockett return Buffer.str().str(); 198e975a473SJulie Hockett } 199e975a473SJulie Hockett 2008899c29bSJulie Hockett std::string serialize(std::unique_ptr<Info> &I) { 2018899c29bSJulie Hockett switch (I->IT) { 2028899c29bSJulie Hockett case InfoType::IT_namespace: 2038899c29bSJulie Hockett return serialize(*static_cast<NamespaceInfo *>(I.get())); 2048899c29bSJulie Hockett case InfoType::IT_record: 2058899c29bSJulie Hockett return serialize(*static_cast<RecordInfo *>(I.get())); 2068899c29bSJulie Hockett case InfoType::IT_enum: 2078899c29bSJulie Hockett return serialize(*static_cast<EnumInfo *>(I.get())); 2088899c29bSJulie Hockett case InfoType::IT_function: 2098899c29bSJulie Hockett return serialize(*static_cast<FunctionInfo *>(I.get())); 2108899c29bSJulie Hockett default: 2118899c29bSJulie Hockett return ""; 2128899c29bSJulie Hockett } 2138899c29bSJulie Hockett } 2148899c29bSJulie Hockett 215e975a473SJulie Hockett static void parseFullComment(const FullComment *C, CommentInfo &CI) { 216e975a473SJulie Hockett ClangDocCommentVisitor Visitor(CI); 217e975a473SJulie Hockett Visitor.parseComment(C); 218e975a473SJulie Hockett } 219e975a473SJulie Hockett 220e975a473SJulie Hockett static SymbolID getUSRForDecl(const Decl *D) { 221e975a473SJulie Hockett llvm::SmallString<128> USR; 222e975a473SJulie Hockett if (index::generateUSRForDecl(D, USR)) 223e975a473SJulie Hockett return SymbolID(); 224e975a473SJulie Hockett return hashUSR(USR); 225e975a473SJulie Hockett } 226e975a473SJulie Hockett 2274df84ac3SBrett Wilson static TagDecl *getTagDeclForType(const QualType &T) { 2284df84ac3SBrett Wilson if (const TagDecl *D = T->getAsTagDecl()) 2294df84ac3SBrett Wilson return D->getDefinition(); 2304df84ac3SBrett Wilson return nullptr; 2314df84ac3SBrett Wilson } 2324df84ac3SBrett Wilson 2334df84ac3SBrett Wilson static RecordDecl *getRecordDeclForType(const QualType &T) { 234b1f01e27SJulie Hockett if (const RecordDecl *D = T->getAsRecordDecl()) 235b1f01e27SJulie Hockett return D->getDefinition(); 236e975a473SJulie Hockett return nullptr; 237e975a473SJulie Hockett } 238e975a473SJulie Hockett 2392b932bc1SPaul Kirth TypeInfo getTypeInfoForType(const QualType &T, const PrintingPolicy &Policy) { 2404df84ac3SBrett Wilson const TagDecl *TD = getTagDeclForType(T); 2414df84ac3SBrett Wilson if (!TD) 2422b932bc1SPaul Kirth return TypeInfo(Reference(SymbolID(), T.getAsString(Policy))); 2434df84ac3SBrett Wilson 2444df84ac3SBrett Wilson InfoType IT; 2454df84ac3SBrett Wilson if (dyn_cast<EnumDecl>(TD)) { 2464df84ac3SBrett Wilson IT = InfoType::IT_enum; 2474df84ac3SBrett Wilson } else if (dyn_cast<RecordDecl>(TD)) { 2484df84ac3SBrett Wilson IT = InfoType::IT_record; 2494df84ac3SBrett Wilson } else { 2504df84ac3SBrett Wilson IT = InfoType::IT_default; 2514df84ac3SBrett Wilson } 2524df84ac3SBrett Wilson return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT, 2532b932bc1SPaul Kirth T.getAsString(Policy), getInfoRelativePath(TD))); 2544df84ac3SBrett Wilson } 2554df84ac3SBrett Wilson 256eb50a2e8SJulie Hockett static bool isPublic(const clang::AccessSpecifier AS, 257eb50a2e8SJulie Hockett const clang::Linkage Link) { 258eb50a2e8SJulie Hockett if (AS == clang::AccessSpecifier::AS_private) 259eb50a2e8SJulie Hockett return false; 26087759476SVlad Serebrennikov else if ((Link == clang::Linkage::Module) || 26187759476SVlad Serebrennikov (Link == clang::Linkage::External)) 262eb50a2e8SJulie Hockett return true; 263eb50a2e8SJulie Hockett return false; // otherwise, linkage is some form of internal linkage 264eb50a2e8SJulie Hockett } 265eb50a2e8SJulie Hockett 266ba3d595fSDiego Astiazaran static bool shouldSerializeInfo(bool PublicOnly, bool IsInAnonymousNamespace, 267ba3d595fSDiego Astiazaran const NamedDecl *D) { 268ba3d595fSDiego Astiazaran bool IsAnonymousNamespace = false; 269ba3d595fSDiego Astiazaran if (const auto *N = dyn_cast<NamespaceDecl>(D)) 270ba3d595fSDiego Astiazaran IsAnonymousNamespace = N->isAnonymousNamespace(); 271ba3d595fSDiego Astiazaran return !PublicOnly || 272ba3d595fSDiego Astiazaran (!IsInAnonymousNamespace && !IsAnonymousNamespace && 273ba3d595fSDiego Astiazaran isPublic(D->getAccessUnsafe(), D->getLinkageInternal())); 274ba3d595fSDiego Astiazaran } 275ba3d595fSDiego Astiazaran 27621fb70c6SBrett Wilson // The InsertChild functions insert the given info into the given scope using 27721fb70c6SBrett Wilson // the method appropriate for that type. Some types are moved into the 27821fb70c6SBrett Wilson // appropriate vector, while other types have Reference objects generated to 27921fb70c6SBrett Wilson // refer to them. 28021fb70c6SBrett Wilson // 28121fb70c6SBrett Wilson // See MakeAndInsertIntoParent(). 28221fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) { 28321fb70c6SBrett Wilson Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace, 2844a68babdSBrett Wilson Info.Name, getInfoRelativePath(Info.Namespace)); 28521fb70c6SBrett Wilson } 28621fb70c6SBrett Wilson 28721fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) { 28821fb70c6SBrett Wilson Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record, 2894a68babdSBrett Wilson Info.Name, getInfoRelativePath(Info.Namespace)); 29021fb70c6SBrett Wilson } 29121fb70c6SBrett Wilson 29221fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, EnumInfo Info) { 29321fb70c6SBrett Wilson Scope.Enums.push_back(std::move(Info)); 29421fb70c6SBrett Wilson } 29521fb70c6SBrett Wilson 29621fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, FunctionInfo Info) { 29721fb70c6SBrett Wilson Scope.Functions.push_back(std::move(Info)); 29821fb70c6SBrett Wilson } 29921fb70c6SBrett Wilson 30021fb70c6SBrett Wilson static void InsertChild(ScopeChildren &Scope, TypedefInfo Info) { 30121fb70c6SBrett Wilson Scope.Typedefs.push_back(std::move(Info)); 30221fb70c6SBrett Wilson } 30321fb70c6SBrett Wilson 30421fb70c6SBrett Wilson // Creates a parent of the correct type for the given child and inserts it into 30521fb70c6SBrett Wilson // that parent. 30621fb70c6SBrett Wilson // 30721fb70c6SBrett Wilson // This is complicated by the fact that namespaces and records are inserted by 30821fb70c6SBrett Wilson // reference (constructing a "Reference" object with that namespace/record's 30921fb70c6SBrett Wilson // info), while everything else is inserted by moving it directly into the child 31021fb70c6SBrett Wilson // vectors. 31121fb70c6SBrett Wilson // 31221fb70c6SBrett Wilson // For namespaces and records, explicitly specify a const& template parameter 31321fb70c6SBrett Wilson // when invoking this function: 31421fb70c6SBrett Wilson // MakeAndInsertIntoParent<const Record&>(...); 31521fb70c6SBrett Wilson // Otherwise, specify an rvalue reference <EnumInfo&&> and move into the 31621fb70c6SBrett Wilson // parameter. Since each variant is used once, it's not worth having a more 31721fb70c6SBrett Wilson // elaborate system to automatically deduce this information. 31821fb70c6SBrett Wilson template <typename ChildType> 31921fb70c6SBrett Wilson std::unique_ptr<Info> MakeAndInsertIntoParent(ChildType Child) { 32021fb70c6SBrett Wilson if (Child.Namespace.empty()) { 32121fb70c6SBrett Wilson // Insert into unnamed parent namespace. 32221fb70c6SBrett Wilson auto ParentNS = std::make_unique<NamespaceInfo>(); 32321fb70c6SBrett Wilson InsertChild(ParentNS->Children, std::forward<ChildType>(Child)); 32421fb70c6SBrett Wilson return ParentNS; 32521fb70c6SBrett Wilson } 32621fb70c6SBrett Wilson 32721fb70c6SBrett Wilson switch (Child.Namespace[0].RefType) { 32821fb70c6SBrett Wilson case InfoType::IT_namespace: { 32921fb70c6SBrett Wilson auto ParentNS = std::make_unique<NamespaceInfo>(); 33021fb70c6SBrett Wilson ParentNS->USR = Child.Namespace[0].USR; 33121fb70c6SBrett Wilson InsertChild(ParentNS->Children, std::forward<ChildType>(Child)); 33221fb70c6SBrett Wilson return ParentNS; 33321fb70c6SBrett Wilson } 33421fb70c6SBrett Wilson case InfoType::IT_record: { 33521fb70c6SBrett Wilson auto ParentRec = std::make_unique<RecordInfo>(); 33621fb70c6SBrett Wilson ParentRec->USR = Child.Namespace[0].USR; 33721fb70c6SBrett Wilson InsertChild(ParentRec->Children, std::forward<ChildType>(Child)); 33821fb70c6SBrett Wilson return ParentRec; 33921fb70c6SBrett Wilson } 34021fb70c6SBrett Wilson default: 34121fb70c6SBrett Wilson llvm_unreachable("Invalid reference type for parent namespace"); 34221fb70c6SBrett Wilson } 34321fb70c6SBrett Wilson } 34421fb70c6SBrett Wilson 345ba3d595fSDiego Astiazaran // There are two uses for this function. 346ba3d595fSDiego Astiazaran // 1) Getting the resulting mode of inheritance of a record. 347ba3d595fSDiego Astiazaran // Example: class A {}; class B : private A {}; class C : public B {}; 348ba3d595fSDiego Astiazaran // It's explicit that C is publicly inherited from C and B is privately 349ba3d595fSDiego Astiazaran // inherited from A. It's not explicit but C is also privately inherited from 350ba3d595fSDiego Astiazaran // A. This is the AS that this function calculates. FirstAS is the 351ba3d595fSDiego Astiazaran // inheritance mode of `class C : B` and SecondAS is the inheritance mode of 352ba3d595fSDiego Astiazaran // `class B : A`. 353ba3d595fSDiego Astiazaran // 2) Getting the inheritance mode of an inherited attribute / method. 354ba3d595fSDiego Astiazaran // Example : class A { public: int M; }; class B : private A {}; 355ba3d595fSDiego Astiazaran // Class B is inherited from class A, which has a public attribute. This 356ba3d595fSDiego Astiazaran // attribute is now part of the derived class B but it's not public. This 357ba3d595fSDiego Astiazaran // will be private because the inheritance is private. This is the AS that 358ba3d595fSDiego Astiazaran // this function calculates. FirstAS is the inheritance mode and SecondAS is 359ba3d595fSDiego Astiazaran // the AS of the attribute / method. 360ba3d595fSDiego Astiazaran static AccessSpecifier getFinalAccessSpecifier(AccessSpecifier FirstAS, 361ba3d595fSDiego Astiazaran AccessSpecifier SecondAS) { 362ba3d595fSDiego Astiazaran if (FirstAS == AccessSpecifier::AS_none || 363ba3d595fSDiego Astiazaran SecondAS == AccessSpecifier::AS_none) 364ba3d595fSDiego Astiazaran return AccessSpecifier::AS_none; 365ba3d595fSDiego Astiazaran if (FirstAS == AccessSpecifier::AS_private || 366ba3d595fSDiego Astiazaran SecondAS == AccessSpecifier::AS_private) 367ba3d595fSDiego Astiazaran return AccessSpecifier::AS_private; 368ba3d595fSDiego Astiazaran if (FirstAS == AccessSpecifier::AS_protected || 369ba3d595fSDiego Astiazaran SecondAS == AccessSpecifier::AS_protected) 370ba3d595fSDiego Astiazaran return AccessSpecifier::AS_protected; 371ba3d595fSDiego Astiazaran return AccessSpecifier::AS_public; 372ba3d595fSDiego Astiazaran } 373ba3d595fSDiego Astiazaran 374ba3d595fSDiego Astiazaran // The Access parameter is only provided when parsing the field of an inherited 375ba3d595fSDiego Astiazaran // record, the access specification of the field depends on the inheritance mode 376ba3d595fSDiego Astiazaran static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly, 377ba3d595fSDiego Astiazaran AccessSpecifier Access = AccessSpecifier::AS_public) { 378e975a473SJulie Hockett for (const FieldDecl *F : D->fields()) { 379ba3d595fSDiego Astiazaran if (!shouldSerializeInfo(PublicOnly, /*IsInAnonymousNamespace=*/false, F)) 380eb50a2e8SJulie Hockett continue; 3814df84ac3SBrett Wilson 3822b932bc1SPaul Kirth auto &LO = F->getLangOpts(); 383b59cd77cSJulie Hockett // Use getAccessUnsafe so that we just get the default AS_none if it's not 384b59cd77cSJulie Hockett // valid, as opposed to an assert. 3854df84ac3SBrett Wilson MemberTypeInfo &NewMember = I.Members.emplace_back( 3862b932bc1SPaul Kirth getTypeInfoForType(F->getTypeSourceInfo()->getType(), LO), 3874df84ac3SBrett Wilson F->getNameAsString(), 388ba3d595fSDiego Astiazaran getFinalAccessSpecifier(Access, F->getAccessUnsafe())); 3894df84ac3SBrett Wilson populateMemberTypeInfo(NewMember, F); 390b59cd77cSJulie Hockett } 391e975a473SJulie Hockett } 392e975a473SJulie Hockett 393e975a473SJulie Hockett static void parseEnumerators(EnumInfo &I, const EnumDecl *D) { 394eaa7b324SBrett Wilson for (const EnumConstantDecl *E : D->enumerators()) { 395eaa7b324SBrett Wilson std::string ValueExpr; 396eaa7b324SBrett Wilson if (const Expr *InitExpr = E->getInitExpr()) 397eaa7b324SBrett Wilson ValueExpr = getSourceCode(D, InitExpr->getSourceRange()); 398eaa7b324SBrett Wilson SmallString<16> ValueStr; 399eaa7b324SBrett Wilson E->getInitVal().toString(ValueStr); 4005ef2456aSPeterChou1 I.Members.emplace_back(E->getNameAsString(), ValueStr.str(), ValueExpr); 4015ef2456aSPeterChou1 ASTContext &Context = E->getASTContext(); 4025ef2456aSPeterChou1 if (RawComment *Comment = 4035ef2456aSPeterChou1 E->getASTContext().getRawCommentForDeclNoCache(E)) { 4045ef2456aSPeterChou1 CommentInfo CInfo; 4055ef2456aSPeterChou1 Comment->setAttached(); 4065ef2456aSPeterChou1 if (comments::FullComment *Fc = Comment->parse(Context, nullptr, E)) { 4075ef2456aSPeterChou1 EnumValueInfo &Member = I.Members.back(); 4085ef2456aSPeterChou1 Member.Description.emplace_back(); 4095ef2456aSPeterChou1 parseFullComment(Fc, Member.Description.back()); 4105ef2456aSPeterChou1 } 4115ef2456aSPeterChou1 } 412eaa7b324SBrett Wilson } 413e975a473SJulie Hockett } 414e975a473SJulie Hockett 415e975a473SJulie Hockett static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { 4162b932bc1SPaul Kirth auto &LO = D->getLangOpts(); 417e975a473SJulie Hockett for (const ParmVarDecl *P : D->parameters()) { 4184df84ac3SBrett Wilson FieldTypeInfo &FieldInfo = I.Params.emplace_back( 4192b932bc1SPaul Kirth getTypeInfoForType(P->getOriginalType(), LO), P->getNameAsString()); 4204a68babdSBrett Wilson FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange()); 421e191086bSBrett Wilson } 422e975a473SJulie Hockett } 423e975a473SJulie Hockett 424ba3d595fSDiego Astiazaran // TODO: Remove the serialization of Parents and VirtualParents, this 425ba3d595fSDiego Astiazaran // information is also extracted in the other definition of parseBases. 426e975a473SJulie Hockett static void parseBases(RecordInfo &I, const CXXRecordDecl *D) { 42773a4d54fSJulie Hockett // Don't parse bases if this isn't a definition. 42873a4d54fSJulie Hockett if (!D->isThisDeclarationADefinition()) 42973a4d54fSJulie Hockett return; 430e975a473SJulie Hockett for (const CXXBaseSpecifier &B : D->bases()) { 431e975a473SJulie Hockett if (B.isVirtual()) 432e975a473SJulie Hockett continue; 433b1f01e27SJulie Hockett if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) { 434b1f01e27SJulie Hockett const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl(); 435b1f01e27SJulie Hockett I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(), 4364a68babdSBrett Wilson InfoType::IT_record, B.getType().getAsString()); 4374df84ac3SBrett Wilson } else if (const RecordDecl *P = getRecordDeclForType(B.getType())) 438b59cd77cSJulie Hockett I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(), 4394a68babdSBrett Wilson InfoType::IT_record, P->getQualifiedNameAsString(), 4404a68babdSBrett Wilson getInfoRelativePath(P)); 441e975a473SJulie Hockett else 4420afc6085SBrett Wilson I.Parents.emplace_back(SymbolID(), B.getType().getAsString()); 443e975a473SJulie Hockett } 444e975a473SJulie Hockett for (const CXXBaseSpecifier &B : D->vbases()) { 4454df84ac3SBrett Wilson if (const RecordDecl *P = getRecordDeclForType(B.getType())) 4464a68babdSBrett Wilson I.VirtualParents.emplace_back( 4474a68babdSBrett Wilson getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record, 4484a68babdSBrett Wilson P->getQualifiedNameAsString(), getInfoRelativePath(P)); 449e975a473SJulie Hockett else 4500afc6085SBrett Wilson I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString()); 451e975a473SJulie Hockett } 452e975a473SJulie Hockett } 453e975a473SJulie Hockett 454e975a473SJulie Hockett template <typename T> 455e975a473SJulie Hockett static void 456e975a473SJulie Hockett populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces, 4572c1c9a24SJulie Hockett const T *D, bool &IsInAnonymousNamespace) { 45821fb70c6SBrett Wilson const DeclContext *DC = D->getDeclContext(); 45921fb70c6SBrett Wilson do { 460d900ef0aSJulie Hockett if (const auto *N = dyn_cast<NamespaceDecl>(DC)) { 461d900ef0aSJulie Hockett std::string Namespace; 462d900ef0aSJulie Hockett if (N->isAnonymousNamespace()) { 463d900ef0aSJulie Hockett Namespace = "@nonymous_namespace"; 4642c1c9a24SJulie Hockett IsInAnonymousNamespace = true; 465d900ef0aSJulie Hockett } else 466d900ef0aSJulie Hockett Namespace = N->getNameAsString(); 467d900ef0aSJulie Hockett Namespaces.emplace_back(getUSRForDecl(N), Namespace, 4684a68babdSBrett Wilson InfoType::IT_namespace, 4694a68babdSBrett Wilson N->getQualifiedNameAsString()); 470d900ef0aSJulie Hockett } else if (const auto *N = dyn_cast<RecordDecl>(DC)) 471b59cd77cSJulie Hockett Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 4724a68babdSBrett Wilson InfoType::IT_record, 4734a68babdSBrett Wilson N->getQualifiedNameAsString()); 474e975a473SJulie Hockett else if (const auto *N = dyn_cast<FunctionDecl>(DC)) 475b59cd77cSJulie Hockett Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 4764a68babdSBrett Wilson InfoType::IT_function, 4774a68babdSBrett Wilson N->getQualifiedNameAsString()); 478e975a473SJulie Hockett else if (const auto *N = dyn_cast<EnumDecl>(DC)) 479b59cd77cSJulie Hockett Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), 4804a68babdSBrett Wilson InfoType::IT_enum, N->getQualifiedNameAsString()); 48121fb70c6SBrett Wilson } while ((DC = DC->getParent())); 482b46131e5SDiego Astiazaran // The global namespace should be added to the list of namespaces if the decl 483b46131e5SDiego Astiazaran // corresponds to a Record and if it doesn't have any namespace (because this 484b46131e5SDiego Astiazaran // means it's in the global namespace). Also if its outermost namespace is a 485b46131e5SDiego Astiazaran // record because that record matches the previous condition mentioned. 48662e48ed1SKazu Hirata if ((Namespaces.empty() && isa<RecordDecl>(D)) || 487b46131e5SDiego Astiazaran (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record)) 488b46131e5SDiego Astiazaran Namespaces.emplace_back(SymbolID(), "GlobalNamespace", 489b46131e5SDiego Astiazaran InfoType::IT_namespace); 490e975a473SJulie Hockett } 491e975a473SJulie Hockett 4924a68babdSBrett Wilson void PopulateTemplateParameters(std::optional<TemplateInfo> &TemplateInfo, 4934a68babdSBrett Wilson const clang::Decl *D) { 4944a68babdSBrett Wilson if (const TemplateParameterList *ParamList = 4954a68babdSBrett Wilson D->getDescribedTemplateParams()) { 4964a68babdSBrett Wilson if (!TemplateInfo) { 4974a68babdSBrett Wilson TemplateInfo.emplace(); 4984a68babdSBrett Wilson } 4994a68babdSBrett Wilson for (const NamedDecl *ND : *ParamList) { 5004a68babdSBrett Wilson TemplateInfo->Params.emplace_back( 5014a68babdSBrett Wilson getSourceCode(ND, ND->getSourceRange())); 5024a68babdSBrett Wilson } 5034a68babdSBrett Wilson } 5044a68babdSBrett Wilson } 5054a68babdSBrett Wilson 5064a68babdSBrett Wilson TemplateParamInfo TemplateArgumentToInfo(const clang::Decl *D, 5074a68babdSBrett Wilson const TemplateArgument &Arg) { 5084a68babdSBrett Wilson // The TemplateArgument's pretty printing handles all the normal cases 5094a68babdSBrett Wilson // well enough for our requirements. 5104a68babdSBrett Wilson std::string Str; 5114a68babdSBrett Wilson llvm::raw_string_ostream Stream(Str); 5124a68babdSBrett Wilson Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false); 5134a68babdSBrett Wilson return TemplateParamInfo(Str); 5144a68babdSBrett Wilson } 5154a68babdSBrett Wilson 516e975a473SJulie Hockett template <typename T> 517d900ef0aSJulie Hockett static void populateInfo(Info &I, const T *D, const FullComment *C, 518d900ef0aSJulie Hockett bool &IsInAnonymousNamespace) { 519e975a473SJulie Hockett I.USR = getUSRForDecl(D); 520e975a473SJulie Hockett I.Name = D->getNameAsString(); 521d900ef0aSJulie Hockett populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace); 522e975a473SJulie Hockett if (C) { 523e975a473SJulie Hockett I.Description.emplace_back(); 524e975a473SJulie Hockett parseFullComment(C, I.Description.back()); 525e975a473SJulie Hockett } 526e975a473SJulie Hockett } 527e975a473SJulie Hockett 528e975a473SJulie Hockett template <typename T> 529e975a473SJulie Hockett static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C, 530d900ef0aSJulie Hockett int LineNumber, StringRef Filename, 531665e9676SDiego Astiazaran bool IsFileInRootDir, 532d900ef0aSJulie Hockett bool &IsInAnonymousNamespace) { 533d900ef0aSJulie Hockett populateInfo(I, D, C, IsInAnonymousNamespace); 534e975a473SJulie Hockett if (D->isThisDeclarationADefinition()) 535665e9676SDiego Astiazaran I.DefLoc.emplace(LineNumber, Filename, IsFileInRootDir); 536e975a473SJulie Hockett else 537665e9676SDiego Astiazaran I.Loc.emplace_back(LineNumber, Filename, IsFileInRootDir); 538e975a473SJulie Hockett } 539e975a473SJulie Hockett 540e975a473SJulie Hockett static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, 541e975a473SJulie Hockett const FullComment *FC, int LineNumber, 542665e9676SDiego Astiazaran StringRef Filename, bool IsFileInRootDir, 543d900ef0aSJulie Hockett bool &IsInAnonymousNamespace) { 544665e9676SDiego Astiazaran populateSymbolInfo(I, D, FC, LineNumber, Filename, IsFileInRootDir, 545665e9676SDiego Astiazaran IsInAnonymousNamespace); 5462b932bc1SPaul Kirth auto &LO = D->getLangOpts(); 5472b932bc1SPaul Kirth I.ReturnType = getTypeInfoForType(D->getReturnType(), LO); 548e975a473SJulie Hockett parseParameters(I, D); 5494a68babdSBrett Wilson 5504a68babdSBrett Wilson PopulateTemplateParameters(I.Template, D); 5514a68babdSBrett Wilson 5524a68babdSBrett Wilson // Handle function template specializations. 5534a68babdSBrett Wilson if (const FunctionTemplateSpecializationInfo *FTSI = 5544a68babdSBrett Wilson D->getTemplateSpecializationInfo()) { 5554a68babdSBrett Wilson if (!I.Template) 5564a68babdSBrett Wilson I.Template.emplace(); 5574a68babdSBrett Wilson I.Template->Specialization.emplace(); 5584a68babdSBrett Wilson auto &Specialization = *I.Template->Specialization; 5594a68babdSBrett Wilson 5604a68babdSBrett Wilson Specialization.SpecializationOf = getUSRForDecl(FTSI->getTemplate()); 5614a68babdSBrett Wilson 5624a68babdSBrett Wilson // Template parameters to the specialization. 5634a68babdSBrett Wilson if (FTSI->TemplateArguments) { 5644a68babdSBrett Wilson for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) { 5654a68babdSBrett Wilson Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg)); 5664a68babdSBrett Wilson } 5674a68babdSBrett Wilson } 5684a68babdSBrett Wilson } 569e975a473SJulie Hockett } 570e975a473SJulie Hockett 57199baa10fSBrett Wilson static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) { 57299baa10fSBrett Wilson assert(D && "Expect non-null FieldDecl in populateMemberTypeInfo"); 57399baa10fSBrett Wilson 57499baa10fSBrett Wilson ASTContext& Context = D->getASTContext(); 57599baa10fSBrett Wilson // TODO investigate whether we can use ASTContext::getCommentForDecl instead 57699baa10fSBrett Wilson // of this logic. See also similar code in Mapper.cpp. 57799baa10fSBrett Wilson RawComment *Comment = Context.getRawCommentForDeclNoCache(D); 57899baa10fSBrett Wilson if (!Comment) 57999baa10fSBrett Wilson return; 58099baa10fSBrett Wilson 58199baa10fSBrett Wilson Comment->setAttached(); 58299baa10fSBrett Wilson if (comments::FullComment *fc = Comment->parse(Context, nullptr, D)) { 58399baa10fSBrett Wilson I.Description.emplace_back(); 58499baa10fSBrett Wilson parseFullComment(fc, I.Description.back()); 58599baa10fSBrett Wilson } 58699baa10fSBrett Wilson } 58799baa10fSBrett Wilson 588ba3d595fSDiego Astiazaran static void 589ba3d595fSDiego Astiazaran parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir, 590ba3d595fSDiego Astiazaran bool PublicOnly, bool IsParent, 591ba3d595fSDiego Astiazaran AccessSpecifier ParentAccess = AccessSpecifier::AS_public) { 592ba3d595fSDiego Astiazaran // Don't parse bases if this isn't a definition. 593ba3d595fSDiego Astiazaran if (!D->isThisDeclarationADefinition()) 594ba3d595fSDiego Astiazaran return; 595ba3d595fSDiego Astiazaran for (const CXXBaseSpecifier &B : D->bases()) { 596ba3d595fSDiego Astiazaran if (const RecordType *Ty = B.getType()->getAs<RecordType>()) { 597ba3d595fSDiego Astiazaran if (const CXXRecordDecl *Base = 598ba3d595fSDiego Astiazaran cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) { 599ba3d595fSDiego Astiazaran // Initialized without USR and name, this will be set in the following 600ba3d595fSDiego Astiazaran // if-else stmt. 601ba3d595fSDiego Astiazaran BaseRecordInfo BI( 602ba3d595fSDiego Astiazaran {}, "", getInfoRelativePath(Base), B.isVirtual(), 603ba3d595fSDiego Astiazaran getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()), 604ba3d595fSDiego Astiazaran IsParent); 605ba3d595fSDiego Astiazaran if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) { 606ba3d595fSDiego Astiazaran const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl(); 607ba3d595fSDiego Astiazaran BI.USR = getUSRForDecl(D); 608ba3d595fSDiego Astiazaran BI.Name = B.getType().getAsString(); 609ba3d595fSDiego Astiazaran } else { 610ba3d595fSDiego Astiazaran BI.USR = getUSRForDecl(Base); 611ba3d595fSDiego Astiazaran BI.Name = Base->getNameAsString(); 612ba3d595fSDiego Astiazaran } 613ba3d595fSDiego Astiazaran parseFields(BI, Base, PublicOnly, BI.Access); 614ba3d595fSDiego Astiazaran for (const auto &Decl : Base->decls()) 615ba3d595fSDiego Astiazaran if (const auto *MD = dyn_cast<CXXMethodDecl>(Decl)) { 616ba3d595fSDiego Astiazaran // Don't serialize private methods 617ba3d595fSDiego Astiazaran if (MD->getAccessUnsafe() == AccessSpecifier::AS_private || 618ba3d595fSDiego Astiazaran !MD->isUserProvided()) 619ba3d595fSDiego Astiazaran continue; 620ba3d595fSDiego Astiazaran FunctionInfo FI; 621ba3d595fSDiego Astiazaran FI.IsMethod = true; 622ba3d595fSDiego Astiazaran // The seventh arg in populateFunctionInfo is a boolean passed by 623ba3d595fSDiego Astiazaran // reference, its value is not relevant in here so it's not used 624ba3d595fSDiego Astiazaran // anywhere besides the function call. 625ba3d595fSDiego Astiazaran bool IsInAnonymousNamespace; 626ba3d595fSDiego Astiazaran populateFunctionInfo(FI, MD, /*FullComment=*/{}, /*LineNumber=*/{}, 627ba3d595fSDiego Astiazaran /*FileName=*/{}, IsFileInRootDir, 628ba3d595fSDiego Astiazaran IsInAnonymousNamespace); 629ba3d595fSDiego Astiazaran FI.Access = 630ba3d595fSDiego Astiazaran getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe()); 63121fb70c6SBrett Wilson BI.Children.Functions.emplace_back(std::move(FI)); 632ba3d595fSDiego Astiazaran } 633ba3d595fSDiego Astiazaran I.Bases.emplace_back(std::move(BI)); 634ba3d595fSDiego Astiazaran // Call this function recursively to get the inherited classes of 635ba3d595fSDiego Astiazaran // this base; these new bases will also get stored in the original 636ba3d595fSDiego Astiazaran // RecordInfo: I. 637ba3d595fSDiego Astiazaran parseBases(I, Base, IsFileInRootDir, PublicOnly, false, 638ba3d595fSDiego Astiazaran I.Bases.back().Access); 639ba3d595fSDiego Astiazaran } 640ba3d595fSDiego Astiazaran } 641ba3d595fSDiego Astiazaran } 642ba3d595fSDiego Astiazaran } 643ba3d595fSDiego Astiazaran 644097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 645097aedc9SJulie Hockett emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber, 646665e9676SDiego Astiazaran llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { 6471c705d9cSJonas Devlieghere auto I = std::make_unique<NamespaceInfo>(); 648d900ef0aSJulie Hockett bool IsInAnonymousNamespace = false; 649d900ef0aSJulie Hockett populateInfo(*I, D, FC, IsInAnonymousNamespace); 650ba3d595fSDiego Astiazaran if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 651097aedc9SJulie Hockett return {}; 652ba3d595fSDiego Astiazaran 653d900ef0aSJulie Hockett I->Name = D->isAnonymousNamespace() 654d900ef0aSJulie Hockett ? llvm::SmallString<16>("@nonymous_namespace") 655d900ef0aSJulie Hockett : I->Name; 6562c1c9a24SJulie Hockett I->Path = getInfoRelativePath(I->Namespace); 657097aedc9SJulie Hockett if (I->Namespace.empty() && I->USR == SymbolID()) 658097aedc9SJulie Hockett return {std::unique_ptr<Info>{std::move(I)}, nullptr}; 659097aedc9SJulie Hockett 66021fb70c6SBrett Wilson // Namespaces are inserted into the parent by reference, so we need to return 66121fb70c6SBrett Wilson // both the parent and the record itself. 66221fb70c6SBrett Wilson return {std::move(I), MakeAndInsertIntoParent<const NamespaceInfo &>(*I)}; 663e975a473SJulie Hockett } 664e975a473SJulie Hockett 665097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 666097aedc9SJulie Hockett emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber, 667665e9676SDiego Astiazaran llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { 6681c705d9cSJonas Devlieghere auto I = std::make_unique<RecordInfo>(); 669d900ef0aSJulie Hockett bool IsInAnonymousNamespace = false; 670665e9676SDiego Astiazaran populateSymbolInfo(*I, D, FC, LineNumber, File, IsFileInRootDir, 671665e9676SDiego Astiazaran IsInAnonymousNamespace); 672ba3d595fSDiego Astiazaran if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 673097aedc9SJulie Hockett return {}; 674d900ef0aSJulie Hockett 6758899c29bSJulie Hockett I->TagType = D->getTagKind(); 6768899c29bSJulie Hockett parseFields(*I, D, PublicOnly); 677b1f01e27SJulie Hockett if (const auto *C = dyn_cast<CXXRecordDecl>(D)) { 678b1f01e27SJulie Hockett if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) { 679b1f01e27SJulie Hockett I->Name = TD->getNameAsString(); 680b1f01e27SJulie Hockett I->IsTypeDef = true; 681b1f01e27SJulie Hockett } 682ba3d595fSDiego Astiazaran // TODO: remove first call to parseBases, that function should be deleted 6838899c29bSJulie Hockett parseBases(*I, C); 684ba3d595fSDiego Astiazaran parseBases(*I, C, IsFileInRootDir, PublicOnly, true); 685b1f01e27SJulie Hockett } 6862c1c9a24SJulie Hockett I->Path = getInfoRelativePath(I->Namespace); 687097aedc9SJulie Hockett 6884a68babdSBrett Wilson PopulateTemplateParameters(I->Template, D); 6894a68babdSBrett Wilson 6904a68babdSBrett Wilson // Full and partial specializations. 6914a68babdSBrett Wilson if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 6924a68babdSBrett Wilson if (!I->Template) 6934a68babdSBrett Wilson I->Template.emplace(); 6944a68babdSBrett Wilson I->Template->Specialization.emplace(); 6954a68babdSBrett Wilson auto &Specialization = *I->Template->Specialization; 6964a68babdSBrett Wilson 6974a68babdSBrett Wilson // What this is a specialization of. 6984a68babdSBrett Wilson auto SpecOf = CTSD->getSpecializedTemplateOrPartial(); 699*b68a952aSKazu Hirata if (auto *CTD = dyn_cast<ClassTemplateDecl *>(SpecOf)) 700*b68a952aSKazu Hirata Specialization.SpecializationOf = getUSRForDecl(CTD); 701*b68a952aSKazu Hirata else if (auto *CTPSD = 702*b68a952aSKazu Hirata dyn_cast<ClassTemplatePartialSpecializationDecl *>(SpecOf)) 703*b68a952aSKazu Hirata Specialization.SpecializationOf = getUSRForDecl(CTPSD); 7044a68babdSBrett Wilson 7054a68babdSBrett Wilson // Parameters to the specilization. For partial specializations, get the 7064a68babdSBrett Wilson // parameters "as written" from the ClassTemplatePartialSpecializationDecl 7074a68babdSBrett Wilson // because the non-explicit template parameters will have generated internal 7084a68babdSBrett Wilson // placeholder names rather than the names the user typed that match the 7094a68babdSBrett Wilson // template parameters. 7104a68babdSBrett Wilson if (const ClassTemplatePartialSpecializationDecl *CTPSD = 7114a68babdSBrett Wilson dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { 7124a68babdSBrett Wilson if (const ASTTemplateArgumentListInfo *AsWritten = 7134a68babdSBrett Wilson CTPSD->getTemplateArgsAsWritten()) { 7144a68babdSBrett Wilson for (unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) { 7154a68babdSBrett Wilson Specialization.Params.emplace_back( 7164a68babdSBrett Wilson getSourceCode(D, (*AsWritten)[i].getSourceRange())); 7174a68babdSBrett Wilson } 7184a68babdSBrett Wilson } 7194a68babdSBrett Wilson } else { 7204a68babdSBrett Wilson for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) { 7214a68babdSBrett Wilson Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg)); 7224a68babdSBrett Wilson } 7234a68babdSBrett Wilson } 7244a68babdSBrett Wilson } 7254a68babdSBrett Wilson 72621fb70c6SBrett Wilson // Records are inserted into the parent by reference, so we need to return 72721fb70c6SBrett Wilson // both the parent and the record itself. 72821fb70c6SBrett Wilson auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I); 72921fb70c6SBrett Wilson return {std::move(I), std::move(Parent)}; 730097aedc9SJulie Hockett } 731097aedc9SJulie Hockett 732097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 733097aedc9SJulie Hockett emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber, 734665e9676SDiego Astiazaran llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { 7358899c29bSJulie Hockett FunctionInfo Func; 736d900ef0aSJulie Hockett bool IsInAnonymousNamespace = false; 737665e9676SDiego Astiazaran populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, 738665e9676SDiego Astiazaran IsInAnonymousNamespace); 7396a29ae4bSDiego Astiazaran Func.Access = clang::AccessSpecifier::AS_none; 740ba3d595fSDiego Astiazaran if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 741097aedc9SJulie Hockett return {}; 742d900ef0aSJulie Hockett 74321fb70c6SBrett Wilson // Info is wrapped in its parent scope so is returned in the second position. 74421fb70c6SBrett Wilson return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))}; 745e975a473SJulie Hockett } 746e975a473SJulie Hockett 747097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 748097aedc9SJulie Hockett emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, 749665e9676SDiego Astiazaran llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { 7508899c29bSJulie Hockett FunctionInfo Func; 751d900ef0aSJulie Hockett bool IsInAnonymousNamespace = false; 752665e9676SDiego Astiazaran populateFunctionInfo(Func, D, FC, LineNumber, File, IsFileInRootDir, 753665e9676SDiego Astiazaran IsInAnonymousNamespace); 754ba3d595fSDiego Astiazaran if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 755097aedc9SJulie Hockett return {}; 756d900ef0aSJulie Hockett 7578899c29bSJulie Hockett Func.IsMethod = true; 7588899c29bSJulie Hockett 759b1f01e27SJulie Hockett const NamedDecl *Parent = nullptr; 760b1f01e27SJulie Hockett if (const auto *SD = 761b1f01e27SJulie Hockett dyn_cast<ClassTemplateSpecializationDecl>(D->getParent())) 762b1f01e27SJulie Hockett Parent = SD->getSpecializedTemplate(); 763b1f01e27SJulie Hockett else 764b1f01e27SJulie Hockett Parent = D->getParent(); 765b1f01e27SJulie Hockett 766b1f01e27SJulie Hockett SymbolID ParentUSR = getUSRForDecl(Parent); 767b1f01e27SJulie Hockett Func.Parent = 7684a68babdSBrett Wilson Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record, 7694a68babdSBrett Wilson Parent->getQualifiedNameAsString()}; 7708899c29bSJulie Hockett Func.Access = D->getAccess(); 7718899c29bSJulie Hockett 77221fb70c6SBrett Wilson // Info is wrapped in its parent scope so is returned in the second position. 77321fb70c6SBrett Wilson return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))}; 77421fb70c6SBrett Wilson } 77521fb70c6SBrett Wilson 77621fb70c6SBrett Wilson std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 77721fb70c6SBrett Wilson emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber, 77821fb70c6SBrett Wilson StringRef File, bool IsFileInRootDir, bool PublicOnly) { 77921fb70c6SBrett Wilson TypedefInfo Info; 78021fb70c6SBrett Wilson 78121fb70c6SBrett Wilson bool IsInAnonymousNamespace = false; 78221fb70c6SBrett Wilson populateInfo(Info, D, FC, IsInAnonymousNamespace); 78321fb70c6SBrett Wilson if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 78421fb70c6SBrett Wilson return {}; 78521fb70c6SBrett Wilson 78621fb70c6SBrett Wilson Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir); 7872b932bc1SPaul Kirth auto &LO = D->getLangOpts(); 7882b932bc1SPaul Kirth Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO); 78921fb70c6SBrett Wilson if (Info.Underlying.Type.Name.empty()) { 79021fb70c6SBrett Wilson // Typedef for an unnamed type. This is like "typedef struct { } Foo;" 79121fb70c6SBrett Wilson // The record serializer explicitly checks for this syntax and constructs 79221fb70c6SBrett Wilson // a record with that name, so we don't want to emit a duplicate here. 79321fb70c6SBrett Wilson return {}; 79421fb70c6SBrett Wilson } 79521fb70c6SBrett Wilson Info.IsUsing = false; 79621fb70c6SBrett Wilson 79721fb70c6SBrett Wilson // Info is wrapped in its parent scope so is returned in the second position. 79821fb70c6SBrett Wilson return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))}; 79921fb70c6SBrett Wilson } 80021fb70c6SBrett Wilson 80121fb70c6SBrett Wilson // A type alias is a C++ "using" declaration for a type. It gets mapped to a 80221fb70c6SBrett Wilson // TypedefInfo with the IsUsing flag set. 80321fb70c6SBrett Wilson std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 80421fb70c6SBrett Wilson emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber, 80521fb70c6SBrett Wilson StringRef File, bool IsFileInRootDir, bool PublicOnly) { 80621fb70c6SBrett Wilson TypedefInfo Info; 80721fb70c6SBrett Wilson 80821fb70c6SBrett Wilson bool IsInAnonymousNamespace = false; 80921fb70c6SBrett Wilson populateInfo(Info, D, FC, IsInAnonymousNamespace); 81021fb70c6SBrett Wilson if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 81121fb70c6SBrett Wilson return {}; 81221fb70c6SBrett Wilson 81321fb70c6SBrett Wilson Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir); 8142b932bc1SPaul Kirth auto &LO = D->getLangOpts(); 8152b932bc1SPaul Kirth Info.Underlying = getTypeInfoForType(D->getUnderlyingType(), LO); 81621fb70c6SBrett Wilson Info.IsUsing = true; 81721fb70c6SBrett Wilson 81821fb70c6SBrett Wilson // Info is wrapped in its parent scope so is returned in the second position. 81921fb70c6SBrett Wilson return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))}; 820e975a473SJulie Hockett } 821e975a473SJulie Hockett 822097aedc9SJulie Hockett std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> 823097aedc9SJulie Hockett emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber, 824665e9676SDiego Astiazaran llvm::StringRef File, bool IsFileInRootDir, bool PublicOnly) { 8258899c29bSJulie Hockett EnumInfo Enum; 826d900ef0aSJulie Hockett bool IsInAnonymousNamespace = false; 827665e9676SDiego Astiazaran populateSymbolInfo(Enum, D, FC, LineNumber, File, IsFileInRootDir, 828665e9676SDiego Astiazaran IsInAnonymousNamespace); 829ba3d595fSDiego Astiazaran if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D)) 830097aedc9SJulie Hockett return {}; 831d900ef0aSJulie Hockett 8328899c29bSJulie Hockett Enum.Scoped = D->isScoped(); 8334a68babdSBrett Wilson if (D->isFixed()) { 8344a68babdSBrett Wilson auto Name = D->getIntegerType().getAsString(); 8354a68babdSBrett Wilson Enum.BaseType = TypeInfo(Name, Name); 8364a68babdSBrett Wilson } 8378899c29bSJulie Hockett parseEnumerators(Enum, D); 8388899c29bSJulie Hockett 83921fb70c6SBrett Wilson // Info is wrapped in its parent scope so is returned in the second position. 84021fb70c6SBrett Wilson return {nullptr, MakeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))}; 841e975a473SJulie Hockett } 842e975a473SJulie Hockett 843e975a473SJulie Hockett } // namespace serialize 844e975a473SJulie Hockett } // namespace doc 845e975a473SJulie Hockett } // namespace clang 846