xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1480093f4SDimitry Andric //=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // This tablegen backend emits code for working with Clang AST properties.
10480093f4SDimitry Andric //
11480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12480093f4SDimitry Andric 
13480093f4SDimitry Andric #include "ASTTableGen.h"
14480093f4SDimitry Andric #include "TableGenBackends.h"
15480093f4SDimitry Andric 
16480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h"
17480093f4SDimitry Andric #include "llvm/ADT/Twine.h"
18480093f4SDimitry Andric #include "llvm/TableGen/Error.h"
19480093f4SDimitry Andric #include "llvm/TableGen/Record.h"
20480093f4SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
21480093f4SDimitry Andric #include <cctype>
22480093f4SDimitry Andric #include <map>
23bdd1243dSDimitry Andric #include <optional>
24480093f4SDimitry Andric #include <set>
25480093f4SDimitry Andric #include <string>
26480093f4SDimitry Andric using namespace llvm;
27480093f4SDimitry Andric using namespace clang;
28480093f4SDimitry Andric using namespace clang::tblgen;
29480093f4SDimitry Andric 
getReaderResultType(TypeNode _)30480093f4SDimitry Andric static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
31480093f4SDimitry Andric 
32480093f4SDimitry Andric namespace {
33480093f4SDimitry Andric 
34480093f4SDimitry Andric struct ReaderWriterInfo {
35480093f4SDimitry Andric   bool IsReader;
36480093f4SDimitry Andric 
37480093f4SDimitry Andric   /// The name of the node hierarchy.  Not actually sensitive to IsReader,
38480093f4SDimitry Andric   /// but useful to cache here anyway.
39480093f4SDimitry Andric   StringRef HierarchyName;
40480093f4SDimitry Andric 
41480093f4SDimitry Andric   /// The suffix on classes: Reader/Writer
42480093f4SDimitry Andric   StringRef ClassSuffix;
43480093f4SDimitry Andric 
44480093f4SDimitry Andric   /// The base name of methods: read/write
45480093f4SDimitry Andric   StringRef MethodPrefix;
46480093f4SDimitry Andric 
47480093f4SDimitry Andric   /// The name of the property helper member: R/W
48480093f4SDimitry Andric   StringRef HelperVariable;
49480093f4SDimitry Andric 
50480093f4SDimitry Andric   /// The result type of methods on the class.
51480093f4SDimitry Andric   StringRef ResultType;
52480093f4SDimitry Andric 
53480093f4SDimitry Andric   template <class NodeClass>
forReader__anon8e7483cb0111::ReaderWriterInfo54480093f4SDimitry Andric   static ReaderWriterInfo forReader() {
55480093f4SDimitry Andric     return ReaderWriterInfo{
56480093f4SDimitry Andric       true,
57480093f4SDimitry Andric       NodeClass::getASTHierarchyName(),
58480093f4SDimitry Andric       "Reader",
59480093f4SDimitry Andric       "read",
60480093f4SDimitry Andric       "R",
61480093f4SDimitry Andric       getReaderResultType(NodeClass())
62480093f4SDimitry Andric     };
63480093f4SDimitry Andric   }
64480093f4SDimitry Andric 
65480093f4SDimitry Andric   template <class NodeClass>
forWriter__anon8e7483cb0111::ReaderWriterInfo66480093f4SDimitry Andric   static ReaderWriterInfo forWriter() {
67480093f4SDimitry Andric     return ReaderWriterInfo{
68480093f4SDimitry Andric       false,
69480093f4SDimitry Andric       NodeClass::getASTHierarchyName(),
70480093f4SDimitry Andric       "Writer",
71480093f4SDimitry Andric       "write",
72480093f4SDimitry Andric       "W",
73480093f4SDimitry Andric       "void"
74480093f4SDimitry Andric     };
75480093f4SDimitry Andric   }
76480093f4SDimitry Andric };
77480093f4SDimitry Andric 
78480093f4SDimitry Andric struct NodeInfo {
79480093f4SDimitry Andric   std::vector<Property> Properties;
80480093f4SDimitry Andric   CreationRule Creator = nullptr;
81480093f4SDimitry Andric   OverrideRule Override = nullptr;
82480093f4SDimitry Andric   ReadHelperRule ReadHelper = nullptr;
83480093f4SDimitry Andric };
84480093f4SDimitry Andric 
85480093f4SDimitry Andric struct CasedTypeInfo {
86480093f4SDimitry Andric   TypeKindRule KindRule;
87480093f4SDimitry Andric   std::vector<TypeCase> Cases;
88480093f4SDimitry Andric };
89480093f4SDimitry Andric 
90480093f4SDimitry Andric class ASTPropsEmitter {
91480093f4SDimitry Andric 	raw_ostream &Out;
92480093f4SDimitry Andric 	RecordKeeper &Records;
93480093f4SDimitry Andric 	std::map<HasProperties, NodeInfo> NodeInfos;
94480093f4SDimitry Andric   std::vector<PropertyType> AllPropertyTypes;
95480093f4SDimitry Andric   std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
96480093f4SDimitry Andric 
97480093f4SDimitry Andric public:
ASTPropsEmitter(RecordKeeper & records,raw_ostream & out)98480093f4SDimitry Andric 	ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
99480093f4SDimitry Andric 		: Out(out), Records(records) {
100480093f4SDimitry Andric 
101480093f4SDimitry Andric 		// Find all the properties.
102480093f4SDimitry Andric 		for (Property property :
103480093f4SDimitry Andric            records.getAllDerivedDefinitions(PropertyClassName)) {
104480093f4SDimitry Andric 			HasProperties node = property.getClass();
105480093f4SDimitry Andric 			NodeInfos[node].Properties.push_back(property);
106480093f4SDimitry Andric 		}
107480093f4SDimitry Andric 
108480093f4SDimitry Andric     // Find all the creation rules.
109480093f4SDimitry Andric     for (CreationRule creationRule :
110480093f4SDimitry Andric            records.getAllDerivedDefinitions(CreationRuleClassName)) {
111480093f4SDimitry Andric       HasProperties node = creationRule.getClass();
112480093f4SDimitry Andric 
113480093f4SDimitry Andric       auto &info = NodeInfos[node];
114480093f4SDimitry Andric       if (info.Creator) {
115480093f4SDimitry Andric         PrintFatalError(creationRule.getLoc(),
116480093f4SDimitry Andric                         "multiple creator rules for \"" + node.getName()
117480093f4SDimitry Andric                           + "\"");
118480093f4SDimitry Andric       }
119480093f4SDimitry Andric       info.Creator = creationRule;
120480093f4SDimitry Andric     }
121480093f4SDimitry Andric 
122480093f4SDimitry Andric     // Find all the override rules.
123480093f4SDimitry Andric     for (OverrideRule overrideRule :
124480093f4SDimitry Andric            records.getAllDerivedDefinitions(OverrideRuleClassName)) {
125480093f4SDimitry Andric       HasProperties node = overrideRule.getClass();
126480093f4SDimitry Andric 
127480093f4SDimitry Andric       auto &info = NodeInfos[node];
128480093f4SDimitry Andric       if (info.Override) {
129480093f4SDimitry Andric         PrintFatalError(overrideRule.getLoc(),
130480093f4SDimitry Andric                         "multiple override rules for \"" + node.getName()
131480093f4SDimitry Andric                           + "\"");
132480093f4SDimitry Andric       }
133480093f4SDimitry Andric       info.Override = overrideRule;
134480093f4SDimitry Andric     }
135480093f4SDimitry Andric 
136480093f4SDimitry Andric     // Find all the write helper rules.
137480093f4SDimitry Andric     for (ReadHelperRule helperRule :
138480093f4SDimitry Andric            records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
139480093f4SDimitry Andric       HasProperties node = helperRule.getClass();
140480093f4SDimitry Andric 
141480093f4SDimitry Andric       auto &info = NodeInfos[node];
142480093f4SDimitry Andric       if (info.ReadHelper) {
143480093f4SDimitry Andric         PrintFatalError(helperRule.getLoc(),
144480093f4SDimitry Andric                         "multiple write helper rules for \"" + node.getName()
145480093f4SDimitry Andric                           + "\"");
146480093f4SDimitry Andric       }
147480093f4SDimitry Andric       info.ReadHelper = helperRule;
148480093f4SDimitry Andric     }
149480093f4SDimitry Andric 
150480093f4SDimitry Andric     // Find all the concrete property types.
151480093f4SDimitry Andric     for (PropertyType type :
152480093f4SDimitry Andric            records.getAllDerivedDefinitions(PropertyTypeClassName)) {
153480093f4SDimitry Andric       // Ignore generic specializations; they're generally not useful when
154480093f4SDimitry Andric       // emitting basic emitters etc.
155480093f4SDimitry Andric       if (type.isGenericSpecialization()) continue;
156480093f4SDimitry Andric 
157480093f4SDimitry Andric       AllPropertyTypes.push_back(type);
158480093f4SDimitry Andric     }
159480093f4SDimitry Andric 
160480093f4SDimitry Andric     // Find all the type kind rules.
161480093f4SDimitry Andric     for (TypeKindRule kindRule :
162480093f4SDimitry Andric            records.getAllDerivedDefinitions(TypeKindClassName)) {
163480093f4SDimitry Andric       PropertyType type = kindRule.getParentType();
164480093f4SDimitry Andric       auto &info = CasedTypeInfos[type];
165480093f4SDimitry Andric       if (info.KindRule) {
166480093f4SDimitry Andric         PrintFatalError(kindRule.getLoc(),
167480093f4SDimitry Andric                         "multiple kind rules for \""
168480093f4SDimitry Andric                            + type.getCXXTypeName() + "\"");
169480093f4SDimitry Andric       }
170480093f4SDimitry Andric       info.KindRule = kindRule;
171480093f4SDimitry Andric     }
172480093f4SDimitry Andric 
173480093f4SDimitry Andric     // Find all the type cases.
174480093f4SDimitry Andric     for (TypeCase typeCase :
175480093f4SDimitry Andric            records.getAllDerivedDefinitions(TypeCaseClassName)) {
176480093f4SDimitry Andric       CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
177480093f4SDimitry Andric     }
178480093f4SDimitry Andric 
179480093f4SDimitry Andric     Validator(*this).validate();
180480093f4SDimitry Andric 	}
181480093f4SDimitry Andric 
visitAllProperties(HasProperties derived,const NodeInfo & derivedInfo,function_ref<void (Property)> visit)182480093f4SDimitry Andric   void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
183480093f4SDimitry Andric                           function_ref<void (Property)> visit) {
184480093f4SDimitry Andric     std::set<StringRef> ignoredProperties;
185480093f4SDimitry Andric 
186480093f4SDimitry Andric     auto overrideRule = derivedInfo.Override;
187480093f4SDimitry Andric     if (overrideRule) {
188480093f4SDimitry Andric       auto list = overrideRule.getIgnoredProperties();
189480093f4SDimitry Andric       ignoredProperties.insert(list.begin(), list.end());
190480093f4SDimitry Andric     }
191480093f4SDimitry Andric 
192480093f4SDimitry Andric     // TODO: we should sort the properties in various ways
193480093f4SDimitry Andric     //   - put arrays at the end to enable abbreviations
194480093f4SDimitry Andric     //   - put conditional properties after properties used in the condition
195480093f4SDimitry Andric 
196480093f4SDimitry Andric     visitAllNodesWithInfo(derived, derivedInfo,
197480093f4SDimitry Andric                           [&](HasProperties node, const NodeInfo &info) {
198480093f4SDimitry Andric       for (Property prop : info.Properties) {
199480093f4SDimitry Andric         if (ignoredProperties.count(prop.getName()))
200480093f4SDimitry Andric           continue;
201480093f4SDimitry Andric 
202480093f4SDimitry Andric         visit(prop);
203480093f4SDimitry Andric       }
204480093f4SDimitry Andric     });
205480093f4SDimitry Andric   }
206480093f4SDimitry Andric 
visitAllNodesWithInfo(HasProperties derivedNode,const NodeInfo & derivedNodeInfo,llvm::function_ref<void (HasProperties node,const NodeInfo & info)> visit)207480093f4SDimitry Andric   void visitAllNodesWithInfo(HasProperties derivedNode,
208480093f4SDimitry Andric                              const NodeInfo &derivedNodeInfo,
209480093f4SDimitry Andric                              llvm::function_ref<void (HasProperties node,
210480093f4SDimitry Andric                                                       const NodeInfo &info)>
211480093f4SDimitry Andric                                visit) {
212480093f4SDimitry Andric     visit(derivedNode, derivedNodeInfo);
213480093f4SDimitry Andric 
214480093f4SDimitry Andric     // Also walk the bases if appropriate.
215480093f4SDimitry Andric     if (ASTNode base = derivedNode.getAs<ASTNode>()) {
216480093f4SDimitry Andric       for (base = base.getBase(); base; base = base.getBase()) {
217480093f4SDimitry Andric         auto it = NodeInfos.find(base);
218480093f4SDimitry Andric 
219480093f4SDimitry Andric         // Ignore intermediate nodes that don't add interesting properties.
220480093f4SDimitry Andric         if (it == NodeInfos.end()) continue;
221480093f4SDimitry Andric         auto &baseInfo = it->second;
222480093f4SDimitry Andric 
223480093f4SDimitry Andric         visit(base, baseInfo);
224480093f4SDimitry Andric       }
225480093f4SDimitry Andric     }
226480093f4SDimitry Andric   }
227480093f4SDimitry Andric 
228480093f4SDimitry Andric   template <class NodeClass>
emitNodeReaderClass()229480093f4SDimitry Andric   void emitNodeReaderClass() {
230480093f4SDimitry Andric     auto info = ReaderWriterInfo::forReader<NodeClass>();
231480093f4SDimitry Andric     emitNodeReaderWriterClass<NodeClass>(info);
232480093f4SDimitry Andric   }
233480093f4SDimitry Andric 
234480093f4SDimitry Andric   template <class NodeClass>
emitNodeWriterClass()235480093f4SDimitry Andric   void emitNodeWriterClass() {
236480093f4SDimitry Andric     auto info = ReaderWriterInfo::forWriter<NodeClass>();
237480093f4SDimitry Andric     emitNodeReaderWriterClass<NodeClass>(info);
238480093f4SDimitry Andric   }
239480093f4SDimitry Andric 
240480093f4SDimitry Andric   template <class NodeClass>
241480093f4SDimitry Andric   void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
242480093f4SDimitry Andric 
243480093f4SDimitry Andric   template <class NodeClass>
244480093f4SDimitry Andric   void emitNodeReaderWriterMethod(NodeClass node,
245480093f4SDimitry Andric                                   const ReaderWriterInfo &info);
246480093f4SDimitry Andric 
247480093f4SDimitry Andric   void emitPropertiedReaderWriterBody(HasProperties node,
248480093f4SDimitry Andric                                       const ReaderWriterInfo &info);
249480093f4SDimitry Andric 
250480093f4SDimitry Andric   void emitReadOfProperty(StringRef readerName, Property property);
251480093f4SDimitry Andric   void emitReadOfProperty(StringRef readerName, StringRef name,
252480093f4SDimitry Andric                           PropertyType type, StringRef condition = "");
253480093f4SDimitry Andric 
254480093f4SDimitry Andric   void emitWriteOfProperty(StringRef writerName, Property property);
255480093f4SDimitry Andric   void emitWriteOfProperty(StringRef writerName, StringRef name,
256480093f4SDimitry Andric                            PropertyType type, StringRef readCode,
257480093f4SDimitry Andric                            StringRef condition = "");
258480093f4SDimitry Andric 
259480093f4SDimitry Andric   void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
260480093f4SDimitry Andric   void emitDispatcherTemplate(const ReaderWriterInfo &info);
261480093f4SDimitry Andric   void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
262480093f4SDimitry Andric   void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
263480093f4SDimitry Andric 
264480093f4SDimitry Andric   void emitCasedReaderWriterMethodBody(PropertyType type,
265480093f4SDimitry Andric                                        const CasedTypeInfo &typeCases,
266480093f4SDimitry Andric                                        const ReaderWriterInfo &info);
267480093f4SDimitry Andric 
268480093f4SDimitry Andric private:
269480093f4SDimitry Andric   class Validator {
270480093f4SDimitry Andric     ASTPropsEmitter &Emitter;
271480093f4SDimitry Andric     std::set<HasProperties> ValidatedNodes;
272480093f4SDimitry Andric 
273480093f4SDimitry Andric   public:
Validator(ASTPropsEmitter & emitter)274480093f4SDimitry Andric     Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
275480093f4SDimitry Andric     void validate();
276480093f4SDimitry Andric 
277480093f4SDimitry Andric   private:
278480093f4SDimitry Andric     void validateNode(HasProperties node, const NodeInfo &nodeInfo);
279480093f4SDimitry Andric     void validateType(PropertyType type, WrappedRecord context);
280480093f4SDimitry Andric   };
281480093f4SDimitry Andric };
282480093f4SDimitry Andric 
283480093f4SDimitry Andric } // end anonymous namespace
284480093f4SDimitry Andric 
validate()285480093f4SDimitry Andric void ASTPropsEmitter::Validator::validate() {
286480093f4SDimitry Andric   for (auto &entry : Emitter.NodeInfos) {
287480093f4SDimitry Andric     validateNode(entry.first, entry.second);
288480093f4SDimitry Andric   }
289480093f4SDimitry Andric 
290480093f4SDimitry Andric   if (ErrorsPrinted > 0) {
291480093f4SDimitry Andric     PrintFatalError("property validation failed");
292480093f4SDimitry Andric   }
293480093f4SDimitry Andric }
294480093f4SDimitry Andric 
validateNode(HasProperties derivedNode,const NodeInfo & derivedNodeInfo)295480093f4SDimitry Andric void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
296480093f4SDimitry Andric                                               const NodeInfo &derivedNodeInfo) {
297480093f4SDimitry Andric   if (!ValidatedNodes.insert(derivedNode).second) return;
298480093f4SDimitry Andric 
299480093f4SDimitry Andric   // A map from property name to property.
300480093f4SDimitry Andric   std::map<StringRef, Property> allProperties;
301480093f4SDimitry Andric 
302480093f4SDimitry Andric   Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
303480093f4SDimitry Andric                                 [&](HasProperties node,
304480093f4SDimitry Andric                                     const NodeInfo &nodeInfo) {
305480093f4SDimitry Andric     for (Property property : nodeInfo.Properties) {
306480093f4SDimitry Andric       validateType(property.getType(), property);
307480093f4SDimitry Andric 
308480093f4SDimitry Andric       auto result = allProperties.insert(
309480093f4SDimitry Andric                       std::make_pair(property.getName(), property));
310480093f4SDimitry Andric 
311480093f4SDimitry Andric       // Diagnose non-unique properties.
312480093f4SDimitry Andric       if (!result.second) {
313480093f4SDimitry Andric         // The existing property is more likely to be associated with a
314480093f4SDimitry Andric         // derived node, so use it as the error.
315480093f4SDimitry Andric         Property existingProperty = result.first->second;
316480093f4SDimitry Andric         PrintError(existingProperty.getLoc(),
317480093f4SDimitry Andric                    "multiple properties named \"" + property.getName()
318480093f4SDimitry Andric                       + "\" in hierarchy of " + derivedNode.getName());
319480093f4SDimitry Andric         PrintNote(property.getLoc(), "existing property");
320480093f4SDimitry Andric       }
321480093f4SDimitry Andric     }
322480093f4SDimitry Andric   });
323480093f4SDimitry Andric }
324480093f4SDimitry Andric 
validateType(PropertyType type,WrappedRecord context)325480093f4SDimitry Andric void ASTPropsEmitter::Validator::validateType(PropertyType type,
326480093f4SDimitry Andric                                               WrappedRecord context) {
327480093f4SDimitry Andric   if (!type.isGenericSpecialization()) {
328480093f4SDimitry Andric     if (type.getCXXTypeName() == "") {
329480093f4SDimitry Andric       PrintError(type.getLoc(),
330480093f4SDimitry Andric                  "type is not generic but has no C++ type name");
331480093f4SDimitry Andric       if (context) PrintNote(context.getLoc(), "type used here");
332480093f4SDimitry Andric     }
333480093f4SDimitry Andric   } else if (auto eltType = type.getArrayElementType()) {
334480093f4SDimitry Andric     validateType(eltType, context);
335480093f4SDimitry Andric   } else if (auto valueType = type.getOptionalElementType()) {
336480093f4SDimitry Andric     validateType(valueType, context);
337480093f4SDimitry Andric 
338480093f4SDimitry Andric     if (valueType.getPackOptionalCode().empty()) {
339480093f4SDimitry Andric       PrintError(valueType.getLoc(),
340480093f4SDimitry Andric                  "type doesn't provide optional-packing code");
341480093f4SDimitry Andric       if (context) PrintNote(context.getLoc(), "type used here");
342480093f4SDimitry Andric     } else if (valueType.getUnpackOptionalCode().empty()) {
343480093f4SDimitry Andric       PrintError(valueType.getLoc(),
344480093f4SDimitry Andric                  "type doesn't provide optional-unpacking code");
345480093f4SDimitry Andric       if (context) PrintNote(context.getLoc(), "type used here");
346480093f4SDimitry Andric     }
347480093f4SDimitry Andric   } else {
348480093f4SDimitry Andric     PrintError(type.getLoc(), "unknown generic property type");
349480093f4SDimitry Andric     if (context) PrintNote(context.getLoc(), "type used here");
350480093f4SDimitry Andric   }
351480093f4SDimitry Andric }
352480093f4SDimitry Andric 
353480093f4SDimitry Andric /****************************************************************************/
354480093f4SDimitry Andric /**************************** AST READER/WRITERS ****************************/
355480093f4SDimitry Andric /****************************************************************************/
356480093f4SDimitry Andric 
357480093f4SDimitry Andric template <class NodeClass>
emitNodeReaderWriterClass(const ReaderWriterInfo & info)358480093f4SDimitry Andric void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
359480093f4SDimitry Andric   StringRef suffix = info.ClassSuffix;
360480093f4SDimitry Andric   StringRef var = info.HelperVariable;
361480093f4SDimitry Andric 
362480093f4SDimitry Andric   // Enter the class declaration.
363480093f4SDimitry Andric   Out << "template <class Property" << suffix << ">\n"
364480093f4SDimitry Andric          "class Abstract" << info.HierarchyName << suffix << " {\n"
365480093f4SDimitry Andric          "public:\n"
366480093f4SDimitry Andric          "  Property" << suffix << " &" << var << ";\n\n";
367480093f4SDimitry Andric 
368480093f4SDimitry Andric   // Emit the constructor.
369480093f4SDimitry Andric   Out << "  Abstract" << info.HierarchyName << suffix
370480093f4SDimitry Andric                       << "(Property" << suffix << " &" << var << ") : "
371480093f4SDimitry Andric                       << var << "(" << var << ") {}\n\n";
372480093f4SDimitry Andric 
373480093f4SDimitry Andric   // Emit a method that dispatches on a kind to the appropriate node-specific
374480093f4SDimitry Andric   // method.
375480093f4SDimitry Andric   Out << "  " << info.ResultType << " " << info.MethodPrefix << "(";
376480093f4SDimitry Andric   if (info.IsReader)
377480093f4SDimitry Andric     Out       << NodeClass::getASTIdTypeName() << " kind";
378480093f4SDimitry Andric   else
379480093f4SDimitry Andric     Out       << "const " << info.HierarchyName << " *node";
380480093f4SDimitry Andric   Out         << ") {\n"
381480093f4SDimitry Andric          "    switch (";
382480093f4SDimitry Andric   if (info.IsReader)
383480093f4SDimitry Andric     Out         << "kind";
384480093f4SDimitry Andric   else
385480093f4SDimitry Andric     Out         << "node->" << NodeClass::getASTIdAccessorName() << "()";
386480093f4SDimitry Andric   Out           << ") {\n";
387480093f4SDimitry Andric   visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
388480093f4SDimitry Andric     if (node.isAbstract()) return;
389480093f4SDimitry Andric     Out << "    case " << info.HierarchyName << "::" << node.getId() << ":\n"
390480093f4SDimitry Andric            "      return " << info.MethodPrefix << node.getClassName() << "(";
391480093f4SDimitry Andric     if (!info.IsReader)
392480093f4SDimitry Andric       Out                  << "static_cast<const " << node.getClassName()
393480093f4SDimitry Andric                            << " *>(node)";
394480093f4SDimitry Andric     Out                    << ");\n";
395480093f4SDimitry Andric   });
396480093f4SDimitry Andric   Out << "    }\n"
397480093f4SDimitry Andric          "    llvm_unreachable(\"bad kind\");\n"
398480093f4SDimitry Andric          "  }\n\n";
399480093f4SDimitry Andric 
400480093f4SDimitry Andric   // Emit node-specific methods for all the concrete nodes.
401480093f4SDimitry Andric   visitASTNodeHierarchy<NodeClass>(Records,
402480093f4SDimitry Andric                                    [&](NodeClass node, NodeClass base) {
403480093f4SDimitry Andric     if (node.isAbstract()) return;
404480093f4SDimitry Andric     emitNodeReaderWriterMethod(node, info);
405480093f4SDimitry Andric   });
406480093f4SDimitry Andric 
407480093f4SDimitry Andric   // Finish the class.
408480093f4SDimitry Andric   Out << "};\n\n";
409480093f4SDimitry Andric }
410480093f4SDimitry Andric 
411480093f4SDimitry Andric /// Emit a reader method for the given concrete AST node class.
412480093f4SDimitry Andric template <class NodeClass>
emitNodeReaderWriterMethod(NodeClass node,const ReaderWriterInfo & info)413480093f4SDimitry Andric void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
414480093f4SDimitry Andric                                            const ReaderWriterInfo &info) {
415480093f4SDimitry Andric   // Declare and start the method.
416480093f4SDimitry Andric   Out << "  " << info.ResultType << " "
417480093f4SDimitry Andric               << info.MethodPrefix << node.getClassName() << "(";
418480093f4SDimitry Andric   if (!info.IsReader)
419480093f4SDimitry Andric     Out <<       "const " << node.getClassName() << " *node";
420480093f4SDimitry Andric   Out <<         ") {\n";
421480093f4SDimitry Andric   if (info.IsReader)
422480093f4SDimitry Andric     Out << "    auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
423480093f4SDimitry Andric 
424480093f4SDimitry Andric   emitPropertiedReaderWriterBody(node, info);
425480093f4SDimitry Andric 
426480093f4SDimitry Andric   // Finish the method declaration.
427480093f4SDimitry Andric   Out << "  }\n\n";
428480093f4SDimitry Andric }
429480093f4SDimitry Andric 
emitPropertiedReaderWriterBody(HasProperties node,const ReaderWriterInfo & info)430480093f4SDimitry Andric void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
431480093f4SDimitry Andric                                                const ReaderWriterInfo &info) {
432480093f4SDimitry Andric   // Find the information for this node.
433480093f4SDimitry Andric   auto it = NodeInfos.find(node);
434480093f4SDimitry Andric   if (it == NodeInfos.end())
435480093f4SDimitry Andric     PrintFatalError(node.getLoc(),
436480093f4SDimitry Andric                     "no information about how to deserialize \""
437480093f4SDimitry Andric                       + node.getName() + "\"");
438480093f4SDimitry Andric   auto &nodeInfo = it->second;
439480093f4SDimitry Andric 
440480093f4SDimitry Andric   StringRef creationCode;
441480093f4SDimitry Andric   if (info.IsReader) {
442480093f4SDimitry Andric     // We should have a creation rule.
443480093f4SDimitry Andric     if (!nodeInfo.Creator)
444480093f4SDimitry Andric       PrintFatalError(node.getLoc(),
445480093f4SDimitry Andric                       "no " CreationRuleClassName " for \""
446480093f4SDimitry Andric                         + node.getName() + "\"");
447480093f4SDimitry Andric 
448480093f4SDimitry Andric     creationCode = nodeInfo.Creator.getCreationCode();
449480093f4SDimitry Andric   }
450480093f4SDimitry Andric 
451480093f4SDimitry Andric   // Emit the ReadHelper code, if present.
452480093f4SDimitry Andric   if (!info.IsReader && nodeInfo.ReadHelper) {
453480093f4SDimitry Andric     Out << "    " << nodeInfo.ReadHelper.getHelperCode() << "\n";
454480093f4SDimitry Andric   }
455480093f4SDimitry Andric 
456480093f4SDimitry Andric   // Emit code to read all the properties.
457480093f4SDimitry Andric   visitAllProperties(node, nodeInfo, [&](Property prop) {
458480093f4SDimitry Andric     // Verify that the creation code refers to this property.
459349cc55cSDimitry Andric     if (info.IsReader && !creationCode.contains(prop.getName()))
460480093f4SDimitry Andric       PrintFatalError(nodeInfo.Creator.getLoc(),
461480093f4SDimitry Andric                       "creation code for " + node.getName()
462480093f4SDimitry Andric                         + " doesn't refer to property \""
463480093f4SDimitry Andric                         + prop.getName() + "\"");
464480093f4SDimitry Andric 
465480093f4SDimitry Andric     // Emit code to read or write this property.
466480093f4SDimitry Andric     if (info.IsReader)
467480093f4SDimitry Andric       emitReadOfProperty(info.HelperVariable, prop);
468480093f4SDimitry Andric     else
469480093f4SDimitry Andric       emitWriteOfProperty(info.HelperVariable, prop);
470480093f4SDimitry Andric   });
471480093f4SDimitry Andric 
472480093f4SDimitry Andric   // Emit the final creation code.
473480093f4SDimitry Andric   if (info.IsReader)
474480093f4SDimitry Andric     Out << "    " << creationCode << "\n";
475480093f4SDimitry Andric }
476480093f4SDimitry Andric 
emitBasicReaderWriterMethodSuffix(raw_ostream & out,PropertyType type,bool isForRead)477480093f4SDimitry Andric static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
478480093f4SDimitry Andric                                               PropertyType type,
479480093f4SDimitry Andric                                               bool isForRead) {
480480093f4SDimitry Andric   if (!type.isGenericSpecialization()) {
481480093f4SDimitry Andric     out << type.getAbstractTypeName();
482480093f4SDimitry Andric   } else if (auto eltType = type.getArrayElementType()) {
483480093f4SDimitry Andric     out << "Array";
484480093f4SDimitry Andric     // We only include an explicit template argument for reads so that
485480093f4SDimitry Andric     // we don't cause spurious const mismatches.
486480093f4SDimitry Andric     if (isForRead) {
487480093f4SDimitry Andric       out << "<";
488480093f4SDimitry Andric       eltType.emitCXXValueTypeName(isForRead, out);
489480093f4SDimitry Andric       out << ">";
490480093f4SDimitry Andric     }
491480093f4SDimitry Andric   } else if (auto valueType = type.getOptionalElementType()) {
492480093f4SDimitry Andric     out << "Optional";
493480093f4SDimitry Andric     // We only include an explicit template argument for reads so that
494480093f4SDimitry Andric     // we don't cause spurious const mismatches.
495480093f4SDimitry Andric     if (isForRead) {
496480093f4SDimitry Andric       out << "<";
497480093f4SDimitry Andric       valueType.emitCXXValueTypeName(isForRead, out);
498480093f4SDimitry Andric       out << ">";
499480093f4SDimitry Andric     }
500480093f4SDimitry Andric   } else {
501480093f4SDimitry Andric     PrintFatalError(type.getLoc(), "unexpected generic property type");
502480093f4SDimitry Andric   }
503480093f4SDimitry Andric }
504480093f4SDimitry Andric 
505480093f4SDimitry Andric /// Emit code to read the given property in a node-reader method.
emitReadOfProperty(StringRef readerName,Property property)506480093f4SDimitry Andric void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
507480093f4SDimitry Andric                                          Property property) {
508480093f4SDimitry Andric   emitReadOfProperty(readerName, property.getName(), property.getType(),
509480093f4SDimitry Andric                      property.getCondition());
510480093f4SDimitry Andric }
511480093f4SDimitry Andric 
emitReadOfProperty(StringRef readerName,StringRef name,PropertyType type,StringRef condition)512480093f4SDimitry Andric void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
513480093f4SDimitry Andric                                          StringRef name,
514480093f4SDimitry Andric                                          PropertyType type,
515480093f4SDimitry Andric                                          StringRef condition) {
516480093f4SDimitry Andric   // Declare all the necessary buffers.
517480093f4SDimitry Andric   auto bufferTypes = type.getBufferElementTypes();
518480093f4SDimitry Andric   for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
519480093f4SDimitry Andric     Out << "    llvm::SmallVector<";
520480093f4SDimitry Andric     PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
521480093f4SDimitry Andric     Out << ", 8> " << name << "_buffer_" << i << ";\n";
522480093f4SDimitry Andric   }
523480093f4SDimitry Andric 
524480093f4SDimitry Andric   //   T prop = R.find("prop").read##ValueType(buffers...);
525480093f4SDimitry Andric   // We intentionally ignore shouldPassByReference here: we're going to
526480093f4SDimitry Andric   // get a pr-value back from read(), and we should be able to forward
527480093f4SDimitry Andric   // that in the creation rule.
528480093f4SDimitry Andric   Out << "    ";
529bdd1243dSDimitry Andric   if (!condition.empty())
530bdd1243dSDimitry Andric     Out << "std::optional<";
531480093f4SDimitry Andric   type.emitCXXValueTypeName(true, Out);
532480093f4SDimitry Andric   if (!condition.empty()) Out << ">";
533480093f4SDimitry Andric   Out << " " << name;
534480093f4SDimitry Andric 
535480093f4SDimitry Andric   if (condition.empty()) {
536480093f4SDimitry Andric     Out << " = ";
537480093f4SDimitry Andric   } else {
538480093f4SDimitry Andric     Out << ";\n"
539480093f4SDimitry Andric            "    if (" << condition << ") {\n"
540480093f4SDimitry Andric            "      " << name << ".emplace(";
541480093f4SDimitry Andric   }
542480093f4SDimitry Andric 
543480093f4SDimitry Andric   Out << readerName << ".find(\"" << name << "\")."
544480093f4SDimitry Andric       << (type.isGenericSpecialization() ? "template " : "") << "read";
545480093f4SDimitry Andric   emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
546480093f4SDimitry Andric   Out << "(";
547480093f4SDimitry Andric   for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
548480093f4SDimitry Andric     Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
549480093f4SDimitry Andric   }
550480093f4SDimitry Andric   Out << ")";
551480093f4SDimitry Andric 
552480093f4SDimitry Andric   if (condition.empty()) {
553480093f4SDimitry Andric     Out << ";\n";
554480093f4SDimitry Andric   } else {
555480093f4SDimitry Andric     Out << ");\n"
556480093f4SDimitry Andric            "    }\n";
557480093f4SDimitry Andric   }
558480093f4SDimitry Andric }
559480093f4SDimitry Andric 
560480093f4SDimitry Andric /// Emit code to write the given property in a node-writer method.
emitWriteOfProperty(StringRef writerName,Property property)561480093f4SDimitry Andric void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
562480093f4SDimitry Andric                                           Property property) {
563480093f4SDimitry Andric   emitWriteOfProperty(writerName, property.getName(), property.getType(),
564480093f4SDimitry Andric                       property.getReadCode(), property.getCondition());
565480093f4SDimitry Andric }
566480093f4SDimitry Andric 
emitWriteOfProperty(StringRef writerName,StringRef name,PropertyType type,StringRef readCode,StringRef condition)567480093f4SDimitry Andric void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
568480093f4SDimitry Andric                                           StringRef name,
569480093f4SDimitry Andric                                           PropertyType type,
570480093f4SDimitry Andric                                           StringRef readCode,
571480093f4SDimitry Andric                                           StringRef condition) {
572480093f4SDimitry Andric   if (!condition.empty()) {
573480093f4SDimitry Andric     Out << "    if (" << condition << ") {\n";
574480093f4SDimitry Andric   }
575480093f4SDimitry Andric 
576480093f4SDimitry Andric   // Focus down to the property:
577480093f4SDimitry Andric   //   T prop = <READ>;
578480093f4SDimitry Andric   //   W.find("prop").write##ValueType(prop);
579480093f4SDimitry Andric   Out << "    ";
580480093f4SDimitry Andric   type.emitCXXValueTypeName(false, Out);
581480093f4SDimitry Andric   Out << " " << name << " = (" << readCode << ");\n"
582480093f4SDimitry Andric          "    " << writerName << ".find(\"" << name << "\").write";
583480093f4SDimitry Andric   emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
584480093f4SDimitry Andric   Out << "(" << name << ");\n";
585480093f4SDimitry Andric 
586480093f4SDimitry Andric   if (!condition.empty()) {
587480093f4SDimitry Andric     Out << "    }\n";
588480093f4SDimitry Andric   }
589480093f4SDimitry Andric }
590480093f4SDimitry Andric 
591480093f4SDimitry Andric /// Emit an .inc file that defines the AbstractFooReader class
592480093f4SDimitry Andric /// for the given AST class hierarchy.
593480093f4SDimitry Andric template <class NodeClass>
emitASTReader(RecordKeeper & records,raw_ostream & out,StringRef description)594480093f4SDimitry Andric static void emitASTReader(RecordKeeper &records, raw_ostream &out,
595480093f4SDimitry Andric                           StringRef description) {
596*5f757f3fSDimitry Andric   emitSourceFileHeader(description, out, records);
597480093f4SDimitry Andric 
598480093f4SDimitry Andric   ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
599480093f4SDimitry Andric }
600480093f4SDimitry Andric 
EmitClangTypeReader(RecordKeeper & records,raw_ostream & out)601480093f4SDimitry Andric void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
602480093f4SDimitry Andric   emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
603480093f4SDimitry Andric }
604480093f4SDimitry Andric 
605480093f4SDimitry Andric /// Emit an .inc file that defines the AbstractFooWriter class
606480093f4SDimitry Andric /// for the given AST class hierarchy.
607480093f4SDimitry Andric template <class NodeClass>
emitASTWriter(RecordKeeper & records,raw_ostream & out,StringRef description)608480093f4SDimitry Andric static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
609480093f4SDimitry Andric                           StringRef description) {
610*5f757f3fSDimitry Andric   emitSourceFileHeader(description, out, records);
611480093f4SDimitry Andric 
612480093f4SDimitry Andric   ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
613480093f4SDimitry Andric }
614480093f4SDimitry Andric 
EmitClangTypeWriter(RecordKeeper & records,raw_ostream & out)615480093f4SDimitry Andric void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
616480093f4SDimitry Andric   emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
617480093f4SDimitry Andric }
618480093f4SDimitry Andric 
619480093f4SDimitry Andric /****************************************************************************/
620480093f4SDimitry Andric /*************************** BASIC READER/WRITERS ***************************/
621480093f4SDimitry Andric /****************************************************************************/
622480093f4SDimitry Andric 
623480093f4SDimitry Andric void
emitDispatcherTemplate(const ReaderWriterInfo & info)624480093f4SDimitry Andric ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
625480093f4SDimitry Andric   // Declare the {Read,Write}Dispatcher template.
626480093f4SDimitry Andric   StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
627480093f4SDimitry Andric   Out << "template <class ValueType>\n"
628480093f4SDimitry Andric          "struct " << dispatcherPrefix << "Dispatcher;\n";
629480093f4SDimitry Andric 
630480093f4SDimitry Andric   // Declare a specific specialization of the dispatcher template.
631480093f4SDimitry Andric   auto declareSpecialization =
632480093f4SDimitry Andric     [&](StringRef specializationParameters,
633480093f4SDimitry Andric         const Twine &cxxTypeName,
634480093f4SDimitry Andric         StringRef methodSuffix) {
635480093f4SDimitry Andric     StringRef var = info.HelperVariable;
636480093f4SDimitry Andric     Out << "template " << specializationParameters << "\n"
637480093f4SDimitry Andric            "struct " << dispatcherPrefix << "Dispatcher<"
638480093f4SDimitry Andric                      << cxxTypeName << "> {\n";
639480093f4SDimitry Andric     Out << "  template <class Basic" << info.ClassSuffix << ", class... Args>\n"
640480093f4SDimitry Andric            "  static " << (info.IsReader ? cxxTypeName : "void") << " "
641480093f4SDimitry Andric                        << info.MethodPrefix
642480093f4SDimitry Andric                        << "(Basic" << info.ClassSuffix << " &" << var
643480093f4SDimitry Andric                        << ", Args &&... args) {\n"
644480093f4SDimitry Andric            "    return " << var << "."
645480093f4SDimitry Andric                          << info.MethodPrefix << methodSuffix
646480093f4SDimitry Andric                          << "(std::forward<Args>(args)...);\n"
647480093f4SDimitry Andric            "  }\n"
648480093f4SDimitry Andric            "};\n";
649480093f4SDimitry Andric   };
650480093f4SDimitry Andric 
651480093f4SDimitry Andric   // Declare explicit specializations for each of the concrete types.
652480093f4SDimitry Andric   for (PropertyType type : AllPropertyTypes) {
653480093f4SDimitry Andric     declareSpecialization("<>",
654480093f4SDimitry Andric                           type.getCXXTypeName(),
655480093f4SDimitry Andric                           type.getAbstractTypeName());
656480093f4SDimitry Andric     // Also declare a specialization for the const type when appropriate.
657480093f4SDimitry Andric     if (!info.IsReader && type.isConstWhenWriting()) {
658480093f4SDimitry Andric       declareSpecialization("<>",
659480093f4SDimitry Andric                             "const " + type.getCXXTypeName(),
660480093f4SDimitry Andric                             type.getAbstractTypeName());
661480093f4SDimitry Andric     }
662480093f4SDimitry Andric   }
663480093f4SDimitry Andric   // Declare partial specializations for ArrayRef and Optional.
664480093f4SDimitry Andric   declareSpecialization("<class T>",
665480093f4SDimitry Andric                         "llvm::ArrayRef<T>",
666480093f4SDimitry Andric                         "Array");
667bdd1243dSDimitry Andric   declareSpecialization("<class T>", "std::optional<T>", "Optional");
668480093f4SDimitry Andric   Out << "\n";
669480093f4SDimitry Andric }
670480093f4SDimitry Andric 
671480093f4SDimitry Andric void
emitPackUnpackOptionalTemplate(const ReaderWriterInfo & info)672480093f4SDimitry Andric ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
673480093f4SDimitry Andric   StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674480093f4SDimitry Andric   StringRef methodName = (info.IsReader ? "unpack" : "pack");
675480093f4SDimitry Andric 
676480093f4SDimitry Andric   // Declare the {Pack,Unpack}OptionalValue template.
677480093f4SDimitry Andric   Out << "template <class ValueType>\n"
678480093f4SDimitry Andric          "struct " << classPrefix << "OptionalValue;\n";
679480093f4SDimitry Andric 
680bdd1243dSDimitry Andric   auto declareSpecialization = [&](const Twine &typeName, StringRef code) {
681480093f4SDimitry Andric     Out << "template <>\n"
682bdd1243dSDimitry Andric            "struct "
683bdd1243dSDimitry Andric         << classPrefix << "OptionalValue<" << typeName
684bdd1243dSDimitry Andric         << "> {\n"
685bdd1243dSDimitry Andric            "  static "
686bdd1243dSDimitry Andric         << (info.IsReader ? "std::optional<" : "") << typeName
687480093f4SDimitry Andric         << (info.IsReader ? "> " : " ") << methodName << "("
688bdd1243dSDimitry Andric         << (info.IsReader ? "" : "std::optional<") << typeName
689bdd1243dSDimitry Andric         << (info.IsReader ? "" : ">")
690bdd1243dSDimitry Andric         << " value) {\n"
691bdd1243dSDimitry Andric            "    return "
692bdd1243dSDimitry Andric         << code
693bdd1243dSDimitry Andric         << ";\n"
694480093f4SDimitry Andric            "  }\n"
695480093f4SDimitry Andric            "};\n";
696480093f4SDimitry Andric   };
697480093f4SDimitry Andric 
698480093f4SDimitry Andric   for (PropertyType type : AllPropertyTypes) {
699480093f4SDimitry Andric     StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
700480093f4SDimitry Andric                                     : type.getPackOptionalCode());
701480093f4SDimitry Andric     if (code.empty()) continue;
702480093f4SDimitry Andric 
703480093f4SDimitry Andric     StringRef typeName = type.getCXXTypeName();
704480093f4SDimitry Andric     declareSpecialization(typeName, code);
705480093f4SDimitry Andric     if (type.isConstWhenWriting() && !info.IsReader)
706480093f4SDimitry Andric       declareSpecialization("const " + typeName, code);
707480093f4SDimitry Andric   }
708480093f4SDimitry Andric   Out << "\n";
709480093f4SDimitry Andric }
710480093f4SDimitry Andric 
711480093f4SDimitry Andric void
emitBasicReaderWriterTemplate(const ReaderWriterInfo & info)712480093f4SDimitry Andric ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
713480093f4SDimitry Andric   // Emit the Basic{Reader,Writer}Base template.
714480093f4SDimitry Andric   Out << "template <class Impl>\n"
715480093f4SDimitry Andric          "class Basic" << info.ClassSuffix << "Base {\n";
716480093f4SDimitry Andric   Out << "  ASTContext &C;\n";
717480093f4SDimitry Andric   Out << "protected:\n"
718e8d8bef9SDimitry Andric          "  Basic"
719e8d8bef9SDimitry Andric       << info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
720480093f4SDimitry Andric       << " {}\n"
721480093f4SDimitry Andric          "public:\n";
722480093f4SDimitry Andric   Out << "  ASTContext &getASTContext() { return C; }\n";
723480093f4SDimitry Andric   Out << "  Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
724480093f4SDimitry Andric 
725480093f4SDimitry Andric   auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
726480093f4SDimitry Andric                                      StringRef abstractTypeName,
727480093f4SDimitry Andric                                      bool shouldPassByReference,
728480093f4SDimitry Andric                                      bool constWhenWriting,
729480093f4SDimitry Andric                                      StringRef paramName) {
730480093f4SDimitry Andric     Out << "  " << (info.IsReader ? cxxTypeName : "void")
731480093f4SDimitry Andric                 << " " << info.MethodPrefix << abstractTypeName << "(";
732480093f4SDimitry Andric     if (!info.IsReader)
733480093f4SDimitry Andric       Out       << (shouldPassByReference || constWhenWriting ? "const " : "")
734480093f4SDimitry Andric                 << cxxTypeName
735480093f4SDimitry Andric                 << (shouldPassByReference ? " &" : "") << " " << paramName;
736480093f4SDimitry Andric     Out         << ") {\n";
737480093f4SDimitry Andric   };
738480093f4SDimitry Andric 
739480093f4SDimitry Andric   // Emit {read,write}ValueType methods for all the enum and subclass types
740480093f4SDimitry Andric   // that default to using the integer/base-class implementations.
741480093f4SDimitry Andric   for (PropertyType type : AllPropertyTypes) {
742480093f4SDimitry Andric     auto enterMethod = [&](StringRef paramName) {
743480093f4SDimitry Andric       enterReaderWriterMethod(type.getCXXTypeName(),
744480093f4SDimitry Andric                               type.getAbstractTypeName(),
745480093f4SDimitry Andric                               type.shouldPassByReference(),
746480093f4SDimitry Andric                               type.isConstWhenWriting(),
747480093f4SDimitry Andric                               paramName);
748480093f4SDimitry Andric     };
749480093f4SDimitry Andric     auto exitMethod = [&] {
750480093f4SDimitry Andric       Out << "  }\n";
751480093f4SDimitry Andric     };
752480093f4SDimitry Andric 
753480093f4SDimitry Andric     // Handled cased types.
754480093f4SDimitry Andric     auto casedIter = CasedTypeInfos.find(type);
755480093f4SDimitry Andric     if (casedIter != CasedTypeInfos.end()) {
756480093f4SDimitry Andric       enterMethod("node");
757480093f4SDimitry Andric       emitCasedReaderWriterMethodBody(type, casedIter->second, info);
758480093f4SDimitry Andric       exitMethod();
759480093f4SDimitry Andric 
760480093f4SDimitry Andric     } else if (type.isEnum()) {
761480093f4SDimitry Andric       enterMethod("value");
762480093f4SDimitry Andric       if (info.IsReader)
763480093f4SDimitry Andric         Out << "    return asImpl().template readEnum<"
764480093f4SDimitry Andric             <<         type.getCXXTypeName() << ">();\n";
765480093f4SDimitry Andric       else
766480093f4SDimitry Andric         Out << "    asImpl().writeEnum(value);\n";
767480093f4SDimitry Andric       exitMethod();
768480093f4SDimitry Andric 
769480093f4SDimitry Andric     } else if (PropertyType superclass = type.getSuperclassType()) {
770480093f4SDimitry Andric       enterMethod("value");
771480093f4SDimitry Andric       if (info.IsReader)
772480093f4SDimitry Andric         Out << "    return cast_or_null<" << type.getSubclassClassName()
773480093f4SDimitry Andric                                           << ">(asImpl().read"
774480093f4SDimitry Andric                                           << superclass.getAbstractTypeName()
775480093f4SDimitry Andric                                           << "());\n";
776480093f4SDimitry Andric       else
777480093f4SDimitry Andric         Out << "    asImpl().write" << superclass.getAbstractTypeName()
778480093f4SDimitry Andric                                     << "(value);\n";
779480093f4SDimitry Andric       exitMethod();
780480093f4SDimitry Andric 
781480093f4SDimitry Andric     } else {
782480093f4SDimitry Andric       // The other types can't be handled as trivially.
783480093f4SDimitry Andric     }
784480093f4SDimitry Andric   }
785480093f4SDimitry Andric   Out << "};\n\n";
786480093f4SDimitry Andric }
787480093f4SDimitry Andric 
emitCasedReaderWriterMethodBody(PropertyType type,const CasedTypeInfo & typeCases,const ReaderWriterInfo & info)788480093f4SDimitry Andric void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
789480093f4SDimitry Andric                                              const CasedTypeInfo &typeCases,
790480093f4SDimitry Andric                                              const ReaderWriterInfo &info) {
791480093f4SDimitry Andric   if (typeCases.Cases.empty()) {
792480093f4SDimitry Andric     assert(typeCases.KindRule);
793480093f4SDimitry Andric     PrintFatalError(typeCases.KindRule.getLoc(),
794480093f4SDimitry Andric                     "no cases found for \"" + type.getCXXTypeName() + "\"");
795480093f4SDimitry Andric   }
796480093f4SDimitry Andric   if (!typeCases.KindRule) {
797480093f4SDimitry Andric     assert(!typeCases.Cases.empty());
798480093f4SDimitry Andric     PrintFatalError(typeCases.Cases.front().getLoc(),
799480093f4SDimitry Andric                     "no kind rule for \"" + type.getCXXTypeName() + "\"");
800480093f4SDimitry Andric   }
801480093f4SDimitry Andric 
802480093f4SDimitry Andric   auto var = info.HelperVariable;
803480093f4SDimitry Andric   std::string subvar = ("sub" + var).str();
804480093f4SDimitry Andric 
805480093f4SDimitry Andric   // Bind `ctx` for readers.
806480093f4SDimitry Andric   if (info.IsReader)
807480093f4SDimitry Andric     Out << "    auto &ctx = asImpl().getASTContext();\n";
808480093f4SDimitry Andric 
809480093f4SDimitry Andric   // Start an object.
810480093f4SDimitry Andric   Out << "    auto &&" << subvar << " = asImpl()."
811480093f4SDimitry Andric                        << info.MethodPrefix << "Object();\n";
812480093f4SDimitry Andric 
813480093f4SDimitry Andric   // Read/write the kind property;
814480093f4SDimitry Andric   TypeKindRule kindRule = typeCases.KindRule;
815480093f4SDimitry Andric   StringRef kindProperty = kindRule.getKindPropertyName();
816480093f4SDimitry Andric   PropertyType kindType = kindRule.getKindType();
817480093f4SDimitry Andric   if (info.IsReader) {
818480093f4SDimitry Andric     emitReadOfProperty(subvar, kindProperty, kindType);
819480093f4SDimitry Andric   } else {
820480093f4SDimitry Andric     // Write the property.  Note that this will implicitly read the
821480093f4SDimitry Andric     // kind into a local variable with the right name.
822480093f4SDimitry Andric     emitWriteOfProperty(subvar, kindProperty, kindType,
823480093f4SDimitry Andric                         kindRule.getReadCode());
824480093f4SDimitry Andric   }
825480093f4SDimitry Andric 
826480093f4SDimitry Andric   // Prepare a ReaderWriterInfo with a helper variable that will use
827480093f4SDimitry Andric   // the sub-reader/writer.
828480093f4SDimitry Andric   ReaderWriterInfo subInfo = info;
829480093f4SDimitry Andric   subInfo.HelperVariable = subvar;
830480093f4SDimitry Andric 
831480093f4SDimitry Andric   // Switch on the kind.
832480093f4SDimitry Andric   Out << "    switch (" << kindProperty << ") {\n";
833480093f4SDimitry Andric   for (TypeCase typeCase : typeCases.Cases) {
834480093f4SDimitry Andric     Out << "    case " << type.getCXXTypeName() << "::"
835480093f4SDimitry Andric                        << typeCase.getCaseName() << ": {\n";
836480093f4SDimitry Andric     emitPropertiedReaderWriterBody(typeCase, subInfo);
837480093f4SDimitry Andric     if (!info.IsReader)
838480093f4SDimitry Andric       Out << "    return;\n";
839480093f4SDimitry Andric     Out << "    }\n\n";
840480093f4SDimitry Andric   }
841480093f4SDimitry Andric   Out << "    }\n"
842480093f4SDimitry Andric          "    llvm_unreachable(\"bad " << kindType.getCXXTypeName()
843480093f4SDimitry Andric                                        << "\");\n";
844480093f4SDimitry Andric }
845480093f4SDimitry Andric 
emitBasicReaderWriterFile(const ReaderWriterInfo & info)846480093f4SDimitry Andric void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
847480093f4SDimitry Andric   emitDispatcherTemplate(info);
848480093f4SDimitry Andric   emitPackUnpackOptionalTemplate(info);
849480093f4SDimitry Andric   emitBasicReaderWriterTemplate(info);
850480093f4SDimitry Andric }
851480093f4SDimitry Andric 
852480093f4SDimitry Andric /// Emit an .inc file that defines some helper classes for reading
853480093f4SDimitry Andric /// basic values.
EmitClangBasicReader(RecordKeeper & records,raw_ostream & out)854480093f4SDimitry Andric void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
855*5f757f3fSDimitry Andric   emitSourceFileHeader("Helper classes for BasicReaders", out, records);
856480093f4SDimitry Andric 
857480093f4SDimitry Andric   // Use any property, we won't be using those properties.
858480093f4SDimitry Andric   auto info = ReaderWriterInfo::forReader<TypeNode>();
859480093f4SDimitry Andric   ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
860480093f4SDimitry Andric }
861480093f4SDimitry Andric 
862480093f4SDimitry Andric /// Emit an .inc file that defines some helper classes for writing
863480093f4SDimitry Andric /// basic values.
EmitClangBasicWriter(RecordKeeper & records,raw_ostream & out)864480093f4SDimitry Andric void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
865*5f757f3fSDimitry Andric   emitSourceFileHeader("Helper classes for BasicWriters", out, records);
866480093f4SDimitry Andric 
867480093f4SDimitry Andric   // Use any property, we won't be using those properties.
868480093f4SDimitry Andric   auto info = ReaderWriterInfo::forWriter<TypeNode>();
869480093f4SDimitry Andric   ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
870480093f4SDimitry Andric }
871