clang 19.0.0git
generate_cxx_src_locs.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4import os
5import sys
6import json
7import filecmp
8import shutil
9import argparse
10
11
13
14 implementationContent = ""
15
16 RefClades = {
17 "DeclarationNameInfo",
18 "NestedNameSpecifierLoc",
19 "TemplateArgumentLoc",
20 "TypeLoc",
21 }
22
23 def __init__(self, templateClasses):
24 self.templateClasses = templateClasses
25
27
28 self.implementationContent += r"""
29/*===- Generated file -------------------------------------------*- C++ -*-===*\
30|* *|
31|* Introspection of available AST node SourceLocations *|
32|* *|
33|* Automatically generated file, do not edit! *|
34|* *|
35\*===----------------------------------------------------------------------===*/
36
37namespace clang {
38namespace tooling {
39
40using LocationAndString = SourceLocationMap::value_type;
41using RangeAndString = SourceRangeMap::value_type;
42
43bool NodeIntrospection::hasIntrospectionSupport() { return true; }
44
45struct RecursionPopper
46{
47 RecursionPopper(std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
48 : TLRG(TypeLocRecursionGuard)
49 {
50
51 }
52
53 ~RecursionPopper()
54 {
55 TLRG.pop_back();
56 }
57
58private:
59std::vector<clang::TypeLoc> &TLRG;
60};
61"""
62
64 InstanceDecoration = "*"
65 if CladeName in self.RefClades:
66 InstanceDecoration = "&"
67
68 self.implementationContent += """
69void GetLocationsImpl(SharedLocationCall const& Prefix,
70 clang::{0} const {1}Object, SourceLocationMap &Locs,
71 SourceRangeMap &Rngs,
72 std::vector<clang::TypeLoc> &TypeLocRecursionGuard);
73""".format(
74 CladeName, InstanceDecoration
75 )
76
77 def GenerateSrcLocMethod(self, ClassName, ClassData, CreateLocalRecursionGuard):
78
79 NormalClassName = ClassName
80 RecursionGuardParam = (
81 ""
82 if CreateLocalRecursionGuard
83 else ", std::vector<clang::TypeLoc>& TypeLocRecursionGuard"
84 )
85
86 if "templateParms" in ClassData:
87 TemplatePreamble = "template <typename "
88 ClassName += "<"
89 First = True
90 for TA in ClassData["templateParms"]:
91 if not First:
92 ClassName += ", "
93 TemplatePreamble += ", typename "
94
95 First = False
96 ClassName += TA
97 TemplatePreamble += TA
98
99 ClassName += ">"
100 TemplatePreamble += ">\n"
101 self.implementationContent += TemplatePreamble
102
103 self.implementationContent += """
104static void GetLocations{0}(SharedLocationCall const& Prefix,
105 clang::{1} const &Object,
106 SourceLocationMap &Locs, SourceRangeMap &Rngs {2})
107{{
108""".format(
109 NormalClassName, ClassName, RecursionGuardParam
110 )
111
112 if "sourceLocations" in ClassData:
113 for locName in ClassData["sourceLocations"]:
114 self.implementationContent += """
115 Locs.insert(LocationAndString(Object.{0}(),
116 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
117""".format(
118 locName
119 )
120
121 self.implementationContent += "\n"
122
123 if "sourceRanges" in ClassData:
124 for rngName in ClassData["sourceRanges"]:
125 self.implementationContent += """
126 Rngs.insert(RangeAndString(Object.{0}(),
127 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
128""".format(
129 rngName
130 )
131
132 self.implementationContent += "\n"
133
134 if (
135 "typeLocs" in ClassData
136 or "typeSourceInfos" in ClassData
137 or "nestedNameLocs" in ClassData
138 or "declNameInfos" in ClassData
139 ):
140 if CreateLocalRecursionGuard:
141 self.implementationContent += (
142 "std::vector<clang::TypeLoc> TypeLocRecursionGuard;\n"
143 )
144
145 self.implementationContent += "\n"
146
147 if "typeLocs" in ClassData:
148 for typeLoc in ClassData["typeLocs"]:
149
150 self.implementationContent += """
151 if (Object.{0}()) {{
152 GetLocationsImpl(
153 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
154 Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
155 }}
156 """.format(
157 typeLoc
158 )
159
160 self.implementationContent += "\n"
161 if "typeSourceInfos" in ClassData:
162 for tsi in ClassData["typeSourceInfos"]:
163 self.implementationContent += """
164 if (Object.{0}()) {{
165 GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(
166 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}",
167 LocationCall::ReturnsPointer), "getTypeLoc"),
168 Object.{0}()->getTypeLoc(), Locs, Rngs, TypeLocRecursionGuard);
169 }}
170 """.format(
171 tsi
172 )
173
174 self.implementationContent += "\n"
175
176 if "nestedNameLocs" in ClassData:
177 for NN in ClassData["nestedNameLocs"]:
178 self.implementationContent += """
179 if (Object.{0}())
180 GetLocationsImpl(
181 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
182 Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
183 """.format(
184 NN
185 )
186
187 if "declNameInfos" in ClassData:
188 for declName in ClassData["declNameInfos"]:
189
190 self.implementationContent += """
191 GetLocationsImpl(
192 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
193 Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
194 """.format(
195 declName
196 )
197
198 self.implementationContent += "}\n"
199
200 def GenerateFiles(self, OutputFile):
201 with open(os.path.join(os.getcwd(), OutputFile), "w") as f:
202 f.write(self.implementationContent)
203
205 self,
206 ASTClassNames,
207 ClassEntries,
208 CladeName,
209 InheritanceMap,
210 CreateLocalRecursionGuard,
211 ):
212
213 MethodReturnType = "NodeLocationAccessors"
214 InstanceDecoration = "*"
215 if CladeName in self.RefClades:
216 InstanceDecoration = "&"
217
218 Signature = "GetLocations(clang::{0} const {1}Object)".format(
219 CladeName, InstanceDecoration
220 )
221 ImplSignature = """
222 GetLocationsImpl(SharedLocationCall const& Prefix,
223 clang::{0} const {1}Object, SourceLocationMap &Locs,
224 SourceRangeMap &Rngs,
225 std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
226 """.format(
227 CladeName, InstanceDecoration
228 )
229
230 self.implementationContent += "void {0} {{ ".format(ImplSignature)
231
232 if CladeName == "TypeLoc":
233 self.implementationContent += "if (Object.isNull()) return;"
234
235 self.implementationContent += """
236 if (llvm::find(TypeLocRecursionGuard, Object) != TypeLocRecursionGuard.end())
237 return;
238 TypeLocRecursionGuard.push_back(Object);
239 RecursionPopper RAII(TypeLocRecursionGuard);
240 """
241
242 RecursionGuardParam = ""
243 if not CreateLocalRecursionGuard:
244 RecursionGuardParam = ", TypeLocRecursionGuard"
245
246 ArgPrefix = "*"
247 if CladeName in self.RefClades:
248 ArgPrefix = ""
249 self.implementationContent += (
250 "GetLocations{0}(Prefix, {1}Object, Locs, Rngs {2});".format(
251 CladeName, ArgPrefix, RecursionGuardParam
252 )
253 )
254
255 if CladeName == "TypeLoc":
256 self.implementationContent += """
257 if (auto QTL = Object.getAs<clang::QualifiedTypeLoc>()) {
258 auto Dequalified = QTL.getNextTypeLoc();
259 return GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getNextTypeLoc"),
260 Dequalified,
261 Locs,
262 Rngs,
263 TypeLocRecursionGuard);
264 }"""
265
266 for ASTClassName in ASTClassNames:
267 if ASTClassName in self.templateClasses:
268 continue
269 if ASTClassName == CladeName:
270 continue
271 if CladeName != "TypeLoc":
272 self.implementationContent += """
273if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
274 GetLocations{0}(Prefix, *Derived, Locs, Rngs {1});
275}}
276""".format(
277 ASTClassName, RecursionGuardParam
278 )
279 continue
280
282 ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap
283 )
284
285 self.implementationContent += "}"
286
287 self.implementationContent += """
288{0} NodeIntrospection::{1} {{
289 NodeLocationAccessors Result;
290 SharedLocationCall Prefix;
291 std::vector<clang::TypeLoc> TypeLocRecursionGuard;
292
293 GetLocationsImpl(Prefix, Object, Result.LocationAccessors,
294 Result.RangeAccessors, TypeLocRecursionGuard);
295""".format(
296 MethodReturnType, Signature
297 )
298
299 self.implementationContent += "return Result; }"
300
302 self, ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap
303 ):
304 CallPrefix = "Prefix"
305 if ASTClassName != "TypeLoc":
306 CallPrefix = """llvm::makeIntrusiveRefCnt<LocationCall>(Prefix,
307 "getAs<clang::{0}>", LocationCall::IsCast)
308 """.format(
309 ASTClassName
310 )
311
312 if ASTClassName in ClassEntries:
313
314 self.implementationContent += """
315 if (auto ConcreteTL = Object.getAs<clang::{0}>())
316 GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
317 """.format(
318 ASTClassName, ASTClassName, CallPrefix, RecursionGuardParam
319 )
320
321 if ASTClassName in InheritanceMap:
322 for baseTemplate in self.templateClasses:
323 if baseTemplate in InheritanceMap[ASTClassName]:
324 self.implementationContent += """
325 if (auto ConcreteTL = Object.getAs<clang::{0}>())
326 GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
327 """.format(
328 InheritanceMap[ASTClassName],
329 baseTemplate,
330 CallPrefix,
331 RecursionGuardParam,
332 )
333
334 def GenerateDynNodeVisitor(self, CladeNames):
335 MethodReturnType = "NodeLocationAccessors"
336
337 Signature = "GetLocations(clang::DynTypedNode const &Node)"
338
339 self.implementationContent += (
340 MethodReturnType + " NodeIntrospection::" + Signature + "{"
341 )
342
343 for CladeName in CladeNames:
344 if CladeName == "DeclarationNameInfo":
345 continue
346 self.implementationContent += """
347 if (const auto *N = Node.get<{0}>())
348 """.format(
349 CladeName
350 )
351 ArgPrefix = ""
352 if CladeName in self.RefClades:
353 ArgPrefix = "*"
354 self.implementationContent += """
355 return GetLocations({0}const_cast<{1} *>(N));""".format(
356 ArgPrefix, CladeName
357 )
358
359 self.implementationContent += "\nreturn {}; }"
360
362
363 self.implementationContent += """
364 }
365}
366"""
367
368
369def main():
370
371 parser = argparse.ArgumentParser()
372 parser.add_argument(
373 "--json-input-path", help="Read API description from FILE", metavar="FILE"
374 )
375 parser.add_argument(
376 "--output-file", help="Generate output in FILEPATH", metavar="FILEPATH"
377 )
378 parser.add_argument(
379 "--use-empty-implementation",
380 help="Generate empty implementation",
381 action="store",
382 type=int,
383 )
384 parser.add_argument(
385 "--empty-implementation",
386 help="Copy empty implementation from FILEPATH",
387 action="store",
388 metavar="FILEPATH",
389 )
390
391 options = parser.parse_args()
392
393 use_empty_implementation = options.use_empty_implementation
394
395 if not use_empty_implementation and not os.path.exists(options.json_input_path):
396 use_empty_implementation = True
397
398 if not use_empty_implementation:
399 with open(options.json_input_path) as f:
400 jsonData = json.load(f)
401
402 if not "classesInClade" in jsonData or not jsonData["classesInClade"]:
403 use_empty_implementation = True
404
405 if use_empty_implementation:
406 if not os.path.exists(options.output_file) or not filecmp.cmp(
407 options.empty_implementation, options.output_file
408 ):
409 shutil.copyfile(options.empty_implementation, options.output_file)
410 sys.exit(0)
411
412 templateClasses = []
413 for (ClassName, ClassAccessors) in jsonData["classEntries"].items():
414 if "templateParms" in ClassAccessors:
415 templateClasses.append(ClassName)
416
417 g = Generator(templateClasses)
418
419 g.GeneratePrologue()
420
421 for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
422 g.GenerateBaseGetLocationsDeclaration(CladeName)
423
424 def getCladeName(ClassName):
425 for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
426 if ClassName in ClassNameData:
427 return CladeName
428
429 for (ClassName, ClassAccessors) in jsonData["classEntries"].items():
430 cladeName = getCladeName(ClassName)
431 g.GenerateSrcLocMethod(
432 ClassName, ClassAccessors, cladeName not in Generator.RefClades
433 )
434
435 for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
436 g.GenerateBaseGetLocationsFunction(
437 ClassNameData,
438 jsonData["classEntries"],
439 CladeName,
440 jsonData["classInheritance"],
441 CladeName not in Generator.RefClades,
442 )
443
444 g.GenerateDynNodeVisitor(jsonData["classesInClade"].keys())
445
446 g.GenerateEpilogue()
447
448 g.GenerateFiles(options.output_file)
449
450
451if __name__ == "__main__":
452 main()
def GenerateBaseTypeLocVisit(self, ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap)
def GenerateDynNodeVisitor(self, CladeNames)
def GenerateBaseGetLocationsDeclaration(self, CladeName)
def GenerateBaseGetLocationsFunction(self, ASTClassNames, ClassEntries, CladeName, InheritanceMap, CreateLocalRecursionGuard)
def __init__(self, templateClasses)
def GenerateSrcLocMethod(self, ClassName, ClassData, CreateLocalRecursionGuard)