2 # -*- coding: utf-8 -*-
12 class Generator(object):
14 implementationContent = ""
17 "DeclarationNameInfo",
18 "NestedNameSpecifierLoc",
19 "TemplateArgumentLoc",
23 def __init__(self, templateClasses):
24 self.templateClasses = templateClasses
26 def GeneratePrologue(self):
28 self.implementationContent += r"""
29 /*===- Generated file -------------------------------------------*- C++ -*-===*\
31 |* Introspection of available AST node SourceLocations *|
33 |* Automatically generated file, do not edit! *|
35 \*===----------------------------------------------------------------------===*/
40 using LocationAndString = SourceLocationMap::value_type;
41 using RangeAndString = SourceRangeMap::value_type;
43 bool NodeIntrospection::hasIntrospectionSupport() { return true; }
45 struct RecursionPopper
47 RecursionPopper(std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
48 : TLRG(TypeLocRecursionGuard)
59 std::vector<clang::TypeLoc> &TLRG;
63 def GenerateBaseGetLocationsDeclaration(self, CladeName):
64 InstanceDecoration = "*"
65 if CladeName in self.RefClades:
66 InstanceDecoration = "&"
68 self.implementationContent += """
69 void GetLocationsImpl(SharedLocationCall const& Prefix,
70 clang::{0} const {1}Object, SourceLocationMap &Locs,
72 std::vector<clang::TypeLoc> &TypeLocRecursionGuard);
74 CladeName, InstanceDecoration
77 def GenerateSrcLocMethod(self, ClassName, ClassData, CreateLocalRecursionGuard):
79 NormalClassName = ClassName
80 RecursionGuardParam = (
82 if CreateLocalRecursionGuard
83 else ", std::vector<clang::TypeLoc>& TypeLocRecursionGuard"
86 if "templateParms" in ClassData:
87 TemplatePreamble = "template <typename "
90 for TA in ClassData["templateParms"]:
93 TemplatePreamble += ", typename "
97 TemplatePreamble += TA
100 TemplatePreamble += ">\n"
101 self.implementationContent += TemplatePreamble
103 self.implementationContent += """
104 static void GetLocations{0}(SharedLocationCall const& Prefix,
105 clang::{1} const &Object,
106 SourceLocationMap &Locs, SourceRangeMap &Rngs {2})
109 NormalClassName, ClassName, RecursionGuardParam
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}")));
121 self.implementationContent += "\n"
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}")));
132 self.implementationContent += "\n"
135 "typeLocs" in ClassData
136 or "typeSourceInfos" in ClassData
137 or "nestedNameLocs" in ClassData
138 or "declNameInfos" in ClassData
140 if CreateLocalRecursionGuard:
141 self.implementationContent += (
142 "std::vector<clang::TypeLoc> TypeLocRecursionGuard;\n"
145 self.implementationContent += "\n"
147 if "typeLocs" in ClassData:
148 for typeLoc in ClassData["typeLocs"]:
150 self.implementationContent += """
153 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
154 Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
160 self.implementationContent += "\n"
161 if "typeSourceInfos" in ClassData:
162 for tsi in ClassData["typeSourceInfos"]:
163 self.implementationContent += """
165 GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(
166 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}",
167 LocationCall::ReturnsPointer), "getTypeLoc"),
168 Object.{0}()->getTypeLoc(), Locs, Rngs, TypeLocRecursionGuard);
174 self.implementationContent += "\n"
176 if "nestedNameLocs" in ClassData:
177 for NN in ClassData["nestedNameLocs"]:
178 self.implementationContent += """
181 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
182 Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
187 if "declNameInfos" in ClassData:
188 for declName in ClassData["declNameInfos"]:
190 self.implementationContent += """
192 llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
193 Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
198 self.implementationContent += "}\n"
200 def GenerateFiles(self, OutputFile):
201 with open(os.path.join(os.getcwd(), OutputFile), "w") as f:
202 f.write(self.implementationContent)
204 def GenerateBaseGetLocationsFunction(
210 CreateLocalRecursionGuard,
213 MethodReturnType = "NodeLocationAccessors"
214 InstanceDecoration = "*"
215 if CladeName in self.RefClades:
216 InstanceDecoration = "&"
218 Signature = "GetLocations(clang::{0} const {1}Object)".format(
219 CladeName, InstanceDecoration
222 GetLocationsImpl(SharedLocationCall const& Prefix,
223 clang::{0} const {1}Object, SourceLocationMap &Locs,
224 SourceRangeMap &Rngs,
225 std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
227 CladeName, InstanceDecoration
230 self.implementationContent += "void {0} {{ ".format(ImplSignature)
232 if CladeName == "TypeLoc":
233 self.implementationContent += "if (Object.isNull()) return;"
235 self.implementationContent += """
236 if (llvm::find(TypeLocRecursionGuard, Object) != TypeLocRecursionGuard.end())
238 TypeLocRecursionGuard.push_back(Object);
239 RecursionPopper RAII(TypeLocRecursionGuard);
242 RecursionGuardParam = ""
243 if not CreateLocalRecursionGuard:
244 RecursionGuardParam = ", TypeLocRecursionGuard"
247 if CladeName in self.RefClades:
249 self.implementationContent += (
250 "GetLocations{0}(Prefix, {1}Object, Locs, Rngs {2});".format(
251 CladeName, ArgPrefix, RecursionGuardParam
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"),
263 TypeLocRecursionGuard);
266 for ASTClassName in ASTClassNames:
267 if ASTClassName in self.templateClasses:
269 if ASTClassName == CladeName:
271 if CladeName != "TypeLoc":
272 self.implementationContent += """
273 if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
274 GetLocations{0}(Prefix, *Derived, Locs, Rngs {1});
277 ASTClassName, RecursionGuardParam
281 self.GenerateBaseTypeLocVisit(
282 ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap
285 self.implementationContent += "}"
287 self.implementationContent += """
288 {0} NodeIntrospection::{1} {{
289 NodeLocationAccessors Result;
290 SharedLocationCall Prefix;
291 std::vector<clang::TypeLoc> TypeLocRecursionGuard;
293 GetLocationsImpl(Prefix, Object, Result.LocationAccessors,
294 Result.RangeAccessors, TypeLocRecursionGuard);
296 MethodReturnType, Signature
299 self.implementationContent += "return Result; }"
301 def GenerateBaseTypeLocVisit(
302 self, ASTClassName, ClassEntries, RecursionGuardParam, InheritanceMap
304 CallPrefix = "Prefix"
305 if ASTClassName != "TypeLoc":
306 CallPrefix = """llvm::makeIntrusiveRefCnt<LocationCall>(Prefix,
307 "getAs<clang::{0}>", LocationCall::IsCast)
312 if ASTClassName in ClassEntries:
314 self.implementationContent += """
315 if (auto ConcreteTL = Object.getAs<clang::{0}>())
316 GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
318 ASTClassName, ASTClassName, CallPrefix, RecursionGuardParam
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});
328 InheritanceMap[ASTClassName],
334 def GenerateDynNodeVisitor(self, CladeNames):
335 MethodReturnType = "NodeLocationAccessors"
337 Signature = "GetLocations(clang::DynTypedNode const &Node)"
339 self.implementationContent += (
340 MethodReturnType + " NodeIntrospection::" + Signature + "{"
343 for CladeName in CladeNames:
344 if CladeName == "DeclarationNameInfo":
346 self.implementationContent += """
347 if (const auto *N = Node.get<{0}>())
352 if CladeName in self.RefClades:
354 self.implementationContent += """
355 return GetLocations({0}const_cast<{1} *>(N));""".format(
359 self.implementationContent += "\nreturn {}; }"
361 def GenerateEpilogue(self):
363 self.implementationContent += """
371 parser = argparse.ArgumentParser()
373 "--json-input-path", help="Read API description from FILE", metavar="FILE"
376 "--output-file", help="Generate output in FILEPATH", metavar="FILEPATH"
379 "--use-empty-implementation",
380 help="Generate empty implementation",
385 "--empty-implementation",
386 help="Copy empty implementation from FILEPATH",
391 options = parser.parse_args()
393 use_empty_implementation = options.use_empty_implementation
395 if not use_empty_implementation and not os.path.exists(options.json_input_path):
396 use_empty_implementation = True
398 if not use_empty_implementation:
399 with open(options.json_input_path) as f:
400 jsonData = json.load(f)
402 if not "classesInClade" in jsonData or not jsonData["classesInClade"]:
403 use_empty_implementation = True
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
409 shutil.copyfile(options.empty_implementation, options.output_file)
413 for (ClassName, ClassAccessors) in jsonData["classEntries"].items():
414 if "templateParms" in ClassAccessors:
415 templateClasses.append(ClassName)
417 g = Generator(templateClasses)
421 for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
422 g.GenerateBaseGetLocationsDeclaration(CladeName)
424 def getCladeName(ClassName):
425 for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
426 if ClassName in ClassNameData:
429 for (ClassName, ClassAccessors) in jsonData["classEntries"].items():
430 cladeName = getCladeName(ClassName)
431 g.GenerateSrcLocMethod(
432 ClassName, ClassAccessors, cladeName not in Generator.RefClades
435 for (CladeName, ClassNameData) in jsonData["classesInClade"].items():
436 g.GenerateBaseGetLocationsFunction(
438 jsonData["classEntries"],
440 jsonData["classInheritance"],
441 CladeName not in Generator.RefClades,
444 g.GenerateDynNodeVisitor(jsonData["classesInClade"].keys())
448 g.GenerateFiles(options.output_file)
451 if __name__ == "__main__":