generate_cxx_src_locs.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import os
  4. import sys
  5. import json
  6. import filecmp
  7. import shutil
  8. import argparse
  9. class Generator(object):
  10. implementationContent = ''
  11. RefClades = {"DeclarationNameInfo",
  12. "NestedNameSpecifierLoc",
  13. "TemplateArgumentLoc",
  14. "TypeLoc"}
  15. def __init__(self, templateClasses):
  16. self.templateClasses = templateClasses
  17. def GeneratePrologue(self):
  18. self.implementationContent += \
  19. """
  20. /*===- Generated file -------------------------------------------*- C++ -*-===*\
  21. |* *|
  22. |* Introspection of available AST node SourceLocations *|
  23. |* *|
  24. |* Automatically generated file, do not edit! *|
  25. |* *|
  26. \*===----------------------------------------------------------------------===*/
  27. namespace clang {
  28. namespace tooling {
  29. using LocationAndString = SourceLocationMap::value_type;
  30. using RangeAndString = SourceRangeMap::value_type;
  31. bool NodeIntrospection::hasIntrospectionSupport() { return true; }
  32. struct RecursionPopper
  33. {
  34. RecursionPopper(std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
  35. : TLRG(TypeLocRecursionGuard)
  36. {
  37. }
  38. ~RecursionPopper()
  39. {
  40. TLRG.pop_back();
  41. }
  42. private:
  43. std::vector<clang::TypeLoc> &TLRG;
  44. };
  45. """
  46. def GenerateBaseGetLocationsDeclaration(self, CladeName):
  47. InstanceDecoration = "*"
  48. if CladeName in self.RefClades:
  49. InstanceDecoration = "&"
  50. self.implementationContent += \
  51. """
  52. void GetLocationsImpl(SharedLocationCall const& Prefix,
  53. clang::{0} const {1}Object, SourceLocationMap &Locs,
  54. SourceRangeMap &Rngs,
  55. std::vector<clang::TypeLoc> &TypeLocRecursionGuard);
  56. """.format(CladeName, InstanceDecoration)
  57. def GenerateSrcLocMethod(self,
  58. ClassName, ClassData, CreateLocalRecursionGuard):
  59. NormalClassName = ClassName
  60. RecursionGuardParam = ('' if CreateLocalRecursionGuard else \
  61. ', std::vector<clang::TypeLoc>& TypeLocRecursionGuard')
  62. if "templateParms" in ClassData:
  63. TemplatePreamble = "template <typename "
  64. ClassName += "<"
  65. First = True
  66. for TA in ClassData["templateParms"]:
  67. if not First:
  68. ClassName += ", "
  69. TemplatePreamble += ", typename "
  70. First = False
  71. ClassName += TA
  72. TemplatePreamble += TA
  73. ClassName += ">"
  74. TemplatePreamble += ">\n";
  75. self.implementationContent += TemplatePreamble
  76. self.implementationContent += \
  77. """
  78. static void GetLocations{0}(SharedLocationCall const& Prefix,
  79. clang::{1} const &Object,
  80. SourceLocationMap &Locs, SourceRangeMap &Rngs {2})
  81. {{
  82. """.format(NormalClassName, ClassName, RecursionGuardParam)
  83. if 'sourceLocations' in ClassData:
  84. for locName in ClassData['sourceLocations']:
  85. self.implementationContent += \
  86. """
  87. Locs.insert(LocationAndString(Object.{0}(),
  88. llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
  89. """.format(locName)
  90. self.implementationContent += '\n'
  91. if 'sourceRanges' in ClassData:
  92. for rngName in ClassData['sourceRanges']:
  93. self.implementationContent += \
  94. """
  95. Rngs.insert(RangeAndString(Object.{0}(),
  96. llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
  97. """.format(rngName)
  98. self.implementationContent += '\n'
  99. if 'typeLocs' in ClassData or 'typeSourceInfos' in ClassData \
  100. or 'nestedNameLocs' in ClassData \
  101. or 'declNameInfos' in ClassData:
  102. if CreateLocalRecursionGuard:
  103. self.implementationContent += \
  104. 'std::vector<clang::TypeLoc> TypeLocRecursionGuard;\n'
  105. self.implementationContent += '\n'
  106. if 'typeLocs' in ClassData:
  107. for typeLoc in ClassData['typeLocs']:
  108. self.implementationContent += \
  109. """
  110. if (Object.{0}()) {{
  111. GetLocationsImpl(
  112. llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
  113. Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
  114. }}
  115. """.format(typeLoc)
  116. self.implementationContent += '\n'
  117. if 'typeSourceInfos' in ClassData:
  118. for tsi in ClassData['typeSourceInfos']:
  119. self.implementationContent += \
  120. """
  121. if (Object.{0}()) {{
  122. GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(
  123. llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}",
  124. LocationCall::ReturnsPointer), "getTypeLoc"),
  125. Object.{0}()->getTypeLoc(), Locs, Rngs, TypeLocRecursionGuard);
  126. }}
  127. """.format(tsi)
  128. self.implementationContent += '\n'
  129. if 'nestedNameLocs' in ClassData:
  130. for NN in ClassData['nestedNameLocs']:
  131. self.implementationContent += \
  132. """
  133. if (Object.{0}())
  134. GetLocationsImpl(
  135. llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
  136. Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
  137. """.format(NN)
  138. if 'declNameInfos' in ClassData:
  139. for declName in ClassData['declNameInfos']:
  140. self.implementationContent += \
  141. """
  142. GetLocationsImpl(
  143. llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
  144. Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
  145. """.format(declName)
  146. self.implementationContent += '}\n'
  147. def GenerateFiles(self, OutputFile):
  148. with open(os.path.join(os.getcwd(),
  149. OutputFile), 'w') as f:
  150. f.write(self.implementationContent)
  151. def GenerateBaseGetLocationsFunction(self, ASTClassNames,
  152. ClassEntries, CladeName, InheritanceMap,
  153. CreateLocalRecursionGuard):
  154. MethodReturnType = 'NodeLocationAccessors'
  155. InstanceDecoration = "*"
  156. if CladeName in self.RefClades:
  157. InstanceDecoration = "&"
  158. Signature = \
  159. 'GetLocations(clang::{0} const {1}Object)'.format(
  160. CladeName, InstanceDecoration)
  161. ImplSignature = \
  162. """
  163. GetLocationsImpl(SharedLocationCall const& Prefix,
  164. clang::{0} const {1}Object, SourceLocationMap &Locs,
  165. SourceRangeMap &Rngs,
  166. std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
  167. """.format(CladeName, InstanceDecoration)
  168. self.implementationContent += 'void {0} {{ '.format(ImplSignature)
  169. if CladeName == "TypeLoc":
  170. self.implementationContent += 'if (Object.isNull()) return;'
  171. self.implementationContent += \
  172. """
  173. if (llvm::find(TypeLocRecursionGuard, Object) != TypeLocRecursionGuard.end())
  174. return;
  175. TypeLocRecursionGuard.push_back(Object);
  176. RecursionPopper RAII(TypeLocRecursionGuard);
  177. """
  178. RecursionGuardParam = ''
  179. if not CreateLocalRecursionGuard:
  180. RecursionGuardParam = ', TypeLocRecursionGuard'
  181. ArgPrefix = '*'
  182. if CladeName in self.RefClades:
  183. ArgPrefix = ''
  184. self.implementationContent += \
  185. 'GetLocations{0}(Prefix, {1}Object, Locs, Rngs {2});'.format(
  186. CladeName, ArgPrefix, RecursionGuardParam)
  187. if CladeName == "TypeLoc":
  188. self.implementationContent += \
  189. '''
  190. if (auto QTL = Object.getAs<clang::QualifiedTypeLoc>()) {
  191. auto Dequalified = QTL.getNextTypeLoc();
  192. return GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getNextTypeLoc"),
  193. Dequalified,
  194. Locs,
  195. Rngs,
  196. TypeLocRecursionGuard);
  197. }'''
  198. for ASTClassName in ASTClassNames:
  199. if ASTClassName in self.templateClasses:
  200. continue
  201. if ASTClassName == CladeName:
  202. continue
  203. if CladeName != "TypeLoc":
  204. self.implementationContent += \
  205. """
  206. if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
  207. GetLocations{0}(Prefix, *Derived, Locs, Rngs {1});
  208. }}
  209. """.format(ASTClassName, RecursionGuardParam)
  210. continue
  211. self.GenerateBaseTypeLocVisit(ASTClassName, ClassEntries,
  212. RecursionGuardParam, InheritanceMap)
  213. self.implementationContent += '}'
  214. self.implementationContent += \
  215. """
  216. {0} NodeIntrospection::{1} {{
  217. NodeLocationAccessors Result;
  218. SharedLocationCall Prefix;
  219. std::vector<clang::TypeLoc> TypeLocRecursionGuard;
  220. GetLocationsImpl(Prefix, Object, Result.LocationAccessors,
  221. Result.RangeAccessors, TypeLocRecursionGuard);
  222. """.format(MethodReturnType, Signature)
  223. self.implementationContent += 'return Result; }'
  224. def GenerateBaseTypeLocVisit(self, ASTClassName, ClassEntries,
  225. RecursionGuardParam, InheritanceMap):
  226. CallPrefix = 'Prefix'
  227. if ASTClassName != 'TypeLoc':
  228. CallPrefix = \
  229. '''llvm::makeIntrusiveRefCnt<LocationCall>(Prefix,
  230. "getAs<clang::{0}>", LocationCall::IsCast)
  231. '''.format(ASTClassName)
  232. if ASTClassName in ClassEntries:
  233. self.implementationContent += \
  234. """
  235. if (auto ConcreteTL = Object.getAs<clang::{0}>())
  236. GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
  237. """.format(ASTClassName, ASTClassName,
  238. CallPrefix, RecursionGuardParam)
  239. if ASTClassName in InheritanceMap:
  240. for baseTemplate in self.templateClasses:
  241. if baseTemplate in InheritanceMap[ASTClassName]:
  242. self.implementationContent += \
  243. """
  244. if (auto ConcreteTL = Object.getAs<clang::{0}>())
  245. GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
  246. """.format(InheritanceMap[ASTClassName], baseTemplate,
  247. CallPrefix, RecursionGuardParam)
  248. def GenerateDynNodeVisitor(self, CladeNames):
  249. MethodReturnType = 'NodeLocationAccessors'
  250. Signature = \
  251. 'GetLocations(clang::DynTypedNode const &Node)'
  252. self.implementationContent += MethodReturnType \
  253. + ' NodeIntrospection::' + Signature + '{'
  254. for CladeName in CladeNames:
  255. if CladeName == "DeclarationNameInfo":
  256. continue
  257. self.implementationContent += \
  258. """
  259. if (const auto *N = Node.get<{0}>())
  260. """.format(CladeName)
  261. ArgPrefix = ""
  262. if CladeName in self.RefClades:
  263. ArgPrefix = "*"
  264. self.implementationContent += \
  265. """
  266. return GetLocations({0}const_cast<{1} *>(N));""".format(ArgPrefix, CladeName)
  267. self.implementationContent += '\nreturn {}; }'
  268. def GenerateEpilogue(self):
  269. self.implementationContent += '''
  270. }
  271. }
  272. '''
  273. def main():
  274. parser = argparse.ArgumentParser()
  275. parser.add_argument('--json-input-path',
  276. help='Read API description from FILE', metavar='FILE')
  277. parser.add_argument('--output-file', help='Generate output in FILEPATH',
  278. metavar='FILEPATH')
  279. parser.add_argument('--use-empty-implementation',
  280. help='Generate empty implementation',
  281. action="store", type=int)
  282. parser.add_argument('--empty-implementation',
  283. help='Copy empty implementation from FILEPATH',
  284. action="store", metavar='FILEPATH')
  285. options = parser.parse_args()
  286. use_empty_implementation = options.use_empty_implementation
  287. if (not use_empty_implementation
  288. and not os.path.exists(options.json_input_path)):
  289. use_empty_implementation = True
  290. if not use_empty_implementation:
  291. with open(options.json_input_path) as f:
  292. jsonData = json.load(f)
  293. if not 'classesInClade' in jsonData or not jsonData["classesInClade"]:
  294. use_empty_implementation = True
  295. if use_empty_implementation:
  296. if not os.path.exists(options.output_file) or \
  297. not filecmp.cmp(options.empty_implementation, options.output_file):
  298. shutil.copyfile(options.empty_implementation, options.output_file)
  299. sys.exit(0)
  300. templateClasses = []
  301. for (ClassName, ClassAccessors) in jsonData['classEntries'].items():
  302. if "templateParms" in ClassAccessors:
  303. templateClasses.append(ClassName)
  304. g = Generator(templateClasses)
  305. g.GeneratePrologue()
  306. for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
  307. g.GenerateBaseGetLocationsDeclaration(CladeName)
  308. def getCladeName(ClassName):
  309. for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
  310. if ClassName in ClassNameData:
  311. return CladeName
  312. for (ClassName, ClassAccessors) in jsonData['classEntries'].items():
  313. cladeName = getCladeName(ClassName)
  314. g.GenerateSrcLocMethod(
  315. ClassName, ClassAccessors,
  316. cladeName not in Generator.RefClades)
  317. for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
  318. g.GenerateBaseGetLocationsFunction(
  319. ClassNameData,
  320. jsonData['classEntries'],
  321. CladeName,
  322. jsonData["classInheritance"],
  323. CladeName not in Generator.RefClades)
  324. g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys())
  325. g.GenerateEpilogue()
  326. g.GenerateFiles(options.output_file)
  327. if __name__ == '__main__':
  328. main()