fix: adapt clice source code for LLVM 22.1 API changes

Major LLVM 22.1 breaking changes addressed:
- NestedNameSpecifier changed from pointer to value type
- ElaboratedType removed (merged into individual type nodes)
- DependentTemplateSpecializationType merged into TemplateSpecializationType
- TreeTransform overrides now require additional parameters
- TagDecl::getTypeForDecl() removed, use ASTContext::getTagType()
- InjectedClassNameType::getInjectedSpecializationType() removed
- TypedefTypeLoc::getTypedefNameDecl() renamed to getDecl()
- AnonymousTagLocations renamed to AnonymousTagNameStyle
- DIAG macro expanded from 11 to 13 parameters
- Header moves: clang/Driver/Options.h → clang/Options/Options.h
- ClangTidyModuleRegistry.h renamed to ClangTidyModule.h
- createDiagnostics/createFileManager API changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ykiko
2026-04-22 23:37:42 +08:00
parent 3e73150569
commit 2d193d80cd
17 changed files with 169 additions and 207 deletions

View File

@@ -7,9 +7,9 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Types.h"
#include "clang/Options/OptionUtils.h"
#include "clang/Options/Options.h"
namespace clice {
@@ -35,7 +35,7 @@ struct Thief {
template struct Thief<&opt::OptTable::DashDashParsing, &opt::OptTable::GroupedShortOptions>;
auto& option_table = driver::getDriverOptTable();
auto& option_table = clang::getDriverOptTable();
} // namespace
@@ -45,7 +45,7 @@ std::unique_ptr<llvm::opt::Arg> ArgumentParser::parse_one(unsigned& index) {
return option_table.ParseOneArg(*this, index, opt::Visibility(visibility_mask));
}
using ID = clang::driver::options::ID;
using ID = clang::options::ID;
bool is_discarded_option(unsigned id) {
switch(id) {
@@ -165,7 +165,7 @@ llvm::StringRef resource_dir() {
if(exe.empty()) {
return std::string{};
}
return clang::driver::Driver::GetResourcesPath(exe);
return clang::GetResourcesPath(exe);
}();
return dir;
}
@@ -246,7 +246,7 @@ std::string print_argv(llvm::ArrayRef<const char*> args) {
}
unsigned default_visibility(llvm::StringRef driver) {
namespace options = clang::driver::options;
namespace options = clang::options;
auto name = llvm::sys::path::filename(driver);
name.consume_back(".exe");

View File

@@ -6,11 +6,11 @@
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "clang/Driver/Options.h"
#include "clang/Options/Options.h"
namespace clice {
using ID = clang::driver::options::ID;
using ID = clang::options::ID;
SearchConfig extract_search_config(llvm::ArrayRef<const char*> arguments,
llvm::StringRef directory) {
@@ -24,9 +24,12 @@ SearchConfig extract_search_config(llvm::ArrayRef<const char*> arguments,
std::vector<SearchDir> after;
auto make_absolute = [&](llvm::StringRef path) -> std::string {
llvm::SmallString<256> abs_path(path);
if(!llvm::sys::path::is_absolute(abs_path)) {
llvm::sys::fs::make_absolute(directory, abs_path);
llvm::SmallString<256> abs_path;
if(llvm::sys::path::is_absolute(path)) {
abs_path = path;
} else {
abs_path = directory;
llvm::sys::path::append(abs_path, path);
}
llvm::sys::path::remove_dots(abs_path, true);
return abs_path.str().str();

View File

@@ -7,6 +7,7 @@
#include "support/logging.h"
#include "llvm/Support/Error.h"
#include "clang/Driver/CreateInvocationFromArgs.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Lex/PreprocessorOptions.h"
@@ -246,13 +247,14 @@ CompilationStatus CompilationUnitRef::Self::run_clang(
self.instance = std::make_unique<clang::CompilerInstance>(std::move(invocation));
auto& instance = *self.instance;
instance.createDiagnostics(*params.vfs, diagnostic_consumer.release(), true);
instance.createDiagnostics(diagnostic_consumer.release(), true);
if(auto remapping = clang::createVFSFromCompilerInvocation(instance.getInvocation(),
instance.getDiagnostics(),
params.vfs)) {
instance.createFileManager(std::move(remapping));
instance.setVirtualFileSystem(std::move(remapping));
}
instance.createFileManager();
if(!instance.createTarget()) {
return CompilationStatus::SetupFail;

View File

@@ -26,7 +26,9 @@ llvm::StringRef DiagnosticID::diagnostic_code() const {
SHOWINSYSHEADER, \
SHOWINSYSMACRO, \
DEFERRABLE, \
CATEGORY) \
CATEGORY, \
DIAGID, \
FLAGS) \
case clang::diag::ENUM: return #ENUM;
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"

View File

@@ -6,7 +6,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang-tidy/ClangTidyCheck.h"
#include "clang-tidy/ClangTidyModuleRegistry.h"
#include "clang-tidy/ClangTidyModule.h"
#include "clang-tidy/ClangTidyOptions.h"
namespace clice::tidy {

View File

@@ -10,7 +10,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang-tidy/ClangTidyCheck.h"
#include "clang-tidy/ClangTidyDiagnosticConsumer.h"
#include "clang-tidy/ClangTidyModuleRegistry.h"
#include "clang-tidy/ClangTidyModule.h"
#include "clang-tidy/ClangTidyOptions.h"
namespace clice::tidy {

View File

@@ -63,7 +63,8 @@ auto symbol_detail(clang::ASTContext& context, const clang::NamedDecl& decl) ->
clang::PrintingPolicy policy(context.getPrintingPolicy());
policy.SuppressScope = true;
policy.SuppressUnwrittenScope = true;
policy.AnonymousTagLocations = false;
policy.AnonymousTagNameStyle =
llvm::to_underlying(clang::PrintingPolicy::AnonymousTagMode::Plain);
policy.PolishForDeclaration = true;
std::string detail;

View File

@@ -131,8 +131,9 @@ public:
policy(unit.context().getPrintingPolicy()) {
// The sugared type is more useful in some cases, and the canonical
// type in other cases.
policy.SuppressScope = true; // keep type names short
policy.AnonymousTagLocations = false; // do not print lambda locations
policy.SuppressScope = true; // keep type names short
policy.AnonymousTagNameStyle =
llvm::to_underlying(clang::PrintingPolicy::AnonymousTagMode::Plain);
// Not setting PrintCanonicalTypes for "auto" allows
// SuppressDefaultTemplateArgs (set by default) to have an effect.
}

View File

@@ -25,7 +25,8 @@ public:
auto range = llvm::make_range(candidates, candidates + candidate_count);
auto policy = sema.getPrintingPolicy();
policy.AnonymousTagLocations = false;
policy.AnonymousTagNameStyle =
llvm::to_underlying(clang::PrintingPolicy::AnonymousTagMode::Plain);
policy.SuppressStrongLifetime = true;
policy.SuppressUnwrittenScope = true;
policy.SuppressScope = true;

View File

@@ -504,14 +504,14 @@ bool USRGenerator::GenLoc(const Decl* D, bool IncludeOffset) {
static void printQualifier(llvm::raw_ostream& Out,
const LangOptions& LangOpts,
NestedNameSpecifier* NNS) {
NestedNameSpecifier NNS) {
// FIXME: Encode the qualifier, don't just print it.
PrintingPolicy PO(LangOpts);
PO.SuppressTagKeyword = true;
PO.SuppressUnwrittenScope = true;
PO.ConstantArraySizeAsWritten = false;
PO.AnonymousTagLocations = false;
NNS->print(Out, PO);
PO.AnonymousTagNameStyle = llvm::to_underlying(PrintingPolicy::AnonymousTagMode::Plain);
NNS.print(Out, PO);
}
void USRGenerator::VisitType(QualType T) {
@@ -740,7 +740,7 @@ void USRGenerator::VisitType(QualType T) {
return;
}
if(const InjectedClassNameType* InjT = T->getAs<InjectedClassNameType>()) {
T = InjT->getInjectedSpecializationType();
T = InjT->desugar();
continue;
}
if(const auto* VT = T->getAs<VectorType>()) {

View File

@@ -200,10 +200,6 @@ llvm::StringRef identifier_of(const clang::NamedDecl& D) {
}
llvm::StringRef identifier_of(clang::QualType type) {
if(const auto* ET = llvm::dyn_cast<clang::ElaboratedType>(type)) {
return identifier_of(ET->getNamedType());
}
if(const auto* BT = llvm::dyn_cast<clang::BuiltinType>(type)) {
clang::PrintingPolicy PP(clang::LangOptions{});
PP.adjustForCPlusPlus();
@@ -308,12 +304,6 @@ const clang::NamedDecl* decl_of_impl(const void* T) {
}
auto decl_of(clang::QualType type) -> const clang::NamedDecl* {
// Strip type-sugar that wraps the underlying type without adding a decl
// (e.g. ElaboratedType for "struct Foo" vs plain "Foo").
if(auto ET = type->getAs<clang::ElaboratedType>()) {
type = ET->getNamedType();
}
if(auto TST = type->getAs<clang::TemplateSpecializationType>()) {
auto decl = TST->getTemplateName().getAsTemplateDecl();
if(type->isDependentType()) {
@@ -405,8 +395,8 @@ std::string display_name_of(const clang::NamedDecl* decl) {
// Handle 'using namespace'. They all have the same name - <using-directive>.
if(auto* UD = llvm::dyn_cast<clang::UsingDirectiveDecl>(decl)) {
out << "using namespace ";
if(auto* Qual = UD->getQualifier())
Qual->print(out, policy);
if(auto Qual = UD->getQualifier())
Qual.print(out, policy);
UD->getNominatedNamespaceAsWritten()->printName(out);
return out.str();
}
@@ -433,8 +423,8 @@ std::string display_name_of(const clang::NamedDecl* decl) {
}
// Print nested name qualifier if it was written in the source code.
if(auto* qualifier = get_qualifier_loc(decl).getNestedNameSpecifier()) {
qualifier->print(out, policy);
if(auto qualifier = get_qualifier_loc(decl).getNestedNameSpecifier()) {
qualifier.print(out, policy);
}
// Print the name itself.

View File

@@ -107,7 +107,7 @@ public:
return true;
}
bool TraverseTypeLoc(clang::TypeLoc loc) {
bool TraverseTypeLoc(clang::TypeLoc loc, bool TraverseQualifier = true) {
CHECK_DERIVED_IMPL(TraverseTypeLoc);
if(!loc) {
@@ -116,10 +116,10 @@ public:
/// FIXME: Workaround for `QualifiedTypeLoc`.
if(auto QL = loc.getAs<clang::QualifiedTypeLoc>()) {
return Base::TraverseTypeLoc(QL.getUnqualifiedLoc());
return Base::TraverseTypeLoc(QL.getUnqualifiedLoc(), TraverseQualifier);
}
return Base::TraverseTypeLoc(loc);
return Base::TraverseTypeLoc(loc, TraverseQualifier);
}
bool TraverseAttr(clang::Attr* attr) {
@@ -132,9 +132,8 @@ public:
return Base::TraverseAttr(attr);
}
/// We don't want to node withou location information.
constexpr bool TraverseNestedNameSpecifier
[[gnu::always_inline]] (clang::NestedNameSpecifier*) {
/// We don't want to node without location information.
constexpr bool TraverseNestedNameSpecifier [[gnu::always_inline]] (clang::NestedNameSpecifier) {
CHECK_DERIVED_IMPL(TraverseNestedNameSpecifier);
return true;
}

View File

@@ -167,7 +167,10 @@ static clang::QualType get_decl_type(clang::Decl* decl) {
if(auto* TND = llvm::dyn_cast<clang::TypedefNameDecl>(decl))
return TND->getUnderlyingType();
if(auto* RD = llvm::dyn_cast<clang::RecordDecl>(decl))
return clang::QualType(RD->getTypeForDecl(), 0);
return decl->getASTContext().getTagType(clang::ElaboratedTypeKeyword::None,
std::nullopt,
RD,
false);
return clang::QualType();
}
@@ -205,14 +208,11 @@ public:
/// Desugar dependent typedefs to expose template parameters for substitution.
clang::QualType TransformTypedefType(clang::TypeLocBuilder& TLB, clang::TypedefTypeLoc TL) {
if(auto* TND = TL.getTypedefNameDecl()) {
if(auto* TND = TL.getDecl()) {
auto underlying = TND->getUnderlyingType();
if(underlying->isDependentType()) {
auto type = TransformType(underlying);
if(!type.isNull()) {
if(auto ET = llvm::dyn_cast<clang::ElaboratedType>(type)) {
type = ET->getNamedType();
}
TLB.pushTrivial(context, type, {});
return type;
}
@@ -221,20 +221,10 @@ public:
return Base::TransformTypedefType(TLB, TL);
}
clang::QualType TransformElaboratedType(clang::TypeLocBuilder& TLB,
clang::ElaboratedTypeLoc TL) {
clang::QualType type = TransformType(TL.getNamedTypeLoc().getType());
if(type.isNull()) {
return Base::TransformElaboratedType(TLB, TL);
}
TLB.pushTrivial(context, type, {});
return type;
}
clang::QualType TransformInjectedClassNameType(clang::TypeLocBuilder& TLB,
clang::InjectedClassNameTypeLoc TL) {
auto ICT = TL.getTypePtr();
clang::QualType type = TransformType(ICT->getInjectedSpecializationType());
clang::QualType type = TransformType(ICT->desugar());
if(type.isNull()) {
return Base::TransformInjectedClassNameType(TLB, TL);
}
@@ -496,24 +486,25 @@ public:
}
if(auto TST = type->getAs<clang::TemplateSpecializationType>()) {
TD = TST->getTemplateName().getAsTemplateDecl();
args = TST->template_arguments();
} else if(auto DTST = type->getAs<clang::DependentTemplateSpecializationType>()) {
// If this DTST was already resolved (possibly to itself when unresolvable),
// skip the redundant lookup.
if(resolved.count(DTST)) {
return lookup_result();
}
if(auto* DTN = TST->getTemplateName().getAsDependentTemplateName()) {
// If this dependent TST was already resolved (possibly to itself when
// unresolvable), skip the redundant lookup.
if(resolved.count(TST)) {
return lookup_result();
}
auto& template_name = DTST->getDependentTemplateName();
auto name = template_name.getName().getIdentifier();
if(!name) {
return {};
}
auto name = DTN->getName().getIdentifier();
if(!name) {
return {};
}
if(auto decl = preferred(lookup(template_name.getQualifier(), name))) {
TD = decl;
args = DTST->template_arguments();
if(auto decl = preferred(lookup(DTN->getQualifier(), name))) {
TD = decl;
args = TST->template_arguments();
}
} else {
TD = TST->getTemplateName().getAsTemplateDecl();
args = TST->template_arguments();
}
}
@@ -536,45 +527,23 @@ public:
return lookup_result();
}
lookup_result lookup(const clang::NestedNameSpecifier* NNS, clang::DeclarationName name) {
lookup_result lookup(clang::NestedNameSpecifier NNS, clang::DeclarationName name) {
if(!NNS) {
return lookup_result();
}
if(auto iter = resolved.find(NNS); iter != resolved.end()) {
return lookup(iter->second, name);
}
// Handle each NestedNameSpecifier kind:
// - Identifier: dependent name in NNS chain (e.g. `base::type::inner`), resolve recursively
// - TypeSpec: concrete or dependent type used as qualifier (e.g. `vector<T>::`)
// - Global/Namespace/NamespaceAlias/Super: not dependent, cannot resolve further
switch(NNS->getKind()) {
case clang::NestedNameSpecifier::Identifier: {
auto stack_size = stack.data.size();
auto* decl = preferred(lookup(NNS->getPrefix(), NNS->getAsIdentifier()));
auto type = get_decl_type(decl);
if(!type.isNull()) {
type = substitute(type);
}
while(stack.data.size() > stack_size) {
stack.pop();
}
if(!type.isNull()) {
resolved.try_emplace(NNS, type);
return lookup(type, name);
}
return {};
// In LLVM 22+, the old Identifier NNS kind is represented as a Type
// (DependentNameType), so the Type case handles both old TypeSpec and
// Identifier cases via lookup(QualType, name) → TransformDependentNameType.
switch(NNS.getKind()) {
case clang::NestedNameSpecifier::Kind::Type: {
return lookup(clang::QualType(NNS.getAsType(), 0), name);
}
case clang::NestedNameSpecifier::TypeSpec: {
return lookup(clang::QualType(NNS->getAsType(), 0), name);
}
case clang::NestedNameSpecifier::Global:
case clang::NestedNameSpecifier::Namespace:
case clang::NestedNameSpecifier::NamespaceAlias:
case clang::NestedNameSpecifier::Super: {
case clang::NestedNameSpecifier::Kind::Global:
case clang::NestedNameSpecifier::Kind::Namespace:
case clang::NestedNameSpecifier::Kind::MicrosoftSuper:
case clang::NestedNameSpecifier::Kind::Null: {
return {};
}
}
@@ -708,14 +677,14 @@ public:
///
/// TODO: Replace with a general mechanism for resolving well-known standard
/// library patterns, or improve the resolver to handle these chains naturally.
clang::QualType hole(clang::NestedNameSpecifier* NNS,
clang::QualType hole(clang::NestedNameSpecifier NNS,
const clang::IdentifierInfo* member,
TemplateArguments arguments) {
if(NNS->getKind() != clang::NestedNameSpecifier::TypeSpec) {
if(NNS.getKind() != clang::NestedNameSpecifier::Kind::Type) {
return clang::QualType();
}
auto TST = NNS->getAsType()->getAs<clang::TemplateSpecializationType>();
auto TST = NNS.getAsType()->getAs<clang::TemplateSpecializationType>();
if(!TST) {
return clang::QualType();
}
@@ -738,17 +707,18 @@ public:
return clang::QualType();
auto T = arguments[0].getAsType();
auto prefix =
clang::NestedNameSpecifier::Create(context, nullptr, Alloc.getTypePtr());
clang::NestedNameSpecifier prefix(Alloc.getTypePtr());
auto rebind = sema.getPreprocessor().getIdentifierInfo("rebind");
auto DTST = context.getDependentTemplateSpecializationType(
clang::ElaboratedTypeKeyword::None,
clang::DependentTemplateStorage(prefix, rebind, false),
arguments);
auto DTN = context.getDependentTemplateName(
clang::DependentTemplateStorage(prefix, rebind, false));
auto TST = context.getTemplateSpecializationType(clang::ElaboratedTypeKeyword::None,
DTN,
arguments,
{});
prefix = clang::NestedNameSpecifier::Create(context, prefix, DTST.getTypePtr());
prefix = clang::NestedNameSpecifier(TST.getTypePtr());
auto other = sema.getPreprocessor().getIdentifierInfo("other");
auto DNT = context.getDependentNameType(clang::ElaboratedTypeKeyword::Typename,
@@ -770,9 +740,11 @@ public:
for(auto& arg: replaceArguments) {
canonicalArguments.emplace_back(context.getCanonicalTemplateArgument(arg));
}
auto result = context.getTemplateSpecializationType(TST->getTemplateName(),
replaceArguments,
canonicalArguments);
auto result =
context.getTemplateSpecializationType(clang::ElaboratedTypeKeyword::None,
TST->getTemplateName(),
replaceArguments,
canonicalArguments);
LOG_DEBUG(
"{}" "hole: 'allocator_traits::rebind_alloc' → '{}'",
pad(),
@@ -859,7 +831,9 @@ public:
clang::QualType TransformDependentNameType(clang::TypeLocBuilder& TLB,
clang::DependentNameTypeLoc TL,
bool DeducedTSTContext = false) {
bool DeducedTSTContext = false,
clang::QualType ObjectType = {},
clang::NamedDecl* UnqualLookup = nullptr) {
auto* DNT = TL.getTypePtr();
LOG_DEBUG("{}" "resolve '{}'", pad(), clang::QualType(DNT, 0).getAsString());
++indent;
@@ -897,7 +871,7 @@ public:
return original;
}
auto* NNS = NNSLoc.getNestedNameSpecifier();
auto NNS = NNSLoc.getNestedNameSpecifier();
auto stack_size = stack.data.size();
auto* decl = preferred(lookup(NNS, DNT->getIdentifier()));
auto type = get_decl_type(decl);
@@ -963,23 +937,32 @@ public:
return original;
}
using Base::TransformDependentTemplateSpecializationType;
clang::QualType rebuild_dtst(clang::TypeLocBuilder& TLB,
clang::DependentTemplateSpecializationTypeLoc TL) {
auto* DTST = TL.getTypePtr();
return TLB.push<clang::DependentTemplateSpecializationTypeLoc>(clang::QualType(DTST, 0))
.getType();
clang::QualType rebuild_tst(clang::TypeLocBuilder& TLB,
clang::TemplateSpecializationTypeLoc TL) {
auto* TST = TL.getTypePtr();
return TLB.push<clang::TemplateSpecializationTypeLoc>(clang::QualType(TST, 0)).getType();
}
clang::QualType TransformDependentTemplateSpecializationType(
clang::TypeLocBuilder& TLB,
clang::DependentTemplateSpecializationTypeLoc TL) {
auto* DTST = TL.getTypePtr();
LOG_DEBUG("{}" "resolve DTST '{}'", pad(), clang::QualType(DTST, 0).getAsString());
clang::QualType
TransformTemplateSpecializationType(clang::TypeLocBuilder& TLB,
clang::TemplateSpecializationTypeLoc TL,
clang::QualType ObjectType = {},
clang::NamedDecl* FirstQualifierInScope = nullptr,
bool AllowInjectedClassName = false) {
auto* TST = TL.getTypePtr();
auto* DTN = TST->getTemplateName().getAsDependentTemplateName();
if(!DTN) {
return Base::TransformTemplateSpecializationType(TLB,
TL,
ObjectType,
FirstQualifierInScope,
AllowInjectedClassName);
}
LOG_DEBUG("{}" "resolve dependent TST '{}'", pad(), clang::QualType(TST, 0).getAsString());
++indent;
if(auto iter = resolved.find(DTST); iter != resolved.end()) {
if(auto iter = resolved.find(TST); iter != resolved.end()) {
--indent;
TLB.pushTrivial(context, iter->second, {});
return iter->second;
@@ -987,19 +970,19 @@ public:
auto NNSLoc = TransformNestedNameSpecifierLoc(TL.getQualifierLoc());
if(!NNSLoc) {
LOG_DEBUG("{}→ <unresolved DTST>", pad());
LOG_DEBUG("{}→ <unresolved dependent TST>", pad());
--indent;
return rebuild_dtst(TLB, TL);
return rebuild_tst(TLB, TL);
}
auto* NNS = NNSLoc.getNestedNameSpecifier();
auto NNS = NNSLoc.getNestedNameSpecifier();
clang::TemplateArgumentListInfo info;
using iterator = clang::TemplateArgumentLocContainerIterator<
clang::DependentTemplateSpecializationTypeLoc>;
using iterator =
clang::TemplateArgumentLocContainerIterator<clang::TemplateSpecializationTypeLoc>;
if(TransformTemplateArguments(iterator(TL, 0), iterator(TL, TL.getNumArgs()), info)) {
LOG_DEBUG("{}→ <unresolved DTST>", pad());
LOG_DEBUG("{}→ <unresolved dependent TST>", pad());
--indent;
return rebuild_dtst(TLB, TL);
return rebuild_tst(TLB, TL);
}
llvm::SmallVector<clang::TemplateArgument, 4> arguments;
@@ -1007,17 +990,17 @@ public:
arguments.push_back(arg.getArgument());
}
auto* name = DTST->getDependentTemplateName().getName().getIdentifier();
auto* name = DTN->getName().getIdentifier();
if(!name) {
LOG_DEBUG("{}→ <unresolved DTST>", pad());
LOG_DEBUG("{}→ <unresolved dependent TST>", pad());
--indent;
return rebuild_dtst(TLB, TL);
return rebuild_tst(TLB, TL);
}
if(auto result = hole(NNS, name, arguments); !result.isNull()) {
LOG_DEBUG("{}" "hole: '{}' → '{}'", pad(), name->getName().str(), result.getAsString());
--indent;
resolved.try_emplace(DTST, result);
resolved.try_emplace(TST, result);
TLB.pushTrivial(context, result, {});
return result;
}
@@ -1037,26 +1020,25 @@ public:
if(!type.isNull()) {
LOG_DEBUG("{}" "→ '{}' (alias)", pad(), type.getAsString());
--indent;
resolved.try_emplace(DTST, type);
resolved.try_emplace(TST, type);
TLB.pushTrivial(context, type, {});
return type;
}
}
} else if(auto* CTD = llvm::dyn_cast<clang::ClassTemplateDecl>(decl)) {
// Resolve DTST to a concrete TemplateSpecializationType.
// e.g. __alloc_traits<allocator<T>>::rebind<T> → rebind<T> (a TST)
// This allows subsequent lookup of members (like "other") to work.
// Keep lookup frames on stack — the caller (e.g. TransformNestedNameSpecifierLoc
// processing A<X>::B<Y>::C<Z>) needs them for parameter substitution.
clang::TemplateName TN(CTD);
llvm::SmallVector<clang::TemplateArgument> canonArgs;
for(auto& arg: arguments) {
canonArgs.push_back(context.getCanonicalTemplateArgument(arg));
}
auto result = context.getTemplateSpecializationType(TN, arguments, canonArgs);
auto result =
context.getTemplateSpecializationType(clang::ElaboratedTypeKeyword::None,
TN,
arguments,
canonArgs);
LOG_DEBUG("{}" "→ TST '{}' (class)", pad(), result.getAsString());
--indent;
resolved.try_emplace(DTST, result);
resolved.try_emplace(TST, result);
TLB.pushTrivial(context, result, {});
return result;
}
@@ -1065,10 +1047,10 @@ public:
stack.pop();
}
LOG_DEBUG("{}→ <unresolved DTST>", pad());
LOG_DEBUG("{}→ <unresolved dependent TST>", pad());
--indent;
auto fallback = rebuild_dtst(TLB, TL);
resolved.try_emplace(DTST, fallback);
auto fallback = rebuild_tst(TLB, TL);
resolved.try_emplace(TST, fallback);
return fallback;
}
@@ -1077,14 +1059,11 @@ public:
/// its own TransformTypedefType). Using substitute() here ensures that typedef
/// expansion does NOT trigger heuristic lookup, preventing the typedef ↔ lookup cycle.
clang::QualType TransformTypedefType(clang::TypeLocBuilder& TLB, clang::TypedefTypeLoc TL) {
if(auto* TND = TL.getTypedefNameDecl()) {
if(auto* TND = TL.getDecl()) {
auto underlying = TND->getUnderlyingType();
if(underlying->isDependentType()) {
auto type = substitute(underlying);
if(!type.isNull()) {
if(auto ET = llvm::dyn_cast<clang::ElaboratedType>(type)) {
type = ET->getNamedType();
}
TLB.pushTrivial(context, type, {});
return type;
}
@@ -1140,7 +1119,7 @@ clang::QualType TemplateResolver::resugar(clang::QualType type, clang::Decl* dec
return resugar.TransformType(type);
}
TemplateResolver::lookup_result TemplateResolver::lookup(const clang::NestedNameSpecifier* NNS,
TemplateResolver::lookup_result TemplateResolver::lookup(clang::NestedNameSpecifier NNS,
clang::DeclarationName name) {
PseudoInstantiator instantiator(sema, resolved);
return instantiator.lookup(NNS, name);

View File

@@ -41,17 +41,17 @@ public:
using lookup_result = clang::DeclContext::lookup_result;
/// Look up the name in the given nested name specifier.
lookup_result lookup(const clang::NestedNameSpecifier* NNS, clang::DeclarationName name);
lookup_result lookup(clang::NestedNameSpecifier NNS, clang::DeclarationName name);
lookup_result lookup(const clang::DependentNameType* type) {
return lookup(type->getQualifier(), type->getIdentifier());
}
lookup_result lookup(const clang::DependentTemplateSpecializationType* type) {
auto& template_name = type->getDependentTemplateName();
auto identifier = template_name.getName().getIdentifier();
lookup_result lookup(const clang::TemplateSpecializationType* type,
const clang::DependentTemplateName* DTN) {
auto identifier = DTN->getName().getIdentifier();
if(identifier) {
return lookup(template_name.getQualifier(), identifier);
return lookup(DTN->getQualifier(), identifier);
} else {
/// TODO: Operators don't have an IdentifierInfo; need DeclarationName-based lookup.
return {};

View File

@@ -756,8 +756,8 @@ public:
return traverse_node(X, [&] { return Base::TraverseDecl(X); });
}
bool TraverseTypeLoc(clang::TypeLoc X) {
return traverse_node(&X, [&] { return Base::TraverseTypeLoc(X); });
bool TraverseTypeLoc(clang::TypeLoc X, bool TraverseQualifier = true) {
return traverse_node(&X, [&] { return Base::TraverseTypeLoc(X, TraverseQualifier); });
}
bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& X) {
@@ -814,9 +814,9 @@ public:
// This means we'd never see 'int' in 'const int'! Work around that here.
// (The reason for the behavior is to avoid traversing the nested Type twice,
// but we ignore TraverseType anyway).
bool TraverseQualifiedTypeLoc(clang::QualifiedTypeLoc QX) {
bool TraverseQualifiedTypeLoc(clang::QualifiedTypeLoc QX, bool TraverseQualifier = true) {
return traverse_node<clang::TypeLoc>(&QX, [&] {
return TraverseTypeLoc(QX.getUnqualifiedLoc());
return TraverseTypeLoc(QX.getUnqualifiedLoc(), TraverseQualifier);
});
}
@@ -825,7 +825,7 @@ public:
}
// Uninteresting parts of the AST that don't have locations within them.
bool TraverseNestedNameSpecifier(clang::NestedNameSpecifier*) {
bool TraverseNestedNameSpecifier(clang::NestedNameSpecifier) {
return true;
}

View File

@@ -515,7 +515,7 @@ public:
/// using Foo = int; Foo foo;
/// ^~~~ reference
VISIT_TYPELOC(TypedefTypeLoc) {
auto decl = loc.getTypedefNameDecl();
auto decl = loc.getDecl();
auto location = loc.getNameLoc();
handleDeclOccurrence(decl, RelationKind::Reference, location);
handleRelation(decl, RelationKind::Reference, decl, location);
@@ -561,14 +561,9 @@ public:
/// std::allocator<T>::rebind<U>
/// ^~~~ reference
VISIT_TYPELOC(DependentTemplateSpecializationTypeLoc) {
auto location = loc.getTemplateNameLoc();
// for(auto decl: resolver.lookup(loc.getTypePtr())) {
// handleDeclOccurrence(decl, RelationKind::WeakReference, location);
// handleRelation(decl, RelationKind::WeakReference, decl, location);
// }
return true;
}
/// Note: In LLVM 22+, DependentTemplateSpecializationTypeLoc was merged
/// into TemplateSpecializationTypeLoc. Dependent template cases are now
/// handled by the TemplateSpecializationTypeLoc visitor above.
/// ============================================================================
/// Specifier
@@ -576,32 +571,19 @@ public:
bool VisitNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc loc) {
auto NNS = loc.getNestedNameSpecifier();
switch(NNS->getKind()) {
case clang::NestedNameSpecifier::Namespace: {
auto decl = NNS->getAsNamespace();
switch(NNS.getKind()) {
case clang::NestedNameSpecifier::Kind::Namespace: {
auto [ns, prefix] = NNS.getAsNamespaceAndPrefix();
auto location = loc.getLocalBeginLoc();
handleDeclOccurrence(decl, RelationKind::Reference, location);
handleRelation(decl, RelationKind::Reference, decl, location);
handleDeclOccurrence(ns, RelationKind::Reference, location);
handleRelation(ns, RelationKind::Reference, ns, location);
break;
}
case clang::NestedNameSpecifier::NamespaceAlias: {
auto decl = NNS->getAsNamespaceAlias();
auto location = loc.getLocalBeginLoc();
handleDeclOccurrence(decl, RelationKind::Reference, location);
handleRelation(decl, RelationKind::Reference, decl, location);
break;
}
case clang::NestedNameSpecifier::Identifier: {
assert(NNS->isDependent() && "Identifier NNS should be dependent");
// FIXME: use TemplateResolver here.
break;
}
case clang::NestedNameSpecifier::TypeSpec:
case clang::NestedNameSpecifier::Global:
case clang::NestedNameSpecifier::Super: {
case clang::NestedNameSpecifier::Kind::Type:
case clang::NestedNameSpecifier::Kind::Global:
case clang::NestedNameSpecifier::Kind::MicrosoftSuper:
case clang::NestedNameSpecifier::Kind::Null: {
break;
};
}

View File

@@ -10,6 +10,7 @@
#include "clang/Basic/FileEntry.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Driver/CreateInvocationFromArgs.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/PPCallbacks.h"
@@ -319,9 +320,10 @@ std::unique_ptr<clang::CompilerInstance>
}
auto instance = std::make_unique<clang::CompilerInstance>(std::move(invocation));
instance->createDiagnostics(*vfs, new clang::IgnoringDiagConsumer(), true);
instance->createDiagnostics(new clang::IgnoringDiagConsumer(), true);
instance->getDiagnostics().setSuppressAllDiagnostics(true);
instance->createFileManager(vfs);
instance->setVirtualFileSystem(vfs);
instance->createFileManager();
return instance;
}