123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- import os
- import sys
- import json
- import filecmp
- import shutil
- import argparse
- class Generator(object):
- implementationContent = ''
- RefClades = {"DeclarationNameInfo",
- "NestedNameSpecifierLoc",
- "TemplateArgumentLoc",
- "TypeLoc"}
- def __init__(self, templateClasses):
- self.templateClasses = templateClasses
- def GeneratePrologue(self):
- self.implementationContent += \
- """
- /*===- Generated file -------------------------------------------*- C++ -*-===*\
- |* *|
- |* Introspection of available AST node SourceLocations *|
- |* *|
- |* Automatically generated file, do not edit! *|
- |* *|
- \*===----------------------------------------------------------------------===*/
- namespace clang {
- namespace tooling {
- using LocationAndString = SourceLocationMap::value_type;
- using RangeAndString = SourceRangeMap::value_type;
- bool NodeIntrospection::hasIntrospectionSupport() { return true; }
- struct RecursionPopper
- {
- RecursionPopper(std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
- : TLRG(TypeLocRecursionGuard)
- {
- }
- ~RecursionPopper()
- {
- TLRG.pop_back();
- }
- private:
- std::vector<clang::TypeLoc> &TLRG;
- };
- """
- def GenerateBaseGetLocationsDeclaration(self, CladeName):
- InstanceDecoration = "*"
- if CladeName in self.RefClades:
- InstanceDecoration = "&"
- self.implementationContent += \
- """
- void GetLocationsImpl(SharedLocationCall const& Prefix,
- clang::{0} const {1}Object, SourceLocationMap &Locs,
- SourceRangeMap &Rngs,
- std::vector<clang::TypeLoc> &TypeLocRecursionGuard);
- """.format(CladeName, InstanceDecoration)
- def GenerateSrcLocMethod(self,
- ClassName, ClassData, CreateLocalRecursionGuard):
- NormalClassName = ClassName
- RecursionGuardParam = ('' if CreateLocalRecursionGuard else \
- ', std::vector<clang::TypeLoc>& TypeLocRecursionGuard')
- if "templateParms" in ClassData:
- TemplatePreamble = "template <typename "
- ClassName += "<"
- First = True
- for TA in ClassData["templateParms"]:
- if not First:
- ClassName += ", "
- TemplatePreamble += ", typename "
- First = False
- ClassName += TA
- TemplatePreamble += TA
- ClassName += ">"
- TemplatePreamble += ">\n";
- self.implementationContent += TemplatePreamble
- self.implementationContent += \
- """
- static void GetLocations{0}(SharedLocationCall const& Prefix,
- clang::{1} const &Object,
- SourceLocationMap &Locs, SourceRangeMap &Rngs {2})
- {{
- """.format(NormalClassName, ClassName, RecursionGuardParam)
- if 'sourceLocations' in ClassData:
- for locName in ClassData['sourceLocations']:
- self.implementationContent += \
- """
- Locs.insert(LocationAndString(Object.{0}(),
- llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
- """.format(locName)
- self.implementationContent += '\n'
- if 'sourceRanges' in ClassData:
- for rngName in ClassData['sourceRanges']:
- self.implementationContent += \
- """
- Rngs.insert(RangeAndString(Object.{0}(),
- llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}")));
- """.format(rngName)
- self.implementationContent += '\n'
- if 'typeLocs' in ClassData or 'typeSourceInfos' in ClassData \
- or 'nestedNameLocs' in ClassData \
- or 'declNameInfos' in ClassData:
- if CreateLocalRecursionGuard:
- self.implementationContent += \
- 'std::vector<clang::TypeLoc> TypeLocRecursionGuard;\n'
- self.implementationContent += '\n'
- if 'typeLocs' in ClassData:
- for typeLoc in ClassData['typeLocs']:
- self.implementationContent += \
- """
- if (Object.{0}()) {{
- GetLocationsImpl(
- llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
- Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
- }}
- """.format(typeLoc)
- self.implementationContent += '\n'
- if 'typeSourceInfos' in ClassData:
- for tsi in ClassData['typeSourceInfos']:
- self.implementationContent += \
- """
- if (Object.{0}()) {{
- GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(
- llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}",
- LocationCall::ReturnsPointer), "getTypeLoc"),
- Object.{0}()->getTypeLoc(), Locs, Rngs, TypeLocRecursionGuard);
- }}
- """.format(tsi)
- self.implementationContent += '\n'
- if 'nestedNameLocs' in ClassData:
- for NN in ClassData['nestedNameLocs']:
- self.implementationContent += \
- """
- if (Object.{0}())
- GetLocationsImpl(
- llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
- Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
- """.format(NN)
- if 'declNameInfos' in ClassData:
- for declName in ClassData['declNameInfos']:
- self.implementationContent += \
- """
- GetLocationsImpl(
- llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
- Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
- """.format(declName)
- self.implementationContent += '}\n'
- def GenerateFiles(self, OutputFile):
- with open(os.path.join(os.getcwd(),
- OutputFile), 'w') as f:
- f.write(self.implementationContent)
- def GenerateBaseGetLocationsFunction(self, ASTClassNames,
- ClassEntries, CladeName, InheritanceMap,
- CreateLocalRecursionGuard):
- MethodReturnType = 'NodeLocationAccessors'
- InstanceDecoration = "*"
- if CladeName in self.RefClades:
- InstanceDecoration = "&"
- Signature = \
- 'GetLocations(clang::{0} const {1}Object)'.format(
- CladeName, InstanceDecoration)
- ImplSignature = \
- """
- GetLocationsImpl(SharedLocationCall const& Prefix,
- clang::{0} const {1}Object, SourceLocationMap &Locs,
- SourceRangeMap &Rngs,
- std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
- """.format(CladeName, InstanceDecoration)
- self.implementationContent += 'void {0} {{ '.format(ImplSignature)
- if CladeName == "TypeLoc":
- self.implementationContent += 'if (Object.isNull()) return;'
- self.implementationContent += \
- """
- if (llvm::find(TypeLocRecursionGuard, Object) != TypeLocRecursionGuard.end())
- return;
- TypeLocRecursionGuard.push_back(Object);
- RecursionPopper RAII(TypeLocRecursionGuard);
- """
- RecursionGuardParam = ''
- if not CreateLocalRecursionGuard:
- RecursionGuardParam = ', TypeLocRecursionGuard'
- ArgPrefix = '*'
- if CladeName in self.RefClades:
- ArgPrefix = ''
- self.implementationContent += \
- 'GetLocations{0}(Prefix, {1}Object, Locs, Rngs {2});'.format(
- CladeName, ArgPrefix, RecursionGuardParam)
- if CladeName == "TypeLoc":
- self.implementationContent += \
- '''
- if (auto QTL = Object.getAs<clang::QualifiedTypeLoc>()) {
- auto Dequalified = QTL.getNextTypeLoc();
- return GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getNextTypeLoc"),
- Dequalified,
- Locs,
- Rngs,
- TypeLocRecursionGuard);
- }'''
- for ASTClassName in ASTClassNames:
- if ASTClassName in self.templateClasses:
- continue
- if ASTClassName == CladeName:
- continue
- if CladeName != "TypeLoc":
- self.implementationContent += \
- """
- if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
- GetLocations{0}(Prefix, *Derived, Locs, Rngs {1});
- }}
- """.format(ASTClassName, RecursionGuardParam)
- continue
- self.GenerateBaseTypeLocVisit(ASTClassName, ClassEntries,
- RecursionGuardParam, InheritanceMap)
- self.implementationContent += '}'
- self.implementationContent += \
- """
- {0} NodeIntrospection::{1} {{
- NodeLocationAccessors Result;
- SharedLocationCall Prefix;
- std::vector<clang::TypeLoc> TypeLocRecursionGuard;
- GetLocationsImpl(Prefix, Object, Result.LocationAccessors,
- Result.RangeAccessors, TypeLocRecursionGuard);
- """.format(MethodReturnType, Signature)
- self.implementationContent += 'return Result; }'
- def GenerateBaseTypeLocVisit(self, ASTClassName, ClassEntries,
- RecursionGuardParam, InheritanceMap):
- CallPrefix = 'Prefix'
- if ASTClassName != 'TypeLoc':
- CallPrefix = \
- '''llvm::makeIntrusiveRefCnt<LocationCall>(Prefix,
- "getAs<clang::{0}>", LocationCall::IsCast)
- '''.format(ASTClassName)
- if ASTClassName in ClassEntries:
- self.implementationContent += \
- """
- if (auto ConcreteTL = Object.getAs<clang::{0}>())
- GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
- """.format(ASTClassName, ASTClassName,
- CallPrefix, RecursionGuardParam)
- if ASTClassName in InheritanceMap:
- for baseTemplate in self.templateClasses:
- if baseTemplate in InheritanceMap[ASTClassName]:
- self.implementationContent += \
- """
- if (auto ConcreteTL = Object.getAs<clang::{0}>())
- GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
- """.format(InheritanceMap[ASTClassName], baseTemplate,
- CallPrefix, RecursionGuardParam)
- def GenerateDynNodeVisitor(self, CladeNames):
- MethodReturnType = 'NodeLocationAccessors'
- Signature = \
- 'GetLocations(clang::DynTypedNode const &Node)'
- self.implementationContent += MethodReturnType \
- + ' NodeIntrospection::' + Signature + '{'
- for CladeName in CladeNames:
- if CladeName == "DeclarationNameInfo":
- continue
- self.implementationContent += \
- """
- if (const auto *N = Node.get<{0}>())
- """.format(CladeName)
- ArgPrefix = ""
- if CladeName in self.RefClades:
- ArgPrefix = "*"
- self.implementationContent += \
- """
- return GetLocations({0}const_cast<{1} *>(N));""".format(ArgPrefix, CladeName)
- self.implementationContent += '\nreturn {}; }'
- def GenerateEpilogue(self):
- self.implementationContent += '''
- }
- }
- '''
- def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('--json-input-path',
- help='Read API description from FILE', metavar='FILE')
- parser.add_argument('--output-file', help='Generate output in FILEPATH',
- metavar='FILEPATH')
- parser.add_argument('--use-empty-implementation',
- help='Generate empty implementation',
- action="store", type=int)
- parser.add_argument('--empty-implementation',
- help='Copy empty implementation from FILEPATH',
- action="store", metavar='FILEPATH')
- options = parser.parse_args()
- use_empty_implementation = options.use_empty_implementation
- if (not use_empty_implementation
- and not os.path.exists(options.json_input_path)):
- use_empty_implementation = True
- if not use_empty_implementation:
- with open(options.json_input_path) as f:
- jsonData = json.load(f)
- if not 'classesInClade' in jsonData or not jsonData["classesInClade"]:
- use_empty_implementation = True
- if use_empty_implementation:
- if not os.path.exists(options.output_file) or \
- not filecmp.cmp(options.empty_implementation, options.output_file):
- shutil.copyfile(options.empty_implementation, options.output_file)
- sys.exit(0)
- templateClasses = []
- for (ClassName, ClassAccessors) in jsonData['classEntries'].items():
- if "templateParms" in ClassAccessors:
- templateClasses.append(ClassName)
- g = Generator(templateClasses)
- g.GeneratePrologue()
- for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
- g.GenerateBaseGetLocationsDeclaration(CladeName)
- def getCladeName(ClassName):
- for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
- if ClassName in ClassNameData:
- return CladeName
- for (ClassName, ClassAccessors) in jsonData['classEntries'].items():
- cladeName = getCladeName(ClassName)
- g.GenerateSrcLocMethod(
- ClassName, ClassAccessors,
- cladeName not in Generator.RefClades)
- for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
- g.GenerateBaseGetLocationsFunction(
- ClassNameData,
- jsonData['classEntries'],
- CladeName,
- jsonData["classInheritance"],
- CladeName not in Generator.RefClades)
- g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys())
- g.GenerateEpilogue()
- g.GenerateFiles(options.output_file)
- if __name__ == '__main__':
- main()
|