1 //===- ExtractAPI/API.cpp ---------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file implements the APIRecord and derived record structs, 11 /// and the APISet class. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/ExtractAPI/API.h" 16 #include "clang/AST/CommentCommandTraits.h" 17 #include "clang/AST/CommentLexer.h" 18 #include "clang/AST/RawCommentList.h" 19 #include "clang/Index/USRGeneration.h" 20 #include "llvm/Support/Allocator.h" 21 22 using namespace clang::extractapi; 23 using namespace llvm; 24 25 GlobalRecord *APISet::addGlobal(GVKind Kind, StringRef Name, StringRef USR, 26 PresumedLoc Loc, 27 const AvailabilityInfo &Availability, 28 LinkageInfo Linkage, const DocComment &Comment, 29 DeclarationFragments Fragments, 30 DeclarationFragments SubHeading, 31 FunctionSignature Signature) { 32 auto Result = Globals.insert({Name, nullptr}); 33 if (Result.second) { 34 // Create the record if it does not already exist. 35 auto Record = APIRecordUniquePtr<GlobalRecord>(new (Allocator) GlobalRecord{ 36 Kind, Name, USR, Loc, Availability, Linkage, Comment, Fragments, 37 SubHeading, Signature}); 38 Result.first->second = std::move(Record); 39 } 40 return Result.first->second.get(); 41 } 42 43 GlobalRecord * 44 APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, 45 const AvailabilityInfo &Availability, LinkageInfo Linkage, 46 const DocComment &Comment, DeclarationFragments Fragments, 47 DeclarationFragments SubHeading) { 48 return addGlobal(GVKind::Variable, Name, USR, Loc, Availability, Linkage, 49 Comment, Fragments, SubHeading, {}); 50 } 51 52 GlobalRecord * 53 APISet::addFunction(StringRef Name, StringRef USR, PresumedLoc Loc, 54 const AvailabilityInfo &Availability, LinkageInfo Linkage, 55 const DocComment &Comment, DeclarationFragments Fragments, 56 DeclarationFragments SubHeading, 57 FunctionSignature Signature) { 58 return addGlobal(GVKind::Function, Name, USR, Loc, Availability, Linkage, 59 Comment, Fragments, SubHeading, Signature); 60 } 61 62 EnumConstantRecord *APISet::addEnumConstant( 63 EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc, 64 const AvailabilityInfo &Availability, const DocComment &Comment, 65 DeclarationFragments Declaration, DeclarationFragments SubHeading) { 66 auto Record = 67 APIRecordUniquePtr<EnumConstantRecord>(new (Allocator) EnumConstantRecord{ 68 Name, USR, Loc, Availability, Comment, Declaration, SubHeading}); 69 return Enum->Constants.emplace_back(std::move(Record)).get(); 70 } 71 72 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, 73 const AvailabilityInfo &Availability, 74 const DocComment &Comment, 75 DeclarationFragments Declaration, 76 DeclarationFragments SubHeading) { 77 auto Result = Enums.insert({Name, nullptr}); 78 if (Result.second) { 79 // Create the record if it does not already exist. 80 auto Record = APIRecordUniquePtr<EnumRecord>(new (Allocator) EnumRecord{ 81 Name, USR, Loc, Availability, Comment, Declaration, SubHeading}); 82 Result.first->second = std::move(Record); 83 } 84 return Result.first->second.get(); 85 } 86 87 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name, 88 StringRef USR, PresumedLoc Loc, 89 const AvailabilityInfo &Availability, 90 const DocComment &Comment, 91 DeclarationFragments Declaration, 92 DeclarationFragments SubHeading) { 93 auto Record = 94 APIRecordUniquePtr<StructFieldRecord>(new (Allocator) StructFieldRecord{ 95 Name, USR, Loc, Availability, Comment, Declaration, SubHeading}); 96 return Struct->Fields.emplace_back(std::move(Record)).get(); 97 } 98 99 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, 100 const AvailabilityInfo &Availability, 101 const DocComment &Comment, 102 DeclarationFragments Declaration, 103 DeclarationFragments SubHeading) { 104 auto Result = Structs.insert({Name, nullptr}); 105 if (Result.second) { 106 // Create the record if it does not already exist. 107 auto Record = APIRecordUniquePtr<StructRecord>(new (Allocator) StructRecord{ 108 Name, USR, Loc, Availability, Comment, Declaration, SubHeading}); 109 Result.first->second = std::move(Record); 110 } 111 return Result.first->second.get(); 112 } 113 114 StringRef APISet::recordUSR(const Decl *D) { 115 SmallString<128> USR; 116 index::generateUSRForDecl(D, USR); 117 return copyString(USR); 118 } 119 120 StringRef APISet::copyString(StringRef String) { 121 if (String.empty()) 122 return {}; 123 124 // No need to allocate memory and copy if the string has already been stored. 125 if (Allocator.identifyObject(String.data())) 126 return String; 127 128 void *Ptr = Allocator.Allocate(String.size(), 1); 129 memcpy(Ptr, String.data(), String.size()); 130 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 131 } 132 133 APIRecord::~APIRecord() {} 134 135 void GlobalRecord::anchor() {} 136