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