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:
@@ -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");
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>()) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user