//------------------------------------------------------------------------------ // CLING - the C++ LLVM-based InterpreterG :) // author: Vassil Vassilev // // This file is dual-licensed: you can choose to license it under the University // of Illinois Open Source License or the GNU Lesser General Public License. See // LICENSE.TXT for details. //------------------------------------------------------------------------------ #include "cling/Utils/AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/GlobalDecl.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Lookup.h" #include "clang/AST/DeclTemplate.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "clang/AST/Mangle.h" #include #include using namespace clang; namespace { template static D* LookupResult2Decl(clang::LookupResult& R) { if (R.empty()) return nullptr; R.resolveKind(); if (R.isSingleResult()) return dyn_cast(R.getFoundDecl()); return (D*)-1; } } namespace cling { namespace utils { static QualType GetPartiallyDesugaredTypeImpl(const ASTContext& Ctx, QualType QT, const Transform::Config& TypeConfig, bool fullyQualifyType, bool fullyQualifyTmpltArg); static NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx, NestedNameSpecifier* scope, const Transform::Config& TypeConfig); static NestedNameSpecifier* CreateNestedNameSpecifierForScopeOf(const ASTContext& Ctx, const Decl *decl, bool FullyQualified); static NestedNameSpecifier* GetFullyQualifiedNameSpecifier(const ASTContext& Ctx, NestedNameSpecifier* scope); bool Analyze::IsWrapper(const FunctionDecl* ND) { if (!ND) return false; if (!ND->getDeclName().isIdentifier()) return false; return ND->getName().starts_with(Synthesize::UniquePrefix); } void Analyze::maybeMangleDeclName(const GlobalDecl& GD, std::string& mangledName) { // copied and adapted from CodeGen::CodeGenModule::getMangledName NamedDecl* D = cast(const_cast(GD.getDecl())); std::unique_ptr mangleCtx; mangleCtx.reset(D->getASTContext().createMangleContext()); if (!mangleCtx->shouldMangleDeclName(D)) { IdentifierInfo *II = D->getIdentifier(); assert(II && "Attempt to mangle unnamed decl."); mangledName = II->getName().str(); return; } llvm::raw_string_ostream RawStr(mangledName); #if defined(_WIN32) // MicrosoftMangle.cpp:954 calls llvm_unreachable when mangling Dtor_Comdat if (isa(GD.getDecl()) && GD.getDtorType() == Dtor_Comdat) { if (const IdentifierInfo* II = D->getIdentifier()) RawStr << II->getName(); } else #endif mangleCtx->mangleName(GD, RawStr); RawStr.flush(); } Expr* Analyze::GetOrCreateLastExpr(FunctionDecl* FD, int* FoundAt /*=0*/, bool omitDeclStmts /*=true*/, Sema* S /*=0*/) { assert(FD && "We need a function declaration!"); assert((omitDeclStmts || S) && "Sema needs to be set when omitDeclStmts is false"); if (FoundAt) *FoundAt = -1; Expr* result = nullptr; if (CompoundStmt* CS = dyn_cast(FD->getBody())) { ArrayRef Stmts(CS->body_begin(), CS->size()); int indexOfLastExpr = Stmts.size(); while(indexOfLastExpr--) { if (!isa(Stmts[indexOfLastExpr])) break; } if (FoundAt) *FoundAt = indexOfLastExpr; if (indexOfLastExpr < 0) return nullptr; if ( (result = dyn_cast(Stmts[indexOfLastExpr])) ) return result; if (!omitDeclStmts) if (DeclStmt* DS = dyn_cast(Stmts[indexOfLastExpr])) { std::vector newBody = Stmts.vec(); for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(), E = DS->decl_rend(); I != E; ++I) { if (VarDecl* VD = dyn_cast(*I)) { // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*S, FD); QualType VDTy = VD->getType().getNonReferenceType(); // Get the location of the place we will insert. SourceLocation Loc = newBody[indexOfLastExpr]->getEndLoc().getLocWithOffset(1); DeclRefExpr* DRE = S->BuildDeclRefExpr(VD, VDTy,VK_LValue, Loc); assert(DRE && "Cannot be null"); indexOfLastExpr++; newBody.insert(newBody.begin() + indexOfLastExpr, DRE); // Attach a new body. FPOptionsOverride FPFeatures; if (CS->hasStoredFPFeatures()) { FPFeatures = CS->getStoredFPFeatures(); } auto newCS = CompoundStmt::Create(S->getASTContext(), newBody, FPFeatures, CS->getLBracLoc(), CS->getRBracLoc()); FD->setBody(newCS); if (FoundAt) *FoundAt = indexOfLastExpr; return DRE; } } } return result; } return result; } const char* const Synthesize::UniquePrefix = "__cling_Un1Qu3"; IntegerLiteral* Synthesize::IntegerLiteralExpr(ASTContext& C, uintptr_t Ptr) { const llvm::APInt Addr(8 * sizeof(void*), Ptr); return IntegerLiteral::Create(C, Addr, C.getUIntPtrType(), SourceLocation()); } Expr* Synthesize::CStyleCastPtrExpr(Sema* S, QualType Ty, uintptr_t Ptr) { ASTContext& Ctx = S->getASTContext(); return CStyleCastPtrExpr(S, Ty, Synthesize::IntegerLiteralExpr(Ctx, Ptr)); } Expr* Synthesize::CStyleCastPtrExpr(Sema* S, QualType Ty, Expr* E) { ASTContext& Ctx = S->getASTContext(); if (!Ty->isPointerType()) Ty = Ctx.getPointerType(Ty); TypeSourceInfo* TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation()); Expr* Result = S->BuildCStyleCastExpr(SourceLocation(), TSI,SourceLocation(),E).get(); assert(Result && "Cannot create CStyleCastPtrExpr"); return Result; } static bool GetFullyQualifiedTemplateName(const ASTContext& Ctx, TemplateName &tname) { bool changed = false; NestedNameSpecifier *NNS = nullptr; TemplateDecl *argtdecl = tname.getAsTemplateDecl(); QualifiedTemplateName *qtname = tname.getAsQualifiedTemplateName(); if (qtname && !qtname->hasTemplateKeyword()) { NNS = qtname->getQualifier(); NestedNameSpecifier *qNNS = GetFullyQualifiedNameSpecifier(Ctx,NNS); if (qNNS != NNS) { changed = true; NNS = qNNS; } else { NNS = nullptr; } } else { NNS = CreateNestedNameSpecifierForScopeOf(Ctx, argtdecl, true); } if (NNS) { TemplateName UnderlyingTN(argtdecl); if (UsingShadowDecl *USD = tname.getAsUsingShadowDecl()) UnderlyingTN = TemplateName(USD); tname = Ctx.getQualifiedTemplateName(NNS, /*TemplateKeyword=*/ false, UnderlyingTN); changed = true; } return changed; } static bool GetFullyQualifiedTemplateArgument(const ASTContext& Ctx, TemplateArgument &arg) { bool changed = false; // Note: we do not handle TemplateArgument::Expression, to replace it // we need the information for the template instance decl. // See GetPartiallyDesugaredTypeImpl if (arg.getKind() == TemplateArgument::Template) { TemplateName tname = arg.getAsTemplate(); changed = GetFullyQualifiedTemplateName(Ctx, tname); if (changed) { arg = TemplateArgument(tname); } } else if (arg.getKind() == TemplateArgument::Type) { QualType SubTy = arg.getAsType(); // Check if the type needs more desugaring and recurse. QualType QTFQ = TypeName::GetFullyQualifiedType(SubTy, Ctx); if (QTFQ != SubTy) { arg = TemplateArgument(QTFQ); changed = true; } } else if (arg.getKind() == TemplateArgument::Pack) { SmallVector desArgs; for (auto I = arg.pack_begin(), E = arg.pack_end(); I != E; ++I) { TemplateArgument pack_arg(*I); changed = GetFullyQualifiedTemplateArgument(Ctx,pack_arg); desArgs.push_back(pack_arg); } if (changed) { // The allocator in ASTContext is mutable ... // Keep the argument const to be inline will all the other interfaces // like: NestedNameSpecifier::Create ASTContext &mutableCtx( const_cast(Ctx) ); arg = TemplateArgument::CreatePackCopy(mutableCtx, desArgs); } } return changed; } static const Type* GetFullyQualifiedLocalType(const ASTContext& Ctx, const Type *typeptr) { // We really just want to handle the template parameter if any .... // In case of template specializations iterate over the arguments and // fully qualify them as well. if (const TemplateSpecializationType* TST = llvm::dyn_cast(typeptr)) { bool mightHaveChanged = false; llvm::SmallVector desArgs; for (const TemplateArgument& Arg : TST->template_arguments()) { // cheap to copy and potentially modified by // GetFullyQualifedTemplateArgument TemplateArgument CopiedArg = Arg; mightHaveChanged |= GetFullyQualifiedTemplateArgument(Ctx, CopiedArg); desArgs.push_back(CopiedArg); } // If desugaring happened allocate new type in the AST. if (mightHaveChanged) { QualType QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(), desArgs, TST->getCanonicalTypeInternal()); return QT.getTypePtr(); } } else if (const RecordType *TSTRecord = llvm::dyn_cast(typeptr)) { // We are asked to fully qualify and we have a Record Type, // which can point to a template instantiation with no sugar in any of // its template argument, however we still need to fully qualify them. if (const ClassTemplateSpecializationDecl* TSTdecl = llvm::dyn_cast(TSTRecord->getDecl())) { const TemplateArgumentList& templateArgs = TSTdecl->getTemplateArgs(); bool mightHaveChanged = false; llvm::SmallVector desArgs; for(unsigned int I = 0, E = templateArgs.size(); I != E; ++I) { // cheap to copy and potentially modified by // GetFullyQualifedTemplateArgument TemplateArgument arg(templateArgs[I]); mightHaveChanged |= GetFullyQualifiedTemplateArgument(Ctx,arg); desArgs.push_back(arg); } // If desugaring happened allocate new type in the AST. if (mightHaveChanged) { TemplateName TN(TSTdecl->getSpecializedTemplate()); QualType QT = Ctx.getTemplateSpecializationType(TN, desArgs, TSTRecord->getCanonicalTypeInternal()); return QT.getTypePtr(); } } } return typeptr; } static NestedNameSpecifier* CreateOuterNNS(const ASTContext& Ctx, const Decl* D, bool FullyQualify) { const DeclContext* DC = D->getDeclContext(); if (const NamespaceDecl* NS = dyn_cast(DC)) { while (NS && NS->isInline()) { // Ignore inline namespace; NS = dyn_cast_or_null(NS->getDeclContext()); } if (NS && NS->getDeclName()) return TypeName::CreateNestedNameSpecifier(Ctx, NS); return nullptr; // no starting '::', no anonymous } else if (const TagDecl* TD = dyn_cast(DC)) { return TypeName::CreateNestedNameSpecifier(Ctx, TD, FullyQualify); } else if (const TypedefNameDecl* TDD = dyn_cast(DC)) { return TypeName::CreateNestedNameSpecifier(Ctx, TDD, FullyQualify); } return nullptr; // no starting '::' } static NestedNameSpecifier* GetFullyQualifiedNameSpecifier(const ASTContext& Ctx, NestedNameSpecifier* scope) { // Return a fully qualified version of this name specifier if (scope->getKind() == NestedNameSpecifier::Global) { // Already fully qualified. return scope; } if (const Type *type = scope->getAsType()) { // Find decl context. const TagDecl* TD = nullptr; if (const TagType* tagdecltype = dyn_cast(type)) { TD = tagdecltype->getDecl(); } else { TD = type->getAsCXXRecordDecl(); } if (TD) { return TypeName::CreateNestedNameSpecifier(Ctx, TD, true /*FullyQualified*/); } else if (const TypedefType* TDD = dyn_cast(type)) { return TypeName::CreateNestedNameSpecifier(Ctx, TDD->getDecl(), true /*FullyQualified*/); } else if (const UsingType* UT = dyn_cast(type)) { return TypeName::CreateNestedNameSpecifier(Ctx, UT->getFoundDecl(), true /*FullyQualified*/); } } else if (const NamespaceDecl* NS = scope->getAsNamespace()) { return TypeName::CreateNestedNameSpecifier(Ctx, NS); } else if (const NamespaceAliasDecl* alias = scope->getAsNamespaceAlias()) { const NamespaceDecl* CanonNS = alias->getNamespace()->getCanonicalDecl(); return TypeName::CreateNestedNameSpecifier(Ctx, CanonNS); } return scope; } static NestedNameSpecifier* SelectPrefix(const ASTContext& Ctx, const DeclContext *declContext, NestedNameSpecifier *original_prefix, const Transform::Config& TypeConfig) { // We have to also desugar the prefix. NestedNameSpecifier* prefix = nullptr; if (declContext) { // We had a scope prefix as input, let see if it is still // the same as the scope of the result and if it is, then // we use it. if (declContext->isNamespace()) { // Deal with namespace. This is mostly about dealing with // namespace aliases (i.e. keeping the one the user used). const NamespaceDecl *new_ns =dyn_cast(declContext); if (new_ns) { new_ns = new_ns->getCanonicalDecl(); NamespaceDecl *old_ns = nullptr; if (original_prefix) { original_prefix->getAsNamespace(); if (NamespaceAliasDecl *alias = original_prefix->getAsNamespaceAlias()) { old_ns = alias->getNamespace()->getCanonicalDecl(); } } if (old_ns == new_ns) { // This is the same namespace, use the original prefix // as a starting point. prefix = GetFullyQualifiedNameSpecifier(Ctx,original_prefix); } else { prefix = TypeName::CreateNestedNameSpecifier(Ctx, dyn_cast(new_ns)); } } } else { const CXXRecordDecl* newtype=dyn_cast(declContext); if (newtype && original_prefix) { // Deal with a class const Type *oldtype = original_prefix->getAsType(); if (oldtype && // NOTE: Should we compare the RecordDecl instead? oldtype->getAsCXXRecordDecl() == newtype) { // This is the same type, use the original prefix as a starting // point. prefix = GetPartiallyDesugaredNNS(Ctx,original_prefix,TypeConfig); } else { const TagDecl *tdecl = dyn_cast(declContext); if (tdecl) { prefix = TypeName::CreateNestedNameSpecifier(Ctx, tdecl, false /*FullyQualified*/); } } } else { // We should only create the nested name specifier // if the outer scope is really a TagDecl. // It could also be a CXXMethod for example. const TagDecl *tdecl = dyn_cast(declContext); if (tdecl) { prefix = TypeName::CreateNestedNameSpecifier(Ctx,tdecl, false /*FullyQualified*/); } } } } else { prefix = GetFullyQualifiedNameSpecifier(Ctx,original_prefix); } return prefix; } static NestedNameSpecifier* SelectPrefix(const ASTContext& Ctx, const ElaboratedType *etype, NestedNameSpecifier *original_prefix, const Transform::Config& TypeConfig) { // We have to also desugar the prefix. NestedNameSpecifier* prefix = etype->getQualifier(); if (original_prefix && prefix) { // We had a scope prefix as input, let see if it is still // the same as the scope of the result and if it is, then // we use it. const Type *newtype = prefix->getAsType(); if (newtype) { // Deal with a class const Type *oldtype = original_prefix->getAsType(); if (oldtype && // NOTE: Should we compare the RecordDecl instead? oldtype->getAsCXXRecordDecl() == newtype->getAsCXXRecordDecl()) { // This is the same type, use the original prefix as a starting // point. prefix = GetPartiallyDesugaredNNS(Ctx,original_prefix,TypeConfig); } else { prefix = GetPartiallyDesugaredNNS(Ctx,prefix,TypeConfig); } } else { // Deal with namespace. This is mostly about dealing with // namespace aliases (i.e. keeping the one the user used). const NamespaceDecl *new_ns = prefix->getAsNamespace(); if (new_ns) { new_ns = new_ns->getCanonicalDecl(); } else if (NamespaceAliasDecl *alias = prefix->getAsNamespaceAlias() ) { new_ns = alias->getNamespace()->getCanonicalDecl(); } if (new_ns) { const NamespaceDecl *old_ns = original_prefix->getAsNamespace(); if (old_ns) { old_ns = old_ns->getCanonicalDecl(); } else if (NamespaceAliasDecl *alias = original_prefix->getAsNamespaceAlias()) { old_ns = alias->getNamespace()->getCanonicalDecl(); } if (old_ns == new_ns) { // This is the same namespace, use the original prefix // as a starting point. prefix = GetFullyQualifiedNameSpecifier(Ctx,original_prefix); } else { prefix = GetFullyQualifiedNameSpecifier(Ctx,prefix); } } else { prefix = GetFullyQualifiedNameSpecifier(Ctx,prefix); } } } return prefix; } static NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx, NestedNameSpecifier* scope, const Transform::Config& TypeConfig) { // Desugar the scope qualifier if needed. if (const Type* scope_type = scope->getAsType()) { // this is not a namespace, so we might need to desugar QualType desugared = GetPartiallyDesugaredTypeImpl(Ctx, QualType(scope_type,0), TypeConfig, /*qualifyType=*/false, /*qualifyTmpltArg=*/true); NestedNameSpecifier* outer_scope = scope->getPrefix(); const ElaboratedType* etype = dyn_cast(desugared.getTypePtr()); if (etype) { // The desugarding returned an elaborated type even-though we // did not request it (/*fullyQualify=*/false), so we must have been // looking a typedef pointing at a (or another) scope. if (outer_scope) { outer_scope = SelectPrefix(Ctx,etype,outer_scope,TypeConfig); } else { outer_scope = GetPartiallyDesugaredNNS(Ctx,etype->getQualifier(), TypeConfig); } desugared = etype->getNamedType(); } else { Decl* decl = nullptr; const TypedefType* typedeftype = dyn_cast_or_null(&(*desugared)); const UsingType* usingtype = dyn_cast_or_null(&(*desugared)); if (typedeftype) { decl = typedeftype->getDecl(); } else if (usingtype) { decl = usingtype->getFoundDecl(); } else { // There are probably other cases ... const TagType* tagdecltype = dyn_cast_or_null(&(*desugared)); if (tagdecltype) { decl = tagdecltype->getDecl(); } else { decl = desugared->getAsCXXRecordDecl(); } } if (decl) { NamedDecl* outer = dyn_cast_or_null(decl->getDeclContext()); NamespaceDecl* outer_ns = dyn_cast_or_null(decl->getDeclContext()); if (outer && !(outer_ns && outer_ns->isAnonymousNamespace()) && outer->getName().size() ) { outer_scope = SelectPrefix(Ctx,decl->getDeclContext(), outer_scope,TypeConfig); } else { outer_scope = nullptr; } } else if (outer_scope) { outer_scope = GetPartiallyDesugaredNNS(Ctx, outer_scope, TypeConfig); } } return NestedNameSpecifier::Create(Ctx,outer_scope, false /* template keyword wanted */, desugared.getTypePtr()); } else { return GetFullyQualifiedNameSpecifier(Ctx,scope); } } bool Analyze::IsStdOrCompilerDetails(const NamedDecl &decl) { // Return true if the TagType is a 'details' of the std implementation // or declared within std. // Details means (For now) declared in __gnu_cxx or starting with // underscore. IdentifierInfo *info = decl.getDeclName().getAsIdentifierInfo(); if (info && info->getNameStart()[0] == '_') { // We have a name starting by _, this is reserve for compiler // implementation, so let's not desugar to it. return true; } // And let's check if it is in one of the know compiler implementation // namespace. const NamedDecl *outer =dyn_cast_or_null(decl.getDeclContext()); while (outer && outer->getName().size() ) { if (outer->getName().compare("std") == 0 || outer->getName().compare("__gnu_cxx") == 0) { return true; } outer = dyn_cast_or_null(outer->getDeclContext()); } return false; } bool Analyze::IsStdClass(const clang::NamedDecl &cl) { // Return true if the class or template is declared directly in the // std namespace (modulo inline namespace). return cl.getDeclContext()->isStdNamespace(); } // See Sema::PushOnScopeChains bool Analyze::isOnScopeChains(const NamedDecl* ND, Sema& SemaR) { // Named decls without name shouldn't be in. Eg: struct {int a}; if (!ND->getDeclName()) return false; // Out-of-line definitions shouldn't be pushed into scope in C++. // Out-of-line variable and function definitions shouldn't even in C. if ((isa(ND) || isa(ND)) && ND->isOutOfLine() && !ND->getDeclContext()->getRedeclContext()->Equals( ND->getLexicalDeclContext()->getRedeclContext())) return false; // Template instantiations should also not be pushed into scope. if (isa(ND) && cast(ND)->isFunctionTemplateSpecialization()) return false; // Using directives are not registered onto the scope chain if (isa(ND)) return false; IdentifierResolver::iterator IDRi = SemaR.IdResolver.begin(ND->getDeclName()), IDRiEnd = SemaR.IdResolver.end(); for (; IDRi != IDRiEnd; ++IDRi) { if (ND == *IDRi) return true; } // Check if the declaration is template instantiation, which is not in // any DeclContext yet, because it came from // Sema::PerformPendingInstantiations // if (isa(D) && // cast(D)->getTemplateInstantiationPattern()) // return false; return false; } unsigned int Transform::Config::DropDefaultArg(clang::TemplateDecl &Template) const { /// Return the number of default argument to drop. if (Analyze::IsStdClass(Template)) { static const char *stls[] = //container names {"vector","list","deque","map","multimap","set","multiset",nullptr}; static unsigned int values[] = //number of default arg. {1,1,1,2,2,2,2}; StringRef name = Template.getName(); for(int k=0;stls[k];k++) { if ( name.equals(stls[k]) ) return values[k]; } } // Check in some struct if the Template decl is registered something like /* DefaultCollection::const_iterator iter; iter = m_defaultArgs.find(&Template); if (iter != m_defaultArgs.end()) { return iter->second; } */ return 0; } static bool ShouldKeepTypedef(const TypedefType* TT, const llvm::SmallSet& ToSkip) { // Return true, if we should keep this typedef rather than desugaring it. return 0 != ToSkip.count(TT->getDecl()->getCanonicalDecl()); } static bool SingleStepPartiallyDesugarTypeImpl(QualType& QT) { // WARNING: // // The large blocks of commented-out code in this routine // are there to support doing more desugaring in the future, // we will probably have to. // // Do not delete until we are completely sure we will // not be changing this routine again! // const Type* QTy = QT.getTypePtr(); Type::TypeClass TC = QTy->getTypeClass(); switch (TC) { // // Unconditionally sugared types. // case Type::Paren: { return false; //const ParenType* Ty = llvm::cast(QTy); //QT = Ty->desugar(); //return true; } case Type::Typedef: { const TypedefType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } case Type::Using: { const UsingType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } case Type::TypeOf: { const TypeOfType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } case Type::Attributed: { return false; //const AttributedType* Ty = llvm::cast(QTy); //QT = Ty->desugar(); //return true; } case Type::SubstTemplateTypeParm: { const SubstTemplateTypeParmType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } case Type::Elaborated: { const ElaboratedType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } // // Conditionally sugared types. // case Type::TypeOfExpr: { const TypeOfExprType* Ty = llvm::cast(QTy); if (Ty->isSugared()) { QT = Ty->desugar(); return true; } return false; } case Type::Decltype: { const DecltypeType* Ty = llvm::cast(QTy); if (Ty->isSugared()) { QT = Ty->desugar(); return true; } return false; } case Type::UnaryTransform: { const UnaryTransformType* Ty = llvm::cast(QTy); if (Ty->isSugared()) { QT = Ty->desugar(); return true; } return false; } case Type::Auto: { return false; //const AutoType* Ty = llvm::cast(QTy); //if (Ty->isSugared()) { // QT = Ty->desugar(); // return true; //} //return false; } case Type::TemplateSpecialization: { //const TemplateSpecializationType* Ty = // llvm::cast(QTy); // Too broad, this returns a the target template but with // canonical argument types. //if (Ty->isTypeAlias()) { // QT = Ty->getAliasedType(); // return true; //} // Too broad, this returns the canonical type //if (Ty->isSugared()) { // QT = Ty->desugar(); // return true; //} return false; } // Not a sugared type. default: { break; } } return false; } bool Transform::SingleStepPartiallyDesugarType(QualType &QT, const ASTContext &Context) { Qualifiers quals = QT.getQualifiers(); bool desugared = SingleStepPartiallyDesugarTypeImpl( QT ); if (desugared) { // If the types has been desugared it also lost its qualifiers. QT = Context.getQualifiedType(QT, quals); } return desugared; } static bool GetPartiallyDesugaredTypeImpl(const ASTContext& Ctx, TemplateArgument &arg, const Transform::Config& TypeConfig, bool fullyQualifyTmpltArg) { bool changed = false; if (arg.getKind() == TemplateArgument::Template) { TemplateName tname = arg.getAsTemplate(); // Note: should we not also desugar? changed = GetFullyQualifiedTemplateName(Ctx, tname); if (changed) { arg = TemplateArgument(tname); } } else if (arg.getKind() == TemplateArgument::Type) { QualType SubTy = arg.getAsType(); // Check if the type needs more desugaring and recurse. if (isa(SubTy) || isa(SubTy) || isa(SubTy) || isa(SubTy) || fullyQualifyTmpltArg) { changed = true; QualType PDQT = GetPartiallyDesugaredTypeImpl(Ctx, SubTy, TypeConfig, /*fullyQualifyType=*/true, /*fullyQualifyTmpltArg=*/true); arg = TemplateArgument(PDQT); } } else if (arg.getKind() == TemplateArgument::Pack) { SmallVector desArgs; for (auto I = arg.pack_begin(), E = arg.pack_end(); I != E; ++I) { TemplateArgument pack_arg(*I); changed = GetPartiallyDesugaredTypeImpl(Ctx,pack_arg, TypeConfig, fullyQualifyTmpltArg); desArgs.push_back(pack_arg); } if (changed) { // The allocator in ASTContext is mutable ... // Keep the argument const to be inline will all the other interfaces // like: NestedNameSpecifier::Create ASTContext &mutableCtx( const_cast(Ctx) ); arg = TemplateArgument::CreatePackCopy(mutableCtx, desArgs); } } return changed; } static const TemplateArgument* GetTmpltArgDeepFirstIndexPack(size_t &cur, const TemplateArgument& arg, size_t idx) { SmallVector desArgs; for (auto I = arg.pack_begin(), E = arg.pack_end(); cur < idx && I != E; ++cur,++I) { if ((*I).getKind() == TemplateArgument::Pack) { auto p_arg = GetTmpltArgDeepFirstIndexPack(cur,(*I),idx); if (cur == idx) return p_arg; } else if (cur == idx) { return I; } } return nullptr; } // Return the template argument corresponding to the index (idx) // when the composite list of arguement is seen flattened out deep // first (where depth is provided by template argument packs) static const TemplateArgument* GetTmpltArgDeepFirstIndex(const TemplateArgumentList& templateArgs, size_t idx) { for (size_t cur = 0, I = 0, E = templateArgs.size(); cur <= idx && I < E; ++I, ++cur) { auto &arg = templateArgs[I]; if (arg.getKind() == TemplateArgument::Pack) { // Need to recurse. auto p_arg = GetTmpltArgDeepFirstIndexPack(cur,arg,idx); if (cur == idx) return p_arg; } else if (cur == idx) { return &arg; } } return nullptr; } static QualType GetPartiallyDesugaredTypeImpl(const ASTContext& Ctx, QualType QT, const Transform::Config& TypeConfig, bool fullyQualifyType, bool fullyQualifyTmpltArg) { if (QT.isNull()) return QT; // If there are no constraints, then use the standard desugaring. if (TypeConfig.empty() && !fullyQualifyType && !fullyQualifyTmpltArg) return QT.getDesugaredType(Ctx); // In case of Int_t* we need to strip the pointer first, desugar and attach // the pointer once again. if (isa(QT.getTypePtr())) { // Get the qualifiers. Qualifiers quals = QT.getQualifiers(); QualType nQT; nQT = GetPartiallyDesugaredTypeImpl(Ctx, QT->getPointeeType(), TypeConfig, fullyQualifyType,fullyQualifyTmpltArg); if (nQT == QT->getPointeeType()) return QT; QT = Ctx.getPointerType(nQT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } while (isa(QT.getTypePtr())) { // Get the qualifiers. Qualifiers quals = QT.getQualifiers(); QT = dyn_cast(QT.getTypePtr())->desugar(); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); } // In case of Int_t& we need to strip the pointer first, desugar and attach // the reference once again. if (isa(QT.getTypePtr())) { // Get the qualifiers. bool isLValueRefTy = isa(QT.getTypePtr()); Qualifiers quals = QT.getQualifiers(); QualType nQT; nQT = GetPartiallyDesugaredTypeImpl(Ctx, QT->getPointeeType(), TypeConfig, fullyQualifyType,fullyQualifyTmpltArg); if (nQT == QT->getPointeeType()) return QT; // Add the r- or l-value reference type back to the desugared one. if (isLValueRefTy) QT = Ctx.getLValueReferenceType(nQT); else QT = Ctx.getRValueReferenceType(nQT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } // In case of Int_t[2] we need to strip the array first, desugar and attach // the array once again. if (isa(QT.getTypePtr())) { // Get the qualifiers. Qualifiers quals = QT.getQualifiers(); if (isa(QT.getTypePtr())) { const ConstantArrayType *arr = dyn_cast(QT.getTypePtr()); QualType newQT = GetPartiallyDesugaredTypeImpl(Ctx,arr->getElementType(), TypeConfig, fullyQualifyType,fullyQualifyTmpltArg); if (newQT == arr->getElementType()) return QT; QT = Ctx.getConstantArrayType (newQT, arr->getSize(), arr->getSizeExpr(), arr->getSizeModifier(), arr->getIndexTypeCVRQualifiers()); } else if (isa(QT.getTypePtr())) { const DependentSizedArrayType *arr = dyn_cast(QT.getTypePtr()); QualType newQT = GetPartiallyDesugaredTypeImpl(Ctx,arr->getElementType(), TypeConfig, fullyQualifyType,fullyQualifyTmpltArg); if (newQT == QT) return QT; QT = Ctx.getDependentSizedArrayType (newQT, arr->getSizeExpr(), arr->getSizeModifier(), arr->getIndexTypeCVRQualifiers(), arr->getBracketsRange()); } else if (isa(QT.getTypePtr())) { const IncompleteArrayType *arr = dyn_cast(QT.getTypePtr()); QualType newQT = GetPartiallyDesugaredTypeImpl(Ctx,arr->getElementType(), TypeConfig, fullyQualifyType,fullyQualifyTmpltArg); if (newQT == arr->getElementType()) return QT; QT = Ctx.getIncompleteArrayType (newQT, arr->getSizeModifier(), arr->getIndexTypeCVRQualifiers()); } else if (isa(QT.getTypePtr())) { const VariableArrayType *arr = dyn_cast(QT.getTypePtr()); QualType newQT = GetPartiallyDesugaredTypeImpl(Ctx,arr->getElementType(), TypeConfig, fullyQualifyType,fullyQualifyTmpltArg); if (newQT == arr->getElementType()) return QT; QT = Ctx.getVariableArrayType (newQT, arr->getSizeExpr(), arr->getSizeModifier(), arr->getIndexTypeCVRQualifiers(), arr->getBracketsRange()); } // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } // If the type is elaborated, first remove the prefix and then // when we are done we will as needed add back the (new) prefix. // for example for std::vector::iterator, we work on // just 'iterator' (which remember which scope its from) // and remove the typedef to get (for example), // __gnu_cxx::__normal_iterator // which is *not* in the std::vector scope and it is // the __gnu__cxx part we should use as the prefix. // NOTE: however we problably want to add the std::vector typedefs // to the list of things to skip! NestedNameSpecifier* original_prefix = nullptr; Qualifiers prefix_qualifiers; const ElaboratedType* etype_input = dyn_cast(QT.getTypePtr()); if (etype_input) { // Intentionally, we do not care about the other compononent of // the elaborated type (the keyword) as part of the partial // desugaring (and/or name normaliztation) is to remove it. original_prefix = etype_input->getQualifier(); if (original_prefix) { const NamespaceDecl *ns = original_prefix->getAsNamespace(); if (!(ns && ns->isAnonymousNamespace())) { // We have to also desugar the prefix unless // it does not have a name (anonymous namespaces). fullyQualifyType = true; prefix_qualifiers = QT.getLocalQualifiers(); QT = QualType(etype_input->getNamedType().getTypePtr(),0); } else { original_prefix = nullptr; } } } // Desugar QT until we cannot desugar any more, or // we hit one of the special typedefs. while (1) { if (const TypedefType* TT = llvm::dyn_cast(QT.getTypePtr())){ if (ShouldKeepTypedef(TT, TypeConfig.m_toSkip)) { if (!fullyQualifyType && !fullyQualifyTmpltArg) { return QT; } // We might have stripped the namespace/scope part, // so we must go on to add it back. break; } } bool wasDesugared = Transform::SingleStepPartiallyDesugarType(QT,Ctx); // Did we get to a basic_string, let's get back to std::string Transform::Config::ReplaceCollection::const_iterator iter = TypeConfig.m_toReplace.find(QT->getCanonicalTypeInternal().getTypePtr()); if (iter != TypeConfig.m_toReplace.end()) { Qualifiers quals = QT.getQualifiers(); QT = QualType( iter->second, 0); QT = Ctx.getQualifiedType(QT,quals); break; } if (!wasDesugared) { // No more work to do, stop now. break; } } // If we have a reference, array or pointer we still need to // desugar what they point to. if (isa(QT.getTypePtr()) || isa(QT.getTypePtr()) || isa(QT.getTypePtr())) { return GetPartiallyDesugaredTypeImpl(Ctx, QT, TypeConfig, fullyQualifyType, fullyQualifyTmpltArg); } NestedNameSpecifier* prefix = nullptr; const ElaboratedType* etype = dyn_cast(QT.getTypePtr()); if (etype) { prefix = SelectPrefix(Ctx,etype,original_prefix,TypeConfig); prefix_qualifiers.addQualifiers(QT.getLocalQualifiers()); QT = QualType(etype->getNamedType().getTypePtr(),0); } else if (fullyQualifyType) { // Let's check whether this type should have been an elaborated type. // in which case we want to add it ... but we can't really preserve // the typedef in this case ... Decl *decl = nullptr; const TypedefType* typedeftype = dyn_cast_or_null(QT.getTypePtr()); const UsingType* usingtype = dyn_cast_or_null(QT.getTypePtr()); if (typedeftype) { decl = typedeftype->getDecl(); } else if (usingtype) { decl = usingtype->getFoundDecl(); } else { // There are probably other cases ... const TagType* tagdecltype = dyn_cast_or_null(QT.getTypePtr()); if (tagdecltype) { decl = tagdecltype->getDecl(); } else { decl = QT->getAsCXXRecordDecl(); } } if (decl) { NamedDecl* outer = dyn_cast_or_null(decl->getDeclContext()); NamespaceDecl* outer_ns = dyn_cast_or_null(decl->getDeclContext()); if (outer && !(outer_ns && outer_ns->isAnonymousNamespace()) && !outer->getNameAsString().empty() ) { if (original_prefix) { const Type *oldtype = original_prefix->getAsType(); if (oldtype) { if (oldtype->getAsCXXRecordDecl() == outer) { // Same type, use the original spelling prefix = GetPartiallyDesugaredNNS(Ctx, original_prefix, TypeConfig); outer = nullptr; // Cancel the later creation. } } else { const NamespaceDecl *old_ns = original_prefix->getAsNamespace(); if (old_ns) { old_ns = old_ns->getCanonicalDecl(); } else if (NamespaceAliasDecl *alias = original_prefix->getAsNamespaceAlias()) { old_ns = alias->getNamespace()->getCanonicalDecl(); } const NamespaceDecl *new_ns = dyn_cast(outer); if (new_ns) new_ns = new_ns->getCanonicalDecl(); if (old_ns == new_ns) { // This is the same namespace, use the original prefix // as a starting point. prefix = GetFullyQualifiedNameSpecifier(Ctx,original_prefix); outer = nullptr; // Cancel the later creation. } } } else { // if (!original_prefix) // move qualifiers on the outer type (avoid 'std::const string'!) prefix_qualifiers = QT.getLocalQualifiers(); QT = QualType(QT.getTypePtr(),0); } if (outer) { if (decl->getDeclContext()->isNamespace()) { prefix = TypeName::CreateNestedNameSpecifier(Ctx, dyn_cast(outer)); } else { // We should only create the nested name specifier // if the outer scope is really a TagDecl. // It could also be a CXXMethod for example. TagDecl *tdecl = dyn_cast(outer); if (tdecl) { prefix = TypeName::CreateNestedNameSpecifier(Ctx,tdecl, false /*FullyQualified*/); prefix = GetPartiallyDesugaredNNS(Ctx,prefix,TypeConfig); } } } } } } // In case of template specializations iterate over the arguments and // desugar them as well. if (const TemplateSpecializationType* TST = dyn_cast(QT.getTypePtr())) { if (TST->isTypeAlias()) { QualType targetType = TST->getAliasedType(); /* // We really need to find a way to propagate/keep the opaque typedef // that are available in TST to the aliased type. We would need // to do something like: QualType targetType = TST->getAliasedType(); QualType resubst = ReSubstTemplateArg(targetType,TST); return GetPartiallyDesugaredTypeImpl(Ctx, resubst, TypeConfig, fullyQualifyType, fullyQualifyTmpltArg); // But this is not quite right (ReSubstTemplateArg is from TMetaUtils) // as it does not resubst for template using myvector = std::vector; myvector vd32d; // and does not work at all for template using ptr = T*; ptr p2; // as the target is not a template. */ // So for now just return move on with the least lose we can do return GetPartiallyDesugaredTypeImpl(Ctx, targetType, TypeConfig, fullyQualifyType, fullyQualifyTmpltArg); } bool mightHaveChanged = false; llvm::SmallVector desArgs; llvm::ArrayRef template_arguments = TST->template_arguments(); unsigned int argi = 0; for (const clang::TemplateArgument *I = template_arguments.begin(), *E = template_arguments.end(); I != E; ++I, ++argi) { if (I->getKind() == TemplateArgument::Expression) { // If we have an expression, we need to replace it / desugar it // as it could contain unqualifed (or partially qualified or // private) parts. QualType canon = QT->getCanonicalTypeInternal(); const RecordType *TSTRecord = dyn_cast(canon.getTypePtr()); if (TSTRecord) { if (const ClassTemplateSpecializationDecl* TSTdecl = dyn_cast(TSTRecord->getDecl())) { const TemplateArgumentList& templateArgs = TSTdecl->getTemplateArgs(); mightHaveChanged = true; const TemplateArgument *match = GetTmpltArgDeepFirstIndex(templateArgs,argi); if (match) desArgs.push_back(*match); continue; } } } if (I->getKind() == TemplateArgument::Template) { TemplateName tname = I->getAsTemplate(); // Note: should we not also desugar? bool changed = GetFullyQualifiedTemplateName(Ctx, tname); if (changed) { desArgs.push_back(TemplateArgument(tname)); mightHaveChanged = true; } else desArgs.push_back(*I); continue; } if (I->getKind() != TemplateArgument::Type) { desArgs.push_back(*I); continue; } QualType SubTy = I->getAsType(); // Check if the type needs more desugaring and recurse. if (isa(SubTy) || isa(SubTy) || isa(SubTy) || isa(SubTy) || fullyQualifyTmpltArg) { QualType PDQT = GetPartiallyDesugaredTypeImpl(Ctx, SubTy, TypeConfig, fullyQualifyType, fullyQualifyTmpltArg); mightHaveChanged |= (SubTy != PDQT); desArgs.push_back(TemplateArgument(PDQT)); } else { desArgs.push_back(*I); } } // If desugaring happened allocate new type in the AST. if (mightHaveChanged) { Qualifiers qualifiers = QT.getLocalQualifiers(); QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(), desArgs, TST->getCanonicalTypeInternal()); QT = Ctx.getQualifiedType(QT, qualifiers); } } else if (fullyQualifyTmpltArg) { if (const RecordType *TSTRecord = dyn_cast(QT.getTypePtr())) { // We are asked to fully qualify and we have a Record Type, // which can point to a template instantiation with no sugar in any of // its template argument, however we still need to fully qualify them. if (const ClassTemplateSpecializationDecl* TSTdecl = dyn_cast(TSTRecord->getDecl())) { const TemplateArgumentList& templateArgs = TSTdecl->getTemplateArgs(); bool mightHaveChanged = false; llvm::SmallVector desArgs; for(unsigned int I = 0, E = templateArgs.size(); I != E; ++I) { #if 1 // cheap to copy and potentially modified by // GetPartiallyDesugaredTypeImpl TemplateArgument arg(templateArgs[I]); mightHaveChanged |= GetPartiallyDesugaredTypeImpl(Ctx,arg, TypeConfig, fullyQualifyTmpltArg); desArgs.push_back(arg); #else if (templateArgs[I].getKind() == TemplateArgument::Template) { TemplateName tname = templateArgs[I].getAsTemplate(); // Note: should we not also desugar? bool changed = GetFullyQualifiedTemplateName(Ctx, tname); if (changed) { desArgs.push_back(TemplateArgument(tname)); mightHaveChanged = true; } else desArgs.push_back(templateArgs[I]); continue; } if (templateArgs[I].getKind() != TemplateArgument::Type) { desArgs.push_back(templateArgs[I]); continue; } QualType SubTy = templateArgs[I].getAsType(); // Check if the type needs more desugaring and recurse. if (isa(SubTy) || isa(SubTy) || isa(SubTy) || isa(SubTy) || fullyQualifyTmpltArg) { mightHaveChanged = true; QualType PDQT = GetPartiallyDesugaredTypeImpl(Ctx, SubTy, TypeConfig, /*fullyQualifyType=*/true, /*fullyQualifyTmpltArg=*/true); desArgs.push_back(TemplateArgument(PDQT)); } else { desArgs.push_back(templateArgs[I]); } #endif } // If desugaring happened allocate new type in the AST. if (mightHaveChanged) { Qualifiers qualifiers = QT.getLocalQualifiers(); TemplateName TN(TSTdecl->getSpecializedTemplate()); QT = Ctx.getTemplateSpecializationType(TN, desArgs, TSTRecord->getCanonicalTypeInternal()); QT = Ctx.getQualifiedType(QT, qualifiers); } } } } // TODO: Find a way to avoid creating new types, if the input is already // fully qualified. if (prefix) { // We intentionally always use ETK_None, we never want // the keyword (humm ... what about anonymous types?) QT = Ctx.getElaboratedType(ETK_None,prefix,QT); QT = Ctx.getQualifiedType(QT, prefix_qualifiers); } else if (original_prefix) { QT = Ctx.getQualifiedType(QT, prefix_qualifiers); } return QT; } QualType Transform::GetPartiallyDesugaredType(const ASTContext& Ctx, QualType QT, const Transform::Config& TypeConfig, bool fullyQualify/*=true*/) { return GetPartiallyDesugaredTypeImpl(Ctx,QT,TypeConfig, /*qualifyType*/fullyQualify, /*qualifyTmpltArg*/fullyQualify); } NamespaceDecl* Lookup::Namespace(Sema* S, const char* Name, const DeclContext* Within) { DeclarationName DName = &S->Context.Idents.get(Name); LookupResult R(*S, DName, SourceLocation(), Sema::LookupNestedNameSpecifierName); R.suppressDiagnostics(); if (!Within) S->LookupName(R, S->TUScope); else { if (const clang::TagDecl* TD = dyn_cast(Within)) { if (!TD->getDefinition()) { // No definition, no lookup result. return nullptr; } } S->LookupQualifiedName(R, const_cast(Within)); } if (R.empty()) return nullptr; R.resolveKind(); return dyn_cast(R.getFoundDecl()); } NamedDecl* Lookup::Named(Sema* S, llvm::StringRef Name, const DeclContext* Within) { DeclarationName DName = &S->Context.Idents.get(Name); return Lookup::Named(S, DName, Within); } NamedDecl* Lookup::Named(Sema* S, const char* Name, const DeclContext* Within) { return Lookup::Named(S, llvm::StringRef(Name), Within); } NamedDecl* Lookup::Named(Sema* S, const clang::DeclarationName& Name, const DeclContext* Within) { LookupResult R(*S, Name, SourceLocation(), Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); Lookup::Named(S, R, Within); return LookupResult2Decl(R); } TagDecl* Lookup::Tag(Sema* S, llvm::StringRef Name, const DeclContext* Within) { DeclarationName DName = &S->Context.Idents.get(Name); return Lookup::Tag(S, DName, Within); } TagDecl* Lookup::Tag(Sema* S, const char* Name, const DeclContext* Within) { return Lookup::Tag(S, llvm::StringRef(Name), Within); } TagDecl* Lookup::Tag(Sema* S, const clang::DeclarationName& Name, const DeclContext* Within) { LookupResult R(*S, Name, SourceLocation(), Sema::LookupTagName, Sema::ForVisibleRedeclaration); Lookup::Named(S, R, Within); return LookupResult2Decl(R); } void Lookup::Named(Sema* S, LookupResult& R, const DeclContext* Within) { R.suppressDiagnostics(); if (!Within) S->LookupName(R, S->TUScope); else { const DeclContext* primaryWithin = nullptr; if (const clang::TagDecl *TD = dyn_cast(Within)) { primaryWithin = dyn_cast_or_null(TD->getDefinition()); } else { primaryWithin = Within->getPrimaryContext(); } if (!primaryWithin) { // No definition, no lookup result. return; } S->LookupQualifiedName(R, const_cast(primaryWithin)); } } static NestedNameSpecifier* CreateNestedNameSpecifierForScopeOf(const ASTContext& Ctx, const Decl *decl, bool FullyQualified) { // Create a nested name specifier for the declaring context of the type. assert(decl); const NamedDecl* outer = llvm::dyn_cast_or_null(decl->getDeclContext()); const NamespaceDecl* outer_ns = llvm::dyn_cast_or_null(decl->getDeclContext()); if (outer && !(outer_ns && outer_ns->isAnonymousNamespace())) { if (const CXXRecordDecl *cxxdecl = llvm::dyn_cast(decl->getDeclContext())) { if (ClassTemplateDecl *clTempl = cxxdecl->getDescribedClassTemplate()) { // We are in the case of a type(def) that was declared in a // class template but is *not* type dependent. In clang, it gets // attached to the class template declaration rather than any // specific class template instantiation. This result in 'odd' // fully qualified typename: // vector<_Tp,_Alloc>::size_type // Make the situation is 'useable' but looking a bit odd by // picking a random instance as the declaring context. // FIXME: We should not use the iterators here to check if we are in // a template specialization. clTempl != cxxdecl already tell us that // is the case. It seems that we rely on a side-effect from triggering // deserializations to support 'some' use-case. See ROOT-9709. if (clTempl->spec_begin() != clTempl->spec_end()) { decl = *(clTempl->spec_begin()); outer = llvm::dyn_cast(decl); outer_ns = llvm::dyn_cast(decl); } } } if (outer_ns) { return TypeName::CreateNestedNameSpecifier(Ctx,outer_ns); } else if (const TagDecl* TD = llvm::dyn_cast(outer)) { return TypeName::CreateNestedNameSpecifier(Ctx, TD, FullyQualified); } } return nullptr; } static NestedNameSpecifier* CreateNestedNameSpecifierForScopeOf(const ASTContext& Ctx, const Type *TypePtr, bool FullyQualified) { // Create a nested name specifier for the declaring context of the type. if (!TypePtr) return nullptr; Decl *decl = nullptr; if (const TypedefType* typedeftype = llvm::dyn_cast(TypePtr)) { decl = typedeftype->getDecl(); } else if (const UsingType* usingtype = llvm::dyn_cast(TypePtr)) { decl = usingtype->getFoundDecl(); } else { // There are probably other cases ... if (const TagType* tagdecltype = llvm::dyn_cast_or_null(TypePtr)) decl = tagdecltype->getDecl(); else decl = TypePtr->getAsCXXRecordDecl(); } if (!decl) return nullptr; return CreateNestedNameSpecifierForScopeOf(Ctx, decl, FullyQualified); } NestedNameSpecifier* TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx, const NamespaceDecl* Namesp) { while (Namesp && Namesp->isInline()) { // Ignore inline namespace; Namesp = dyn_cast_or_null(Namesp->getDeclContext()); } if (!Namesp) return nullptr; bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, Namesp, FullyQualified), Namesp); } NestedNameSpecifier* TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx, const TypedefNameDecl* TD, bool FullyQualify) { return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, TD, FullyQualify), true /*Template*/, TD->getTypeForDecl()); } NestedNameSpecifier* TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx, const UsingShadowDecl* USD, bool FullyQualify) { return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, USD, FullyQualify), true /*Template*/, cast(USD)->getTypeForDecl()); } NestedNameSpecifier* TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx, const TagDecl *TD, bool FullyQualify) { const Type* Ty = Ctx.getTypeDeclType(TD).getTypePtr(); if (FullyQualify) Ty = GetFullyQualifiedLocalType(Ctx, Ty); return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, TD, FullyQualify), false /* template keyword wanted */, Ty); } QualType TypeName::GetFullyQualifiedType(QualType QT, const ASTContext& Ctx) { // Return the fully qualified type, if we need to recurse through any // template parameter, this needs to be merged somehow with // GetPartialDesugaredType. // In case of myType* we need to strip the pointer first, fully qualifiy // and attach the pointer once again. if (llvm::isa(QT.getTypePtr())) { // Get the qualifiers. Qualifiers quals = QT.getQualifiers(); QT = GetFullyQualifiedType(QT->getPointeeType(), Ctx); QT = Ctx.getPointerType(QT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } // In case of myType& we need to strip the pointer first, fully qualifiy // and attach the pointer once again. if (llvm::isa(QT.getTypePtr())) { // Get the qualifiers. bool isLValueRefTy = llvm::isa(QT.getTypePtr()); Qualifiers quals = QT.getQualifiers(); QT = GetFullyQualifiedType(QT->getPointeeType(), Ctx); // Add the r- or l-value reference type back to the desugared one. if (isLValueRefTy) QT = Ctx.getLValueReferenceType(QT); else QT = Ctx.getRValueReferenceType(QT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } // Strip deduced types. if (const AutoType* AutoTy = dyn_cast(QT.getTypePtr())) { if (!AutoTy->getDeducedType().isNull()) return GetFullyQualifiedType(AutoTy->getDeducedType(), Ctx); } // Remove the part of the type related to the type being a template // parameter (we won't report it as part of the 'type name' and it is // actually make the code below to be more complex (to handle those) while (isa(QT.getTypePtr())) { // Get the qualifiers. Qualifiers quals = QT.getQualifiers(); QT = dyn_cast(QT.getTypePtr())->desugar(); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); } NestedNameSpecifier* prefix = nullptr; Qualifiers prefix_qualifiers = QT.getLocalQualifiers(); if (const ElaboratedType* etype_input = llvm::dyn_cast(QT.getTypePtr())) { // Intentionally, we do not care about the other compononent of // the elaborated type (the keyword) as part of the partial // desugaring (and/or name normalization) is to remove it. prefix = etype_input->getQualifier(); if (prefix) { const NamespaceDecl *ns = prefix->getAsNamespace(); if (prefix != NestedNameSpecifier::GlobalSpecifier(Ctx) && !(ns && ns->isAnonymousNamespace())) { prefix = GetFullyQualifiedNameSpecifier(Ctx, prefix); } else { prefix = nullptr; } } QT = etype_input->getNamedType(); } if (prefix == nullptr) { // Create a nested name specifier if needed (i.e. if the decl context // is not the global scope. prefix = CreateNestedNameSpecifierForScopeOf(Ctx,QT.getTypePtr(), true /*FullyQualified*/); // move the qualifiers on the outer type (avoid 'std::const string'!) if (prefix) { prefix_qualifiers.addQualifiers(QT.getLocalQualifiers()); QT = QualType(QT.getTypePtr(),0); } } // In case of template specializations iterate over the arguments and // fully qualify them as well. if(llvm::isa(QT.getTypePtr())) { Qualifiers qualifiers = QT.getLocalQualifiers(); const Type *TypePtr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr()); QT = Ctx.getQualifiedType(TypePtr, qualifiers); } else if (llvm::isa(QT.getTypePtr())) { // We are asked to fully qualify and we have a Record Type, // which can point to a template instantiation with no sugar in any of // its template argument, however we still need to fully qualify them. Qualifiers qualifiers = QT.getLocalQualifiers(); const Type *TypePtr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr()); QT = Ctx.getQualifiedType(TypePtr, qualifiers); } if (prefix) { // We intentionally always use ETK_None, we never want // the keyword (humm ... what about anonymous types?) QT = Ctx.getElaboratedType(ETK_None,prefix,QT); } if (prefix_qualifiers) { QT = Ctx.getQualifiedType(QT, prefix_qualifiers); } return QT; } std::string TypeName::GetFullyQualifiedName(QualType QT, const ASTContext &Ctx) { QualType FQQT = GetFullyQualifiedType(QT, Ctx); PrintingPolicy Policy(Ctx.getPrintingPolicy()); Policy.SuppressScope = false; Policy.AnonymousTagLocations = false; return FQQT.getAsString(Policy); } } // end namespace utils } // end namespace cling