1411 lines
52 KiB
C++
1411 lines
52 KiB
C++
//------------------------------------------------------------------------------
|
|
// CLING - the C++ LLVM-based InterpreterG :)
|
|
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
|
|
//
|
|
// 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 "clang/AST/Mangle.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
using namespace clang;
|
|
|
|
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);
|
|
|
|
bool Analyze::IsWrapper(const NamedDecl* ND) {
|
|
if (!ND)
|
|
return false;
|
|
|
|
return StringRef(ND->getNameAsString())
|
|
.startswith(Synthesize::UniquePrefix);
|
|
}
|
|
|
|
void Analyze::maybeMangleDeclName(const GlobalDecl& GD,
|
|
std::string& mangledName) {
|
|
// copied and adapted from CodeGen::CodeGenModule::getMangledName
|
|
|
|
NamedDecl* D
|
|
= cast<NamedDecl>(const_cast<Decl*>(GD.getDecl()));
|
|
llvm::OwningPtr<MangleContext> mangleCtx;
|
|
mangleCtx.reset(D->getASTContext().createMangleContext());
|
|
if (!mangleCtx->shouldMangleDeclName(D)) {
|
|
IdentifierInfo *II = D->getIdentifier();
|
|
assert(II && "Attempt to mangle unnamed decl.");
|
|
mangledName = II->getName();
|
|
return;
|
|
}
|
|
|
|
llvm::raw_string_ostream RawStr(mangledName);
|
|
switch(D->getKind()) {
|
|
case Decl::CXXConstructor:
|
|
//Ctor_Complete, // Complete object ctor
|
|
//Ctor_Base, // Base object ctor
|
|
//Ctor_CompleteAllocating // Complete object allocating ctor (unused)
|
|
mangleCtx->mangleCXXCtor(cast<CXXConstructorDecl>(D),
|
|
GD.getCtorType(), RawStr);
|
|
break;
|
|
|
|
case Decl::CXXDestructor:
|
|
//Dtor_Deleting, // Deleting dtor
|
|
//Dtor_Complete, // Complete object dtor
|
|
//Dtor_Base // Base object dtor
|
|
mangleCtx->mangleCXXDtor(cast<CXXDestructorDecl>(D),
|
|
GD.getDtorType(), RawStr);
|
|
break;
|
|
|
|
default :
|
|
mangleCtx->mangleName(D, RawStr);
|
|
break;
|
|
}
|
|
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 = 0;
|
|
if (CompoundStmt* CS = dyn_cast<CompoundStmt>(FD->getBody())) {
|
|
ArrayRef<Stmt*> Stmts
|
|
= llvm::makeArrayRef(CS->body_begin(), CS->size());
|
|
int indexOfLastExpr = Stmts.size();
|
|
while(indexOfLastExpr--) {
|
|
if (!isa<NullStmt>(Stmts[indexOfLastExpr]))
|
|
break;
|
|
}
|
|
|
|
if (FoundAt)
|
|
*FoundAt = indexOfLastExpr;
|
|
|
|
if (indexOfLastExpr < 0)
|
|
return 0;
|
|
|
|
if ( (result = dyn_cast<Expr>(Stmts[indexOfLastExpr])) )
|
|
return result;
|
|
if (!omitDeclStmts)
|
|
if (DeclStmt* DS = dyn_cast<DeclStmt>(Stmts[indexOfLastExpr])) {
|
|
std::vector<Stmt*> newBody = Stmts.vec();
|
|
for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(),
|
|
E = DS->decl_rend(); I != E; ++I) {
|
|
if (VarDecl* VD = dyn_cast<VarDecl>(*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]->getLocEnd().getLocWithOffset(1);
|
|
Expr* DRE = S->BuildDeclRefExpr(VD, VDTy,VK_LValue, Loc).take();
|
|
assert(DRE && "Cannot be null");
|
|
indexOfLastExpr++;
|
|
newBody.insert(newBody.begin() + indexOfLastExpr, DRE);
|
|
|
|
// Attach the new body (note: it does dealloc/alloc of all nodes)
|
|
CS->setStmts(S->getASTContext(), &newBody.front(),newBody.size());
|
|
if (FoundAt)
|
|
*FoundAt = indexOfLastExpr;
|
|
return DRE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const char* const Synthesize::UniquePrefix = "__cling_Un1Qu3";
|
|
|
|
Expr* Synthesize::CStyleCastPtrExpr(Sema* S, QualType Ty, uint64_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).take();
|
|
assert(Result && "Cannot create CStyleCastPtrExpr");
|
|
return Result;
|
|
}
|
|
|
|
IntegerLiteral* Synthesize::IntegerLiteralExpr(ASTContext& C, uint64_t Ptr) {
|
|
const llvm::APInt Addr(8 * sizeof(void *), Ptr);
|
|
return IntegerLiteral::Create(C, Addr, C.UnsignedLongTy, SourceLocation());
|
|
}
|
|
|
|
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<const TemplateSpecializationType>(typeptr)) {
|
|
|
|
bool mightHaveChanged = false;
|
|
llvm::SmallVector<TemplateArgument, 4> desArgs;
|
|
for (TemplateSpecializationType::iterator
|
|
I = TST->begin(), E = TST->end();
|
|
I != E; ++I) {
|
|
if (I->getKind() != TemplateArgument::Type) {
|
|
desArgs.push_back(*I);
|
|
continue;
|
|
}
|
|
|
|
QualType SubTy = I->getAsType();
|
|
// Check if the type needs more desugaring and recurse.
|
|
mightHaveChanged = true;
|
|
QualType QTFQ = TypeName::GetFullyQualifiedType(SubTy, Ctx);
|
|
desArgs.push_back(TemplateArgument(QTFQ));
|
|
}
|
|
|
|
// If desugaring happened allocate new type in the AST.
|
|
if (mightHaveChanged) {
|
|
QualType QT
|
|
= Ctx.getTemplateSpecializationType(TST->getTemplateName(),
|
|
desArgs.data(), desArgs.size(),
|
|
TST->getCanonicalTypeInternal());
|
|
return QT.getTypePtr();
|
|
}
|
|
} else if (const RecordType *TSTRecord
|
|
= llvm::dyn_cast<const RecordType>(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<ClassTemplateSpecializationDecl>(TSTRecord->getDecl()))
|
|
{
|
|
const TemplateArgumentList& templateArgs
|
|
= TSTdecl->getTemplateArgs();
|
|
|
|
bool mightHaveChanged = false;
|
|
llvm::SmallVector<TemplateArgument, 4> desArgs;
|
|
for(unsigned int I = 0, E = templateArgs.size();
|
|
I != E; ++I) {
|
|
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.
|
|
mightHaveChanged = true;
|
|
QualType QTFQ = TypeName::GetFullyQualifiedType(SubTy, Ctx);
|
|
desArgs.push_back(TemplateArgument(QTFQ));
|
|
}
|
|
// If desugaring happened allocate new type in the AST.
|
|
if (mightHaveChanged) {
|
|
TemplateName TN(TSTdecl->getSpecializedTemplate());
|
|
QualType QT
|
|
= Ctx.getTemplateSpecializationType(TN,
|
|
desArgs.data(),
|
|
desArgs.size(),
|
|
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<NamespaceDecl>(DC)) {
|
|
while (NS && NS->isInline()) {
|
|
// Ignore inline namespace;
|
|
NS = dyn_cast_or_null<NamespaceDecl>(NS->getDeclContext());
|
|
}
|
|
if (NS->getDeclName())
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, NS);
|
|
return 0; // no starting '::', no anonymous
|
|
} else if (const TagDecl* TD = dyn_cast<TagDecl>(DC)) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, TD, FullyQualify);
|
|
} else if (const TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(DC)) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, TDD, FullyQualify);
|
|
}
|
|
return 0; // 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 = 0;
|
|
if (const TagType* tagdecltype = dyn_cast<TagType>(type)) {
|
|
TD = tagdecltype->getDecl();
|
|
} else {
|
|
TD = type->getAsCXXRecordDecl();
|
|
}
|
|
if (TD) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, TD,
|
|
true /*FullyQualified*/);
|
|
} else if (const TypedefType* TDD = dyn_cast<TypedefType>(type)) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, TDD->getDecl(),
|
|
true /*FullyQualified*/);
|
|
}
|
|
} else if (const NamespaceDecl* NS = scope->getAsNamespace()) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, NS);
|
|
} else if (const NamespaceAliasDecl* alias = scope->getAsNamespaceAlias()) {
|
|
const NamespaceDecl* NS = alias->getNamespace()->getCanonicalDecl();
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, NS);
|
|
}
|
|
|
|
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 = 0;
|
|
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<NamespaceDecl>(declContext);
|
|
if (new_ns) {
|
|
new_ns = new_ns->getCanonicalDecl();
|
|
NamespaceDecl *old_ns = 0;
|
|
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<NamespaceDecl>(new_ns));
|
|
}
|
|
}
|
|
} else {
|
|
const CXXRecordDecl* newtype=dyn_cast<CXXRecordDecl>(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<TagDecl>(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<TagDecl>(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<ElaboratedType>(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 = 0;
|
|
const TypedefType* typedeftype =
|
|
dyn_cast_or_null<TypedefType>(&(*desugared));
|
|
if (typedeftype) {
|
|
decl = typedeftype->getDecl();
|
|
} else {
|
|
// There are probably other cases ...
|
|
const TagType* tagdecltype = dyn_cast_or_null<TagType>(&(*desugared));
|
|
if (tagdecltype) {
|
|
decl = tagdecltype->getDecl();
|
|
} else {
|
|
decl = desugared->getAsCXXRecordDecl();
|
|
}
|
|
}
|
|
if (decl) {
|
|
NamedDecl* outer
|
|
= dyn_cast_or_null<NamedDecl>(decl->getDeclContext());
|
|
NamespaceDecl* outer_ns
|
|
= dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext());
|
|
if (outer
|
|
&& !(outer_ns && outer_ns->isAnonymousNamespace())
|
|
&& outer->getName().size() ) {
|
|
outer_scope = SelectPrefix(Ctx,decl->getDeclContext(),
|
|
outer_scope,TypeConfig);
|
|
} else {
|
|
outer_scope = 0;
|
|
}
|
|
} 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<NamedDecl>(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<NamedDecl>(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).
|
|
|
|
const clang::DeclContext *ctx = cl.getDeclContext();
|
|
|
|
while (ctx && ctx->isInlineNamespace()) {
|
|
ctx = ctx->getParent();
|
|
}
|
|
|
|
if (ctx && ctx->isNamespace())
|
|
{
|
|
const clang::NamedDecl *parent = llvm::dyn_cast<clang::NamedDecl> (ctx);
|
|
if (parent) {
|
|
if (parent->getDeclContext()->isTranslationUnit()
|
|
&& parent->getQualifiedNameAsString()=="std") {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// 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<VarDecl>(ND) || isa<FunctionDecl>(ND)) && ND->isOutOfLine() &&
|
|
!ND->getDeclContext()->getRedeclContext()->Equals(
|
|
ND->getLexicalDeclContext()->getRedeclContext()))
|
|
return false;
|
|
|
|
// Template instantiations should also not be pushed into scope.
|
|
if (isa<FunctionDecl>(ND) &&
|
|
cast<FunctionDecl>(ND)->isFunctionTemplateSpecialization())
|
|
return false;
|
|
|
|
// Using directives are not registered onto the scope chain
|
|
if (isa<UsingDirectiveDecl>(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<FunctionDecl>(D) &&
|
|
// cast<FunctionDecl>(D)->getTemplateInstantiationPattern())
|
|
// return false;
|
|
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool IsCompilerDetails(const TagType *tagTy)
|
|
{
|
|
// Return true if the TagType is a 'details' of the std implementation.
|
|
// (For now it means declared in __gnu_cxx or starting with underscore).
|
|
|
|
const TagDecl *decl = tagTy->getDecl();
|
|
assert(decl);
|
|
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<NamedDecl>(decl->getDeclContext());
|
|
while (outer && outer->getName().size() ) {
|
|
if (outer->getName().compare("__gnu_cxx") == 0) {
|
|
return true;
|
|
}
|
|
outer = dyn_cast_or_null<NamedDecl>(outer->getDeclContext());
|
|
}
|
|
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",0};
|
|
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(QualType QT,
|
|
const llvm::SmallSet<const Type*, 4>& TypesToSkip)
|
|
{
|
|
// Return true, if we should keep this typedef rather than desugaring it.
|
|
|
|
if ( 0 != TypesToSkip.count(QT.getTypePtr()) )
|
|
return true;
|
|
|
|
const TypedefType* typedeftype =
|
|
dyn_cast_or_null<TypedefType>(QT.getTypePtr());
|
|
const TypedefNameDecl* decl = typedeftype ? typedeftype->getDecl() : 0;
|
|
if (decl) {
|
|
const NamedDecl* outer
|
|
= dyn_cast_or_null<NamedDecl>(decl->getDeclContext());
|
|
// We want to keep the typedef that are defined within std and
|
|
// are pointing to something also declared in std (usually an
|
|
// implementation details like std::basic_string or __gnu_cxx::iterator.
|
|
|
|
while ( outer && outer->getName().size() ) {
|
|
// NOTE: Net is being cast too widely, replace by a lookup.
|
|
// or by using Sema::getStdNamespace
|
|
if (outer->getDeclContext()->isTranslationUnit()
|
|
&& outer->getName().compare("std") == 0) {
|
|
// And now let's check that the target is also within std.
|
|
const Type *underlyingType
|
|
= decl->getUnderlyingType().getSplitDesugaredType().Ty;
|
|
const ElaboratedType *elTy = dyn_cast<ElaboratedType>(underlyingType);
|
|
if (elTy) {
|
|
underlyingType = elTy->getNamedType().getTypePtr();
|
|
}
|
|
const TagType *tagTy = underlyingType->getAs<TagType>();
|
|
if (tagTy) {
|
|
bool details = IsCompilerDetails(tagTy);
|
|
if (details) return true;
|
|
}
|
|
}
|
|
outer = dyn_cast_or_null<NamedDecl>(outer->getDeclContext());
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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<ParenType>(QTy);
|
|
//QT = Ty->desugar();
|
|
//return true;
|
|
}
|
|
case Type::Typedef: {
|
|
const TypedefType* Ty = llvm::cast<TypedefType>(QTy);
|
|
QT = Ty->desugar();
|
|
return true;
|
|
}
|
|
case Type::TypeOf: {
|
|
const TypeOfType* Ty = llvm::cast<TypeOfType>(QTy);
|
|
QT = Ty->desugar();
|
|
return true;
|
|
}
|
|
case Type::Attributed: {
|
|
return false;
|
|
//const AttributedType* Ty = llvm::cast<AttributedType>(QTy);
|
|
//QT = Ty->desugar();
|
|
//return true;
|
|
}
|
|
case Type::SubstTemplateTypeParm: {
|
|
const SubstTemplateTypeParmType* Ty =
|
|
llvm::cast<SubstTemplateTypeParmType>(QTy);
|
|
QT = Ty->desugar();
|
|
return true;
|
|
}
|
|
case Type::Elaborated: {
|
|
const ElaboratedType* Ty = llvm::cast<ElaboratedType>(QTy);
|
|
QT = Ty->desugar();
|
|
return true;
|
|
}
|
|
//
|
|
// Conditionally sugared types.
|
|
//
|
|
case Type::TypeOfExpr: {
|
|
const TypeOfExprType* Ty = llvm::cast<TypeOfExprType>(QTy);
|
|
if (Ty->isSugared()) {
|
|
QT = Ty->desugar();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
case Type::Decltype: {
|
|
const DecltypeType* Ty = llvm::cast<DecltypeType>(QTy);
|
|
if (Ty->isSugared()) {
|
|
QT = Ty->desugar();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
case Type::UnaryTransform: {
|
|
return false;
|
|
//const UnaryTransformType* Ty = llvm::cast<UnaryTransformType>(QTy);
|
|
//if (Ty->isSugared()) {
|
|
// QT = Ty->desugar();
|
|
// return true;
|
|
//}
|
|
//return false;
|
|
}
|
|
case Type::Auto: {
|
|
return false;
|
|
//const AutoType* Ty = llvm::cast<AutoType>(QTy);
|
|
//if (Ty->isSugared()) {
|
|
// QT = Ty->desugar();
|
|
// return true;
|
|
//}
|
|
//return false;
|
|
}
|
|
case Type::TemplateSpecialization: {
|
|
return false;
|
|
//const TemplateSpecializationType* Ty =
|
|
// llvm::cast<TemplateSpecializationType>(QTy);
|
|
//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 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<PointerType>(QT.getTypePtr())) {
|
|
// Get the qualifiers.
|
|
Qualifiers quals = QT.getQualifiers();
|
|
QT = GetPartiallyDesugaredTypeImpl(Ctx, QT->getPointeeType(), TypeConfig,
|
|
fullyQualifyType,fullyQualifyTmpltArg);
|
|
QT = Ctx.getPointerType(QT);
|
|
// Add back the qualifiers.
|
|
QT = Ctx.getQualifiedType(QT, quals);
|
|
return QT;
|
|
}
|
|
|
|
while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) {
|
|
// Get the qualifiers.
|
|
Qualifiers quals = QT.getQualifiers();
|
|
|
|
QT = dyn_cast<SubstTemplateTypeParmType>(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 pointer once again.
|
|
if (isa<ReferenceType>(QT.getTypePtr())) {
|
|
// Get the qualifiers.
|
|
bool isLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
|
|
Qualifiers quals = QT.getQualifiers();
|
|
QT = GetPartiallyDesugaredTypeImpl(Ctx, QT->getPointeeType(), TypeConfig,
|
|
fullyQualifyType,fullyQualifyTmpltArg);
|
|
// 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;
|
|
}
|
|
|
|
// 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<int>::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<int> 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 = 0;
|
|
Qualifiers prefix_qualifiers;
|
|
const ElaboratedType* etype_input
|
|
= dyn_cast<ElaboratedType>(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 = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Desugar QT until we cannot desugar any more, or
|
|
// we hit one of the special typedefs.
|
|
while (1) {
|
|
if (llvm::isa<TypedefType>(QT.getTypePtr()) &&
|
|
ShouldKeepTypedef(QT, 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.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 or pointer we still need to
|
|
// desugar what they point to.
|
|
if (isa<PointerType>(QT.getTypePtr()) ||
|
|
isa<ReferenceType>(QT.getTypePtr()) ) {
|
|
return GetPartiallyDesugaredTypeImpl(Ctx, QT, TypeConfig,
|
|
fullyQualifyType,
|
|
fullyQualifyTmpltArg);
|
|
}
|
|
|
|
NestedNameSpecifier* prefix = 0;
|
|
const ElaboratedType* etype
|
|
= dyn_cast<ElaboratedType>(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 = 0;
|
|
const TypedefType* typedeftype =
|
|
dyn_cast_or_null<TypedefType>(QT.getTypePtr());
|
|
if (typedeftype) {
|
|
decl = typedeftype->getDecl();
|
|
} else {
|
|
// There are probably other cases ...
|
|
const TagType* tagdecltype = dyn_cast_or_null<TagType>(QT.getTypePtr());
|
|
if (tagdecltype) {
|
|
decl = tagdecltype->getDecl();
|
|
} else {
|
|
decl = QT->getAsCXXRecordDecl();
|
|
}
|
|
}
|
|
if (decl) {
|
|
NamedDecl* outer
|
|
= dyn_cast_or_null<NamedDecl>(decl->getDeclContext());
|
|
NamespaceDecl* outer_ns
|
|
= dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext());
|
|
if (outer
|
|
&& !(outer_ns && outer_ns->isAnonymousNamespace())
|
|
&& outer->getName().size() ) {
|
|
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 = 0; // 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<NamespaceDecl>(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 = 0; // 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<NamespaceDecl>(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<TagDecl>(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<const TemplateSpecializationType>(QT.getTypePtr())) {
|
|
|
|
bool mightHaveChanged = false;
|
|
llvm::SmallVector<TemplateArgument, 4> desArgs;
|
|
unsigned int argi = 0;
|
|
for(TemplateSpecializationType::iterator I = TST->begin(), E = TST->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<const RecordType>(canon.getTypePtr());
|
|
if (TSTRecord) {
|
|
if (const ClassTemplateSpecializationDecl* TSTdecl =
|
|
dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl()))
|
|
{
|
|
const TemplateArgumentList& templateArgs
|
|
= TSTdecl->getTemplateArgs();
|
|
|
|
mightHaveChanged = true;
|
|
desArgs.push_back(templateArgs[argi]);
|
|
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<TypedefType>(SubTy)
|
|
|| isa<TemplateSpecializationType>(SubTy)
|
|
|| isa<ElaboratedType>(SubTy)
|
|
|| fullyQualifyTmpltArg) {
|
|
mightHaveChanged = true;
|
|
QualType PDQT
|
|
= GetPartiallyDesugaredTypeImpl(Ctx, SubTy, TypeConfig,
|
|
fullyQualifyType,
|
|
fullyQualifyTmpltArg);
|
|
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.data(),
|
|
desArgs.size(),
|
|
TST->getCanonicalTypeInternal());
|
|
QT = Ctx.getQualifiedType(QT, qualifiers);
|
|
}
|
|
} else if (fullyQualifyTmpltArg) {
|
|
|
|
if (const RecordType *TSTRecord
|
|
= dyn_cast<const RecordType>(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<ClassTemplateSpecializationDecl>(TSTRecord->getDecl()))
|
|
{
|
|
const TemplateArgumentList& templateArgs
|
|
= TSTdecl->getTemplateArgs();
|
|
|
|
bool mightHaveChanged = false;
|
|
llvm::SmallVector<TemplateArgument, 4> desArgs;
|
|
for(unsigned int I = 0, E = templateArgs.size();
|
|
I != E; ++I) {
|
|
|
|
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<TypedefType>(SubTy)
|
|
|| isa<TemplateSpecializationType>(SubTy)
|
|
|| isa<ElaboratedType>(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]);
|
|
}
|
|
}
|
|
|
|
// If desugaring happened allocate new type in the AST.
|
|
if (mightHaveChanged) {
|
|
Qualifiers qualifiers = QT.getLocalQualifiers();
|
|
TemplateName TN(TSTdecl->getSpecializedTemplate());
|
|
QT = Ctx.getTemplateSpecializationType(TN, desArgs.data(),
|
|
desArgs.size(),
|
|
TSTRecord->getCanonicalTypeInternal());
|
|
QT = Ctx.getQualifiedType(QT, 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);
|
|
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
|
|
S->LookupQualifiedName(R, const_cast<DeclContext*>(Within));
|
|
|
|
if (R.empty())
|
|
return 0;
|
|
|
|
R.resolveKind();
|
|
|
|
return dyn_cast<NamespaceDecl>(R.getFoundDecl());
|
|
}
|
|
|
|
NamedDecl* Lookup::Named(Sema* S, const char* Name,
|
|
const DeclContext* Within) {
|
|
DeclarationName DName = &S->Context.Idents.get(Name);
|
|
return Lookup::Named(S, DName, Within);
|
|
}
|
|
|
|
NamedDecl* Lookup::Named(Sema* S, const DeclarationName& Name,
|
|
const DeclContext* Within) {
|
|
LookupResult R(*S, Name, SourceLocation(), Sema::LookupOrdinaryName,
|
|
Sema::ForRedeclaration);
|
|
R.suppressDiagnostics();
|
|
if (!Within)
|
|
S->LookupName(R, S->TUScope);
|
|
else
|
|
S->LookupQualifiedName(R, const_cast<DeclContext*>(Within));
|
|
|
|
if (R.empty())
|
|
return 0;
|
|
|
|
R.resolveKind();
|
|
|
|
return R.getFoundDecl();
|
|
|
|
}
|
|
|
|
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 0;
|
|
|
|
Decl *decl = 0;
|
|
if (const TypedefType* typedeftype = llvm::dyn_cast<TypedefType>(TypePtr)) {
|
|
decl = typedeftype->getDecl();
|
|
} else {
|
|
// There are probably other cases ...
|
|
if (const TagType* tagdecltype = llvm::dyn_cast_or_null<TagType>(TypePtr))
|
|
decl = tagdecltype->getDecl();
|
|
else
|
|
decl = TypePtr->getAsCXXRecordDecl();
|
|
}
|
|
|
|
if (!decl)
|
|
return 0;
|
|
|
|
NamedDecl* outer
|
|
= llvm::dyn_cast_or_null<NamedDecl>(decl->getDeclContext());
|
|
NamespaceDecl* outer_ns
|
|
= llvm::dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext());
|
|
if (outer && !(outer_ns && outer_ns->isAnonymousNamespace())) {
|
|
|
|
if (CXXRecordDecl *cxxdecl
|
|
= llvm::dyn_cast<CXXRecordDecl>(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.
|
|
if (clTempl->spec_begin() != clTempl->spec_end()) {
|
|
decl = *(clTempl->spec_begin());
|
|
outer = llvm::dyn_cast<NamedDecl>(decl);
|
|
outer_ns = llvm::dyn_cast<NamespaceDecl>(decl);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (outer_ns) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx,outer_ns);
|
|
} else if (const TagDecl* TD = llvm::dyn_cast<TagDecl>(outer)) {
|
|
return TypeName::CreateNestedNameSpecifier(Ctx, TD, FullyQualified);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
NestedNameSpecifier*
|
|
TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx,
|
|
const NamespaceDecl* Namesp) {
|
|
while (Namesp && Namesp->isInline()) {
|
|
// Ignore inline namespace;
|
|
Namesp = dyn_cast_or_null<NamespaceDecl>(Namesp->getDeclContext());
|
|
}
|
|
if (!Namesp) return 0;
|
|
|
|
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 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<PointerType>(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<ReferenceType>(QT.getTypePtr())) {
|
|
// Get the qualifiers.
|
|
bool isLValueRefTy = llvm::isa<LValueReferenceType>(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;
|
|
}
|
|
|
|
NestedNameSpecifier* prefix = 0;
|
|
Qualifiers prefix_qualifiers;
|
|
if (const ElaboratedType* etype_input
|
|
= llvm::dyn_cast<ElaboratedType>(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_qualifiers = QT.getLocalQualifiers();
|
|
prefix = GetFullyQualifiedNameSpecifier(Ctx, prefix);
|
|
QT = QualType(etype_input->getNamedType().getTypePtr(),0);
|
|
} else {
|
|
prefix = 0;
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// 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 = 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<const TemplateSpecializationType>(QT.getTypePtr())) {
|
|
|
|
Qualifiers qualifiers = QT.getLocalQualifiers();
|
|
const Type *TypePtr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr());
|
|
QT = Ctx.getQualifiedType(TypePtr, qualifiers);
|
|
|
|
} else if (llvm::isa<const RecordType>(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);
|
|
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
|