412 lines
14 KiB
Python
Executable File
412 lines
14 KiB
Python
Executable File
#!/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()
|