xref: /llvm-project/clang/lib/ExtractAPI/API.cpp (revision 5bb5704c1b35023b8a6217a6eb7d98a47efe1ca2)
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