eliminate python SyntaxWarnings from check-all output.
[platform/upstream/llvm.git] / clang / lib / Tooling / DumpTool / generate_cxx_src_locs.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3
4 import os
5 import sys
6 import json
7 import filecmp
8 import shutil
9 import argparse
10
11
12 class Generator(object):
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
26     def GeneratePrologue(self):
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
37 namespace clang {
38 namespace tooling {
39
40 using LocationAndString = SourceLocationMap::value_type;
41 using RangeAndString = SourceRangeMap::value_type;
42
43 bool NodeIntrospection::hasIntrospectionSupport() { return true; }
44
45 struct 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
58 private:
59 std::vector<clang::TypeLoc> &TLRG;
60 };
61 """
62
63     def GenerateBaseGetLocationsDeclaration(self, CladeName):
64         InstanceDecoration = "*"
65         if CladeName in self.RefClades:
66             InstanceDecoration = "&"
67
68         self.implementationContent += """
69 void 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 += """
104 static 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
204     def GenerateBaseGetLocationsFunction(
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 += """
273 if (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
281             self.GenerateBaseTypeLocVisit(
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
301     def GenerateBaseTypeLocVisit(
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
361     def GenerateEpilogue(self):
362
363         self.implementationContent += """
364   }
365 }
366 """
367
368
369 def 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
451 if __name__ == "__main__":
452     main()