Files
clice/docs/examples/ASTVisitor.cpp
2024-08-09 13:43:54 +08:00

830 lines
32 KiB
C++

#include <Clang/Clang.h>
#include <clang/Sema/Lookup.h>
#include <clang/Sema/Template.h>
class DependentShaper {
clang::ASTContext& context;
clang::Sema& sema;
public:
DependentShaper(clang::ASTContext& context, clang::Sema& sema) : context(context), sema(sema) {}
/// replace template arguments in a dependent type
/// e.g.
/// ```cpp
/// template <typename T1, typename T2>
/// struct A {
/// using reference = T1&;
/// };
///
/// template <typename U1, typename U2>
/// struct B {
/// using type = A<U1, U2>::reference;
/// };
/// ```
/// we want to simplify `A<U1, U2>::reference` to `U1&`, then we need to call
/// `replace(<T1&>, <T1 = U1, T2 = U2>)` to get `U1&`.
clang::QualType replace(clang::QualType input,
llvm::ArrayRef<clang::TemplateArgument> originalArguments) {
assert(type->isDependentType() && "type is not dependent");
// if the input is still a dependent name type, we need to simplify it recursively
while(auto type = llvm::dyn_cast<clang::DependentNameType>(input)) {
input = simplify(type);
}
clang::ElaboratedType* elaboratedType = nullptr;
clang::MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(originalArguments);
llvm::outs() << "-------------------------------------------------\n";
clang::Sema::CodeSynthesisContext InstContext;
// InstContext.Kind = clang::Sema::CodeSynthesisContext::TemplateInstantiation;
// InstContext.Entity = nullptr;
// InstContext.TemplateArgs = TemplateArgs;
// sema.CodeSynthesisContexts.back().dump();
auto result = sema.SubstType(input, list, {}, {});
if(auto type = llvm::dyn_cast<clang::LValueReferenceType>(input)) {
auto pointee = type->getPointeeType();
while(auto elaboratedType = llvm::dyn_cast<clang::ElaboratedType>(pointee)) {
pointee = elaboratedType->desugar();
}
// get the position of the dependent type in the template parameter list
// e.g `T1` in <typename T1, typename T2>, the index is 0
if(auto paramType = llvm::dyn_cast<clang::TemplateTypeParmType>(pointee)) {
auto index = paramType->getIndex();
auto argument = originalArguments[index];
// create a new type that fit the replacement
return context.getLValueReferenceType(argument.getAsType());
} else if(auto defType = llvm::dyn_cast<clang::TypedefType>(pointee)) {
return replace(defType->getDecl()->getUnderlyingType(), originalArguments);
} else {
pointee->dump();
std::terminate();
}
}
// TODO: handle other kinds
return input;
}
clang::NamedDecl* lookup(const clang::ClassTemplateDecl* classTemplateDecl,
const clang::IdentifierInfo* identifier) {
clang::CXXRecordDecl* recordDecl = classTemplateDecl->getTemplatedDecl();
auto result = recordDecl->lookup(identifier);
return result.front();
}
/// for a complex dependent type: `X<...>::name::name2::...::nameN`, we can resolve it
/// recursively. so we only need to handle the `X<...>::name`, whose prefix is a template
/// specialization type.
clang::QualType simplify(const clang::TemplateSpecializationType* templateType,
const clang::IdentifierInfo* identifier) {
// X is a class template or a type alias template
auto templateDecl = templateType->getTemplateName().getAsTemplateDecl();
if(auto classTemplateDecl = llvm::dyn_cast<clang::ClassTemplateDecl>(templateDecl)) {
// lookup the identifier in the record decl
auto namedDecl = lookup(classTemplateDecl, identifier);
if(auto decl = llvm::dyn_cast<clang::TypeAliasDecl>(namedDecl)) {
return replace(decl->getUnderlyingType(), templateType->template_arguments());
} else if(auto decl = llvm::dyn_cast<clang::TypedefDecl>(namedDecl)) {
return replace(decl->getUnderlyingType(), templateType->template_arguments());
} else {
namedDecl->dump();
}
} else if(auto aliasTemplateDecl =
llvm::dyn_cast<clang::TypeAliasTemplateDecl>(templateDecl)) {
// TODO:
} else {
templateDecl->dump();
}
}
const clang::QualType simplify(const clang::NestedNameSpecifier* specifier,
const clang::IdentifierInfo* identifier) {
auto kind = specifier->getKind();
switch(specifier->getKind()) {
case clang::NestedNameSpecifier::Identifier: {
const auto prefix = simplify(specifier->getPrefix(), specifier->getAsIdentifier());
if(auto type = llvm::dyn_cast<clang::TemplateSpecializationType>(prefix)) {
return simplify(type, identifier);
} else {
prefix->dump();
}
break;
}
case clang::NestedNameSpecifier::TypeSpec: {
auto node = specifier->getAsType();
if(auto type = llvm::dyn_cast<clang::TemplateTypeParmType>(node)) {
// represent a direct dependent name, e.g. typename T::^ name
// and can not be further simplified
// node->dump();
type->dump();
} else if(auto type = node->getAs<clang::TemplateSpecializationType>()) {
// represent a dependent name that is a template specialization
// e.g. typename vector<int>::^ name, and can be further simplified
return simplify(type, identifier);
} else {
node->dump();
}
break;
}
case clang::NestedNameSpecifier::TypeSpecWithTemplate: {
llvm::outs() << "unsupported kind: " << kind << "\n";
break;
}
default: {
llvm::outs() << "unsupported kind: " << kind << "\n";
}
}
}
const clang::QualType simplify(const clang::DependentNameType* type) {
// llvm::outs() << "-----------------------------------------------------------" << "\n";
// type->dump();
return simplify(type->getQualifier(), type->getIdentifier());
}
};
namespace clang {
class DependentNameResolver {
public:
Sema& S;
ASTContext& Ctx;
clang::NamedDecl* CurrentDecl;
public:
DependentNameResolver(ASTContext& Ctx, Sema& S) : Ctx(Ctx), S(S) {}
std::vector<TemplateArgument> resolve(llvm::ArrayRef<TemplateArgument> arguments) {
std::vector<TemplateArgument> result;
for(auto arg: arguments) {
if(arg.getKind() == TemplateArgument::ArgKind::Type) {
if(auto type = llvm::dyn_cast<TemplateTypeParmType>(arg.getAsType())) {
const TemplateTypeParmDecl* param = type->getDecl();
if(param->hasDefaultArgument()) {
result.push_back(param->getDefaultArgument().getArgument());
continue;
}
}
}
result.push_back(arg);
}
return result;
}
QualType resolve(QualType T) {
if(!T->isDependentType()) {
return T;
}
while(true) {
if(auto DNT = T->getAs<DependentNameType>()) {
T = resolve(DNT);
} else if(auto DTST = T->getAs<DependentTemplateSpecializationType>()) {
T = resolve(DTST);
} else if(auto LRT = T->getAs<LValueReferenceType>()) {
return Ctx.getLValueReferenceType(resolve(LRT->getPointeeType()));
} else {
return T;
}
}
}
/// resolve a dependent name type, e.g. `typename std::vector<T>::reference`
QualType resolve(const DependentNameType* DNT) {
// e.g. when DNT is `typename std::vector<T>::reference`
// - qualifier: std::vector<T>
// - identifier: reference
return resolve(DNT->getQualifier(), DNT->getIdentifier());
}
/// resolve a dependent template specialization type.
QualType resolve(const DependentTemplateSpecializationType* DTST) {
// e.g. when DTST is `typename std::allocator_traits<Alloc>::template rebind_alloc<T>`.
// - qualifier: std::allocator_traits<Alloc>
// - identifier: rebind_alloc
// - template_arguments: <T>
return resolve(DTST->getQualifier(), DTST->getIdentifier(), DTST->template_arguments());
}
QualType resolve(const NestedNameSpecifier* TST,
const IdentifierInfo* II,
ArrayRef<TemplateArgument> arguments = {}) {
switch(TST->getKind()) {
case NestedNameSpecifier::SpecifierKind::Identifier: {
llvm::outs() << "\n------------------ Identifier -----------------------\n";
// when the kind of TST is Identifier
// e.g. std::vector<std::vector<T>>::value_type::
// resolve it recursively
return resolve(resolve(TST->getPrefix(), TST->getAsIdentifier()), II, arguments);
}
case NestedNameSpecifier::SpecifierKind::TypeSpec: {
llvm::outs() << "\n------------------ TypeSpec -----------------------\n";
TST->dump();
llvm::outs() << " " << II->getName() << "\n";
// when the kind of TST is TypeSpec, e.g. std::vector<T>::
return resolve(QualType(TST->getAsType(), 0), II, arguments);
}
case NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: {
llvm::outs() << "------------------ TypeSpecWithTemplate -----------------------\n";
// when the kind of TST is TypeSpecWithTemplate, e.g. std::vector<T>::template
// name<U>::
TST->dump();
return resolve(QualType(TST->getAsType(), 0), II, arguments);
}
default: {
llvm::outs() << "\n------------------ Unknown -----------------------\n";
TST->dump();
std::terminate();
}
}
}
QualType substitute(ClassTemplateDecl* CTD,
const IdentifierInfo* II,
ArrayRef<TemplateArgument> arguments = {}) {
Sema::CodeSynthesisContext context;
auto args = resolve(arguments);
context.Entity = CTD;
context.TemplateArgs = args.data();
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
auto recordDecl = CTD->getTemplatedDecl();
auto member = recordDecl->lookup(II).front();
QualType type;
if(auto TAD = llvm::dyn_cast<TypeAliasDecl>(member)) {
type = TAD->getUnderlyingType();
} else if(auto TD = llvm::dyn_cast<TypedefDecl>(member)) {
type = TD->getUnderlyingType();
} else if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(member)) {
auto args2 = resolve(arguments);
context.Entity = TATD;
context.TemplateArgs = args2.data();
context.Kind = Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(TATD, args2, false);
auto TAD = TATD->getTemplatedDecl();
type = TAD->getUnderlyingType();
} else if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(member)) {
return substitute(CTD, II, arguments);
} else {
member->dump();
std::terminate();
}
list.addOuterTemplateArguments(CTD, args, true);
return S.SubstType(type, list, {}, {});
}
/// typename A<U1>::template B<U2>::template C<U3>::type::
QualType resolve(const DependentTemplateSpecializationType* DTST, const IdentifierInfo* II) {
// auto prefix;
MultiLevelTemplateArgumentList list;
while(true) {
// list.addOuterTemplateArguments()
}
}
QualType
resolve(QualType T, const IdentifierInfo* II, ArrayRef<TemplateArgument> arguments = {}) {
if(!T->isDependentType() && arguments.size() == 0) {
// TODO:
}
llvm::outs() << "\n";
T.dump();
Sema::CodeSynthesisContext context;
if(auto TTPT = T->getAs<TemplateTypeParmType>()) {
llvm::outs() << "\n-------------------------------------------------\n";
T->dump();
llvm::outs() << " \n" << II->getName();
// e.g. when T is `T`
// - index: 0
} else if(auto TST = T->getAs<TemplateSpecializationType>()) {
auto TemplateName = TST->getTemplateName();
auto TemplateDecl = TemplateName.getAsTemplateDecl();
auto TemplatedDecl = TemplateDecl->getTemplatedDecl();
if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(TemplateDecl)) {
return substitute(CTD, II, TST->template_arguments());
} else {
TemplateDecl->dump();
std::terminate();
}
auto TemplateArgs = TST->template_arguments();
} else if(auto DTST = T->getAs<DependentTemplateSpecializationType>()) {
auto TST = DTST->getQualifier()->getAsType()->getAs<TemplateSpecializationType>();
auto TemplateName = TST->getTemplateName();
auto TemplateDecl = TemplateName.getAsTemplateDecl();
auto TemplatedDecl = TemplateDecl->getTemplatedDecl();
if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(TemplateDecl)) {
auto args = resolve(TST->template_arguments());
context.Entity = CTD;
context.TemplateArgs = args.data();
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(CTD, args, true);
auto recordDecl = CTD->getTemplatedDecl();
auto member = recordDecl->lookup(DTST->getIdentifier()).front();
if(auto CTD2 = llvm::dyn_cast<ClassTemplateDecl>(member)) {
auto args2 = resolve(DTST->template_arguments());
context.Entity = CTD2;
context.TemplateArgs = args2.data();
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(CTD2, args2, true);
list.addOuterTemplateArguments(CTD, args, true);
auto CRD = CTD2->getTemplatedDecl();
return S.SubstType(
llvm::dyn_cast<TypeAliasDecl>(CRD->lookup(II).front())->getUnderlyingType(),
list,
{},
{});
} else if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(member)) {
auto args2 = resolve(arguments);
context.Entity = TATD;
context.TemplateArgs = args2.data();
context.Kind = Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(TATD, args2, false);
list.addOuterTemplateArguments(CTD, args, true);
auto TAD = TATD->getTemplatedDecl();
return S.SubstType(TAD->getUnderlyingType(), list, {}, {});
} else {
member->dump();
std::terminate();
}
} else {
T->dump();
std::terminate();
}
// S.SubstType()
}
}
};
class DependentNameResolverV2 {
public:
Sema& S;
ASTContext& Ctx;
std::vector<std::pair<Decl*, std::vector<TemplateArgument>>*> arguments;
public:
DependentNameResolverV2(ASTContext& Ctx, Sema& S) : Ctx(Ctx), S(S) {}
std::vector<TemplateArgument> resolve(llvm::ArrayRef<TemplateArgument> arguments) {
std::vector<TemplateArgument> result;
for(auto arg: arguments) {
if(arg.getKind() == TemplateArgument::ArgKind::Type) {
// check whether it is a TemplateTypeParmType.
if(auto type = llvm::dyn_cast<TemplateTypeParmType>(arg.getAsType())) {
const TemplateTypeParmDecl* param = type->getDecl();
if(param && param->hasDefaultArgument()) {
result.push_back(param->getDefaultArgument().getArgument());
continue;
}
}
}
result.push_back(arg);
}
return result;
}
QualType dealias(QualType type) {
if(auto DNT = type->getAs<TemplateSpecializationType>()) {
return QualType(DNT, 0);
} else if(auto DTST = type->getAs<DependentTemplateSpecializationType>()) {
auto NNS = NestedNameSpecifier::Create(
Ctx,
nullptr,
false,
dealias(QualType(DTST->getQualifier()->getAsType(), 0)).getTypePtr());
return Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(),
NNS,
DTST->getIdentifier(),
resolve(DTST->template_arguments()));
} else {
return type;
}
}
QualType resolve(QualType type) {
while(true) {
// llvm::outs() <<
// "--------------------------------------------------------------------\n";
// type.dump();
MultiLevelTemplateArgumentList list;
if(auto DNT = type->getAs<DependentNameType>()) {
type = resolve(resolve(DNT->getQualifier(), DNT->getIdentifier()));
for(auto begin = arguments.rbegin(), end = arguments.rend(); begin != end;
++begin) {
list.addOuterTemplateArguments((*begin)->first, (*begin)->second, true);
}
type = S.SubstType(dealias(type), list, {}, {});
arguments.clear();
} else if(auto DTST = type->getAs<DependentTemplateSpecializationType>()) {
auto ND = resolve(DTST->getQualifier(), DTST->getIdentifier());
if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(ND)) {
auto args = resolve(DTST->template_arguments());
Sema::CodeSynthesisContext context;
context.Entity = TATD;
context.Kind = Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation;
context.TemplateArgs = args.data();
S.pushCodeSynthesisContext(context);
list.addOuterTemplateArguments(TATD, args, true);
for(auto begin = arguments.rbegin(), end = arguments.rend(); begin != end;
++begin) {
list.addOuterTemplateArguments((*begin)->first, (*begin)->second, true);
}
// llvm::outs() << "before:
// ----------------------------------------------------------------\n";
// TATD->getTemplatedDecl()->getUnderlyingType().dump();
type = dealias(TATD->getTemplatedDecl()->getUnderlyingType());
// llvm::outs() << "arguments:
// -------------------------------------------------------------\n";
// list.dump();
type = S.SubstType(type, list, {}, {});
// type.dump();
arguments.clear();
} else {
ND->dump();
std::terminate();
}
// return resolve(DTST);
} else if(auto LRT = type->getAs<LValueReferenceType>()) {
type = Ctx.getLValueReferenceType(resolve(LRT->getPointeeType()));
} else {
return type;
}
}
}
QualType resolve(NamedDecl* ND) {
if(auto TD = llvm::dyn_cast<TypedefDecl>(ND)) {
return TD->getUnderlyingType();
} else if(auto TAD = llvm::dyn_cast<TypeAliasDecl>(ND)) {
return TAD->getUnderlyingType();
} else {
ND->dump();
std::terminate();
}
}
NamedDecl* resolve(const NestedNameSpecifier* NNS, const IdentifierInfo* II) {
switch(NNS->getKind()) {
// prefix is an identifier, e.g. <...>::name::
case NestedNameSpecifier::SpecifierKind::Identifier: {
return lookup(resolve(resolve(NNS->getPrefix(), NNS->getAsIdentifier())), II);
}
// prefix is a type, e.g. <...>::typename name::
case NestedNameSpecifier::SpecifierKind::TypeSpec:
case NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: {
return lookup(QualType(NNS->getAsType(), 0), II);
}
default: {
NNS->dump();
std::terminate();
}
}
}
NamedDecl* lookup(QualType Type, const IdentifierInfo* Name) {
NamedDecl* TemplateDecl;
ArrayRef<TemplateArgument> arguments;
llvm::outs() << "--------------------------------------------------------------------\n";
Type.dump();
Type->getCanonicalTypeInternal();
if(auto TTPT = Type->getAs<TemplateTypeParmType>()) {
Type->dump();
std::terminate();
} else if(auto TST = Type->getAs<TemplateSpecializationType>()) {
auto TemplateName = TST->getTemplateName();
TemplateDecl = TemplateName.getAsTemplateDecl();
arguments = TST->template_arguments();
} else if(auto DTST = Type->getAs<DependentTemplateSpecializationType>()) {
TemplateDecl = resolve(DTST->getQualifier(), DTST->getIdentifier());
arguments = DTST->template_arguments();
} else if(auto RT = Type->getAs<RecordType>()) {
return RT->getDecl()->lookup(Name).front();
} else {
Type->dump();
std::terminate();
}
this->arguments.push_back(
new std::pair<Decl*, std::vector<TemplateArgument>>{TemplateDecl, resolve(arguments)});
NamedDecl* result;
Sema::CodeSynthesisContext context;
context.Entity = TemplateDecl;
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
context.TemplateArgs = this->arguments.back()->second.data();
S.pushCodeSynthesisContext(context);
if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(TemplateDecl)) {
llvm::outs()
<< "--------------------------------------------------------------------\n";
llvm::SmallVector<ClassTemplatePartialSpecializationDecl*> paritals;
CTD->getPartialSpecializations(paritals);
for(auto partial: paritals) {
partial->getInjectedSpecializationType().dump();
}
llvm::outs()
<< "--------------------------------------------------------------------\n";
// CTD->findPartialSpecialization()
auto partial = CTD->findPartialSpecialization(Type);
if(partial) {
result = partial->lookup(Name).front();
}
if(!result) {
result = CTD->getTemplatedDecl()->lookup(Name).front();
}
} else if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(TemplateDecl)) {
result = lookup(TATD->getTemplatedDecl()->getUnderlyingType(), Name);
}
if(result == nullptr) {
Type.dump();
std::terminate();
}
return result;
}
};
} // namespace clang
#define Traverse(NAME) bool Traverse##NAME(clang::NAME* node)
#define WalkUpFrom(NAME) bool WalkUpFrom##NAME(clang::NAME* node)
#define VISIT(NAME) bool Visit##NAME(clang::NAME* node)
class ASTVistor : public clang::RecursiveASTVisitor<ASTVistor> {
private:
clang::Preprocessor& preprocessor;
clang::SourceManager& sourceManager;
clang::syntax::TokenBuffer& buffer;
clang::ASTContext& context;
clang::Sema& sema;
clang::syntax::TokenBuffer& TB;
public:
ASTVistor(clang::Preprocessor& preprocessor,
clang::syntax::TokenBuffer& buffer,
clang::ASTContext& context,
clang::Sema& sema,
clang::syntax::TokenBuffer& TB) :
preprocessor(preprocessor), sourceManager(preprocessor.getSourceManager()), buffer(buffer),
context(context), sema(sema), TB(TB) {}
bool TraverseTranslationUnitDecl(clang::TranslationUnitDecl* decl) {
for(auto it = decl->decls_begin(), end = decl->decls_end(); it != end; ++it) {
auto decl = *it;
if(sourceManager.isInMainFile(decl->getLocation())) {
TraverseDecl(*it);
}
}
return true;
}
bool VisitDecl(clang::Decl* decl) {
llvm::outs() << "Visiting Decl: " << decl->getDeclKindName() << "\n";
return true;
}
// bool VisitTypeAliasDecl(clang::TypeAliasDecl* decl) {}
// bool FieldDeclecl(clang::FieldDecl* decl) {
// llvm::outs() << "Visiting FieldDeclecl: " << decl->getDeclKindName() << "\n";
// return true;
// }
//
// bool WalkUpFromCXXRecordDecl(clang::CXXRecordDecl* decl) {
// llvm::outs() << "Visiting CXXRecordDecl\n";
// // clang::TemplateSpecializationType t;
// clang::TemplateSpecializationTypeLoc loc;
//
// return true;
//}
//
bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr* expr) {
expr->getAngleBrackets().getBegin().dump(sourceManager);
expr->getAngleBrackets().getEnd().dump(sourceManager);
return true;
}
bool VisitTypeLoc(clang::TypeLoc loc) {
// loc.dump();
return true;
}
VISIT(DeclaratorDecl) {
for(unsigned i = 0; i < node->getNumTemplateParameterLists(); ++i) {
if(auto* TPL = node->getTemplateParameterList(i)) {
TPL->getLAngleLoc().dump(sourceManager);
TPL->getRAngleLoc().dump(sourceManager);
}
}
return true;
}
VISIT(TagDecl) {
for(unsigned i = 0; i < node->getNumTemplateParameterLists(); ++i) {
if(auto* TPL = node->getTemplateParameterList(i)) {
TPL->getLAngleLoc().dump(sourceManager);
TPL->getRAngleLoc().dump(sourceManager);
}
}
return true;
}
VISIT(TemplateDecl) {
if(clang::TemplateParameterList* params = node->getTemplateParameters()) {
auto langle = params->getLAngleLoc();
auto rangle = params->getRAngleLoc();
langle.dump(sourceManager);
rangle.dump(sourceManager);
}
return true;
}
VISIT(FunctionDecl) {
if(auto* args = node->getTemplateSpecializationArgsAsWritten()) {
auto langle = args->LAngleLoc;
auto rangle = args->RAngleLoc;
langle.dump(sourceManager);
rangle.dump(sourceManager);
}
return true;
}
VISIT(ClassTemplateSpecializationDecl) {
if(const clang::ASTTemplateArgumentListInfo* args = node->getTemplateArgsAsWritten()) {
auto langle = args->getLAngleLoc();
auto rangle = args->getRAngleLoc();
langle.dump(sourceManager);
rangle.dump(sourceManager);
}
return true;
}
VISIT(ClassTemplatePartialSpecializationDecl) {
if(clang::TemplateParameterList* params = node->getTemplateParameters()) {
auto langle = params->getLAngleLoc();
auto rangle = params->getRAngleLoc();
langle.dump(sourceManager);
rangle.dump(sourceManager);
}
return true;
}
// VISIT(FunctionTemplateSpecializationInfo) {
// if(clang::TemplateParameterList* params = node->getTemplateParameters()) {
// auto langle = params->getLAngleLoc();
// auto rangle = params->getRAngleLoc();
// }
// return true;
// }
// bool VisitTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc) {
// // loc.dump();
// auto l_angle = loc.getLAngleLoc();
// l_angle.dump(sourceManager);
// auto r_angle = sourceManager.getFileLoc(loc.getRAngleLoc());
// r_angle.dump(sourceManager);
//
// // llvm::outs() << sourceManager.getSpellingColumnNumber(r_angle) << "\n";
// // llvm::outs() << sourceManager.getExpansionColumnNumber(r_angle) << "\n";
//
// llvm::outs() << sourceManager.isInMainFile(r_angle) << "\n";
//
// auto ID = sourceManager.getFileID(r_angle);
// llvm::outs() << sourceManager.getFilename(r_angle) << "\n";
//
// auto tokens = buffer.spelledTokens(sourceManager.getFileID(l_angle));
// for(auto& token: tokens) {
// token.location().dump(sourceManager);
// }
// return true;
//}
};
int main(int argc, const char** argv) {
assert(argc == 2 && "Usage: Preprocessor <source-file>");
llvm::outs() << "running ASTVisitor...\n";
auto instance = std::make_unique<clang::CompilerInstance>();
clang::DiagnosticIDs* ids = new clang::DiagnosticIDs();
clang::DiagnosticOptions* diag_opts = new clang::DiagnosticOptions();
clang::DiagnosticConsumer* consumer = new clang::IgnoringDiagConsumer();
clang::DiagnosticsEngine* engine = new clang::DiagnosticsEngine(ids, diag_opts, consumer);
instance->setDiagnostics(engine);
auto invocation = std::make_shared<clang::CompilerInvocation>();
std::vector<const char*> args = {
"/usr/local/bin/clang++",
"-Xclang",
"-no-round-trip-args",
"-std=c++20",
argv[1],
};
invocation = clang::createInvocation(args, {});
// clang::CompilerInvocation::CreateFromArgs(*invocation, args, instance->getDiagnostics());
instance->setInvocation(std::move(invocation));
if(!instance->createTarget()) {
llvm::errs() << "Failed to create target\n";
std::terminate();
}
clang::SyntaxOnlyAction action;
if(!action.BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
llvm::errs() << "Failed to begin source file\n";
std::terminate();
}
clang::syntax::TokenCollector collector{instance->getPreprocessor()};
if(auto error = action.Execute()) {
llvm::errs() << "Failed to execute action: " << error << "\n";
std::terminate();
}
clang::syntax::TokenBuffer buffer = std::move(collector).consume();
buffer.indexExpandedTokens();
auto tu = instance->getASTContext().getTranslationUnitDecl();
ASTVistor visitor{instance->getPreprocessor(),
buffer,
instance->getASTContext(),
instance->getSema(),
buffer};
visitor.TraverseDecl(tu);
action.EndSourceFile();
};