1 | //===-- Implementation of APIIndexer class --------------------------------===// |
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 | #include "APIIndexer.h" |
10 | |
11 | #include "llvm/ADT/StringExtras.h" |
12 | #include "llvm/ADT/StringRef.h" |
13 | #include "llvm/TableGen/Error.h" |
14 | #include "llvm/TableGen/Record.h" |
15 | |
16 | namespace llvm_libc { |
17 | |
18 | static const char NamedTypeClassName[] = "NamedType" ; |
19 | static const char PtrTypeClassName[] = "PtrType" ; |
20 | static const char RestrictedPtrTypeClassName[] = "RestrictedPtrType" ; |
21 | static const char ConstTypeClassName[] = "ConstType" ; |
22 | static const char StructTypeClassName[] = "Struct" ; |
23 | |
24 | static const char StandardSpecClassName[] = "StandardSpec" ; |
25 | static const char PublicAPIClassName[] = "PublicAPI" ; |
26 | |
27 | static bool isa(llvm::Record *Def, llvm::Record *TypeClass) { |
28 | llvm::RecordRecTy *RecordType = Def->getType(); |
29 | llvm::ArrayRef<llvm::Record *> Classes = RecordType->getClasses(); |
30 | // We want exact types. That is, we don't want the classes listed in |
31 | // spec.td to be subclassed. Hence, we do not want the record |Def| |
32 | // to be of more than one class type.. |
33 | if (Classes.size() != 1) |
34 | return false; |
35 | return Classes[0] == TypeClass; |
36 | } |
37 | |
38 | bool APIIndexer::isaNamedType(llvm::Record *Def) { |
39 | return isa(Def, NamedTypeClass); |
40 | } |
41 | |
42 | bool APIIndexer::isaStructType(llvm::Record *Def) { |
43 | return isa(Def, StructClass); |
44 | } |
45 | |
46 | bool APIIndexer::isaPtrType(llvm::Record *Def) { |
47 | return isa(Def, PtrTypeClass); |
48 | } |
49 | |
50 | bool APIIndexer::isaConstType(llvm::Record *Def) { |
51 | return isa(Def, ConstTypeClass); |
52 | } |
53 | |
54 | bool APIIndexer::isaRestrictedPtrType(llvm::Record *Def) { |
55 | return isa(Def, RestrictedPtrTypeClass); |
56 | } |
57 | |
58 | bool APIIndexer::isaStandardSpec(llvm::Record *Def) { |
59 | return isa(Def, StandardSpecClass); |
60 | } |
61 | |
62 | bool APIIndexer::isaPublicAPI(llvm::Record *Def) { |
63 | return isa(Def, PublicAPIClass); |
64 | } |
65 | |
66 | std::string APIIndexer::getTypeAsString(llvm::Record *TypeRecord) { |
67 | if (isaNamedType(TypeRecord) || isaStructType(TypeRecord)) { |
68 | return std::string(TypeRecord->getValueAsString("Name" )); |
69 | } else if (isaPtrType(TypeRecord)) { |
70 | return getTypeAsString(TypeRecord->getValueAsDef("PointeeType" )) + " *" ; |
71 | } else if (isaConstType(TypeRecord)) { |
72 | return std::string("const " ) + |
73 | getTypeAsString(TypeRecord->getValueAsDef("UnqualifiedType" )); |
74 | } else if (isaRestrictedPtrType(TypeRecord)) { |
75 | return getTypeAsString(TypeRecord->getValueAsDef("PointeeType" )) + |
76 | " *__restrict" ; |
77 | } else { |
78 | llvm::PrintFatalError(TypeRecord->getLoc(), "Invalid type.\n" ); |
79 | } |
80 | } |
81 | |
82 | void APIIndexer::indexStandardSpecDef(llvm::Record *StandardSpec) { |
83 | auto = StandardSpec->getValueAsListOfDefs("Headers" ); |
84 | for (llvm::Record *HeaderSpec : HeaderSpecList) { |
85 | llvm::StringRef Header = HeaderSpec->getValueAsString("Name" ); |
86 | if (!StdHeader.has_value() || Header == StdHeader) { |
87 | PublicHeaders.emplace(Header); |
88 | auto MacroSpecList = HeaderSpec->getValueAsListOfDefs("Macros" ); |
89 | // TODO: Trigger a fatal error on duplicate specs. |
90 | for (llvm::Record *MacroSpec : MacroSpecList) |
91 | MacroSpecMap[std::string(MacroSpec->getValueAsString("Name" ))] = |
92 | MacroSpec; |
93 | |
94 | auto TypeSpecList = HeaderSpec->getValueAsListOfDefs("Types" ); |
95 | for (llvm::Record *TypeSpec : TypeSpecList) |
96 | TypeSpecMap[std::string(TypeSpec->getValueAsString("Name" ))] = TypeSpec; |
97 | |
98 | auto FunctionSpecList = HeaderSpec->getValueAsListOfDefs("Functions" ); |
99 | for (llvm::Record *FunctionSpec : FunctionSpecList) { |
100 | auto FunctionName = std::string(FunctionSpec->getValueAsString("Name" )); |
101 | FunctionSpecMap[FunctionName] = FunctionSpec; |
102 | FunctionToHeaderMap[FunctionName] = std::string(Header); |
103 | } |
104 | |
105 | auto EnumerationSpecList = |
106 | HeaderSpec->getValueAsListOfDefs("Enumerations" ); |
107 | for (llvm::Record *EnumerationSpec : EnumerationSpecList) { |
108 | EnumerationSpecMap[std::string( |
109 | EnumerationSpec->getValueAsString("Name" ))] = EnumerationSpec; |
110 | } |
111 | |
112 | auto ObjectSpecList = HeaderSpec->getValueAsListOfDefs("Objects" ); |
113 | for (llvm::Record *ObjectSpec : ObjectSpecList) { |
114 | auto ObjectName = std::string(ObjectSpec->getValueAsString("Name" )); |
115 | ObjectSpecMap[ObjectName] = ObjectSpec; |
116 | ObjectToHeaderMap[ObjectName] = std::string(Header); |
117 | } |
118 | } |
119 | } |
120 | } |
121 | |
122 | void APIIndexer::indexPublicAPIDef(llvm::Record *PublicAPI) { |
123 | // While indexing the public API, we do not check if any of the entities |
124 | // requested is from an included standard. Such a check is done while |
125 | // generating the API. |
126 | auto MacroDefList = PublicAPI->getValueAsListOfDefs("Macros" ); |
127 | for (llvm::Record *MacroDef : MacroDefList) |
128 | MacroDefsMap[std::string(MacroDef->getValueAsString("Name" ))] = MacroDef; |
129 | |
130 | auto TypeList = PublicAPI->getValueAsListOfStrings("Types" ); |
131 | for (llvm::StringRef TypeName : TypeList) |
132 | RequiredTypes.insert(std::string(TypeName)); |
133 | |
134 | auto StructList = PublicAPI->getValueAsListOfStrings("Structs" ); |
135 | for (llvm::StringRef StructName : StructList) |
136 | Structs.insert(std::string(StructName)); |
137 | |
138 | auto FunctionList = PublicAPI->getValueAsListOfStrings("Functions" ); |
139 | for (llvm::StringRef FunctionName : FunctionList) |
140 | Functions.insert(std::string(FunctionName)); |
141 | |
142 | auto EnumerationList = PublicAPI->getValueAsListOfStrings("Enumerations" ); |
143 | for (llvm::StringRef EnumerationName : EnumerationList) |
144 | Enumerations.insert(std::string(EnumerationName)); |
145 | |
146 | auto ObjectList = PublicAPI->getValueAsListOfStrings("Objects" ); |
147 | for (llvm::StringRef ObjectName : ObjectList) |
148 | Objects.insert(std::string(ObjectName)); |
149 | } |
150 | |
151 | void APIIndexer::index(llvm::RecordKeeper &Records) { |
152 | NamedTypeClass = Records.getClass(NamedTypeClassName); |
153 | PtrTypeClass = Records.getClass(PtrTypeClassName); |
154 | RestrictedPtrTypeClass = Records.getClass(RestrictedPtrTypeClassName); |
155 | StructClass = Records.getClass(StructTypeClassName); |
156 | ConstTypeClass = Records.getClass(ConstTypeClassName); |
157 | StandardSpecClass = Records.getClass(StandardSpecClassName); |
158 | PublicAPIClass = Records.getClass(PublicAPIClassName); |
159 | |
160 | const auto &DefsMap = Records.getDefs(); |
161 | for (auto &Pair : DefsMap) { |
162 | llvm::Record *Def = Pair.second.get(); |
163 | if (isaStandardSpec(Def)) |
164 | indexStandardSpecDef(Def); |
165 | if (isaPublicAPI(Def)) { |
166 | if (!StdHeader.has_value() || |
167 | Def->getValueAsString("HeaderName" ) == StdHeader) |
168 | indexPublicAPIDef(Def); |
169 | } |
170 | } |
171 | } |
172 | |
173 | } // namespace llvm_libc |
174 | |