2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
2014-01-07 14:08:37 +04:00
//
// 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.
2012-09-05 13:37:39 +04:00
//------------------------------------------------------------------------------
# include "cling/Utils/AST.h"
# include "clang/AST/ASTContext.h"
# include "clang/AST/DeclarationName.h"
2013-10-24 22:14:19 +04:00
# include "clang/AST/GlobalDecl.h"
2012-09-05 13:37:39 +04:00
# include "clang/Sema/Sema.h"
# include "clang/Sema/Lookup.h"
2013-02-08 02:56:10 +04:00
# include "clang/AST/DeclTemplate.h"
2012-09-05 13:37:39 +04:00
2012-10-15 20:57:53 +04:00
# include "llvm/ADT/ArrayRef.h"
2013-10-23 02:08:14 +04:00
# include "clang/AST/Mangle.h"
2012-10-17 12:52:24 +04:00
# include "llvm/ADT/StringRef.h"
2013-10-23 02:08:14 +04:00
2013-02-14 21:23:47 +04:00
# include <stdio.h>
2013-10-23 02:08:14 +04:00
2012-09-05 13:37:39 +04:00
using namespace clang ;
namespace cling {
namespace utils {
2012-10-15 20:57:53 +04:00
2013-08-29 02:02:57 +04:00
static
2013-12-05 19:21:12 +04:00
QualType GetPartiallyDesugaredTypeImpl ( const ASTContext & Ctx ,
QualType QT ,
2013-09-03 08:44:24 +04:00
const Transform : : Config & TypeConfig ,
2013-08-29 02:02:57 +04:00
bool fullyQualifyType ,
bool fullyQualifyTmpltArg ) ;
static
NestedNameSpecifier * GetPartiallyDesugaredNNS ( const ASTContext & Ctx ,
2013-12-05 19:21:12 +04:00
NestedNameSpecifier * scope ,
2013-09-03 08:44:24 +04:00
const Transform : : Config & TypeConfig ) ;
2013-08-29 02:02:57 +04:00
2012-10-17 12:52:24 +04:00
bool Analyze : : IsWrapper ( const NamedDecl * ND ) {
if ( ! ND )
return false ;
2013-03-01 22:12:48 +04:00
return StringRef ( ND - > getNameAsString ( ) )
2012-10-17 12:52:24 +04:00
. startswith ( Synthesize : : UniquePrefix ) ;
}
2013-12-04 19:39:43 +04:00
void Analyze : : maybeMangleDeclName ( const GlobalDecl & GD ,
2013-10-24 22:14:19 +04:00
std : : string & mangledName ) {
2013-12-04 19:39:43 +04:00
// copied and adapted from CodeGen::CodeGenModule::getMangledName
2013-10-25 20:41:14 +04:00
2013-12-04 19:39:43 +04:00
NamedDecl * D
= cast < NamedDecl > ( const_cast < Decl * > ( GD . getDecl ( ) ) ) ;
2013-10-23 02:08:14 +04:00
llvm : : OwningPtr < MangleContext > mangleCtx ;
mangleCtx . reset ( D - > getASTContext ( ) . createMangleContext ( ) ) ;
2013-10-25 20:41:14 +04:00
if ( ! mangleCtx - > shouldMangleDeclName ( D ) ) {
IdentifierInfo * II = D - > getIdentifier ( ) ;
assert ( II & & " Attempt to mangle unnamed decl. " ) ;
mangledName = II - > getName ( ) ;
return ;
}
2013-12-05 19:21:12 +04:00
2013-10-25 01:59:15 +04:00
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)
2013-12-05 19:21:12 +04:00
mangleCtx - > mangleCXXCtor ( cast < CXXConstructorDecl > ( D ) ,
2013-10-25 01:59:15 +04:00
GD . getCtorType ( ) , RawStr ) ;
break ;
2013-10-23 02:08:14 +04:00
2013-10-25 01:59:15 +04:00
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 ;
2013-10-23 02:08:14 +04:00
2013-10-25 01:59:15 +04:00
default :
mangleCtx - > mangleName ( D , RawStr ) ;
break ;
2013-10-23 02:08:14 +04:00
}
2013-10-25 01:59:15 +04:00
RawStr . flush ( ) ;
2013-10-23 02:08:14 +04:00
}
2013-12-05 19:21:12 +04:00
Expr * Analyze : : GetOrCreateLastExpr ( FunctionDecl * FD ,
2012-10-19 13:22:36 +04:00
int * FoundAt /*=0*/ ,
bool omitDeclStmts /*=true*/ ,
2012-10-19 15:56:52 +04:00
Sema * S /*=0*/ ) {
2012-10-19 13:22:36 +04:00
assert ( FD & & " We need a function declaration! " ) ;
assert ( ( omitDeclStmts | | S )
& & " Sema needs to be set when omitDeclStmts is false " ) ;
2012-10-15 20:57:53 +04:00
if ( FoundAt )
* FoundAt = - 1 ;
2012-10-19 13:22:36 +04:00
Expr * result = 0 ;
2012-10-15 20:57:53 +04:00
if ( CompoundStmt * CS = dyn_cast < CompoundStmt > ( FD - > getBody ( ) ) ) {
2013-03-01 22:12:48 +04:00
ArrayRef < Stmt * > Stmts
2012-10-15 20:57:53 +04:00
= llvm : : makeArrayRef ( CS - > body_begin ( ) , CS - > size ( ) ) ;
int indexOfLastExpr = Stmts . size ( ) ;
2012-10-19 13:22:36 +04:00
while ( indexOfLastExpr - - ) {
if ( ! isa < NullStmt > ( Stmts [ indexOfLastExpr ] ) )
2013-12-05 19:21:12 +04:00
break ;
2012-10-19 13:22:36 +04:00
}
2012-10-15 20:57:53 +04:00
if ( FoundAt )
* FoundAt = indexOfLastExpr ;
2012-10-19 13:22:36 +04:00
2012-10-15 20:57:53 +04:00
if ( indexOfLastExpr < 0 )
return 0 ;
2012-10-19 13:22:36 +04:00
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.
2013-12-05 19:21:12 +04:00
SourceLocation Loc
2012-10-19 13:22:36 +04:00
= 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)
2013-12-05 19:21:12 +04:00
CS - > setStmts ( S - > getASTContext ( ) , & newBody . front ( ) , newBody . size ( ) ) ;
2012-10-19 13:22:36 +04:00
if ( FoundAt )
* FoundAt = indexOfLastExpr ;
return DRE ;
}
}
}
return result ;
2012-10-15 20:57:53 +04:00
}
2012-10-19 13:22:36 +04:00
return result ;
2012-10-15 20:57:53 +04:00
}
2012-10-19 17:49:34 +04:00
const char * const Synthesize : : UniquePrefix = " __cling_Un1Qu3 " ;
2012-10-17 12:52:24 +04:00
2012-09-05 13:37:39 +04:00
Expr * Synthesize : : CStyleCastPtrExpr ( Sema * S , QualType Ty , uint64_t Ptr ) {
2013-04-25 16:48:15 +04:00
ASTContext & Ctx = S - > getASTContext ( ) ;
return CStyleCastPtrExpr ( S , Ty , Synthesize : : IntegerLiteralExpr ( Ctx , Ptr ) ) ;
}
Expr * Synthesize : : CStyleCastPtrExpr ( Sema * S , QualType Ty , Expr * E ) {
2012-09-05 13:37:39 +04:00
ASTContext & Ctx = S - > getASTContext ( ) ;
if ( ! Ty - > isPointerType ( ) )
Ty = Ctx . getPointerType ( Ty ) ;
2013-04-25 16:48:15 +04:00
TypeSourceInfo * TSI = Ctx . getTrivialTypeSourceInfo ( Ty , SourceLocation ( ) ) ;
2013-12-05 19:21:12 +04:00
Expr * Result
2013-04-25 16:48:15 +04:00
= S - > BuildCStyleCastExpr ( SourceLocation ( ) , TSI , SourceLocation ( ) , E ) . take ( ) ;
2012-09-05 13:37:39 +04:00
assert ( Result & & " Cannot create CStyleCastPtrExpr " ) ;
return Result ;
}
2012-11-21 21:05:10 +04:00
IntegerLiteral * Synthesize : : IntegerLiteralExpr ( ASTContext & C , uint64_t Ptr ) {
const llvm : : APInt Addr ( 8 * sizeof ( void * ) , Ptr ) ;
return IntegerLiteral : : Create ( C , Addr , C . UnsignedLongTy , SourceLocation ( ) ) ;
}
2013-12-05 19:21:12 +04:00
static const Type *
GetFullyQualifiedLocalType ( const ASTContext & Ctx ,
const Type * typeptr ) {
2013-12-04 19:39:43 +04:00
// 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.
2013-12-05 19:21:12 +04:00
if ( const TemplateSpecializationType * TST
= llvm : : dyn_cast < const TemplateSpecializationType > ( typeptr ) ) {
2013-12-04 19:39:43 +04:00
bool mightHaveChanged = false ;
2013-12-05 19:21:12 +04:00
llvm : : SmallVector < TemplateArgument , 4 > desArgs ;
for ( TemplateSpecializationType : : iterator
I = TST - > begin ( ) , E = TST - > end ( ) ;
2013-12-04 19:39:43 +04:00
I ! = E ; + + I ) {
2013-12-05 19:21:12 +04:00
if ( I - > getKind ( ) ! = TemplateArgument : : Type ) {
2013-12-04 19:39:43 +04:00
desArgs . push_back ( * I ) ;
continue ;
}
2013-12-05 19:21:12 +04:00
QualType SubTy = I - > getAsType ( ) ;
2013-12-04 19:39:43 +04:00
// Check if the type needs more desugaring and recurse.
mightHaveChanged = true ;
2013-12-05 19:21:12 +04:00
QualType QTFQ = TypeName : : GetFullyQualifiedType ( SubTy , Ctx ) ;
desArgs . push_back ( TemplateArgument ( QTFQ ) ) ;
2013-12-04 19:39:43 +04:00
}
// If desugaring happened allocate new type in the AST.
if ( mightHaveChanged ) {
2013-12-05 19:21:12 +04:00
QualType QT
= Ctx . getTemplateSpecializationType ( TST - > getTemplateName ( ) ,
desArgs . data ( ) , desArgs . size ( ) ,
TST - > getCanonicalTypeInternal ( ) ) ;
2013-12-04 19:39:43 +04:00
return QT . getTypePtr ( ) ;
}
2013-12-05 19:21:12 +04:00
} else if ( const RecordType * TSTRecord
= llvm : : dyn_cast < const RecordType > ( typeptr ) ) {
2013-12-04 19:39:43 +04:00
// 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.
2013-12-05 19:21:12 +04:00
if ( const ClassTemplateSpecializationDecl * TSTdecl =
llvm : : dyn_cast < ClassTemplateSpecializationDecl > ( TSTRecord - > getDecl ( ) ) )
2013-12-04 19:39:43 +04:00
{
2013-12-05 19:21:12 +04:00
const TemplateArgumentList & templateArgs
2013-12-04 19:39:43 +04:00
= TSTdecl - > getTemplateArgs ( ) ;
bool mightHaveChanged = false ;
2013-12-05 19:21:12 +04:00
llvm : : SmallVector < TemplateArgument , 4 > desArgs ;
2013-12-04 19:39:43 +04:00
for ( unsigned int I = 0 , E = templateArgs . size ( ) ;
I ! = E ; + + I ) {
2013-12-05 19:21:12 +04:00
if ( templateArgs [ I ] . getKind ( ) ! = TemplateArgument : : Type ) {
2013-12-04 19:39:43 +04:00
desArgs . push_back ( templateArgs [ I ] ) ;
continue ;
}
2013-12-05 19:21:12 +04:00
QualType SubTy = templateArgs [ I ] . getAsType ( ) ;
2013-12-04 19:39:43 +04:00
// Check if the type needs more desugaring and recurse.
mightHaveChanged = true ;
2013-12-05 19:21:12 +04:00
QualType QTFQ = TypeName : : GetFullyQualifiedType ( SubTy , Ctx ) ;
desArgs . push_back ( TemplateArgument ( QTFQ ) ) ;
2013-12-04 19:39:43 +04:00
}
// If desugaring happened allocate new type in the AST.
if ( mightHaveChanged ) {
2013-12-05 19:21:12 +04:00
TemplateName TN ( TSTdecl - > getSpecializedTemplate ( ) ) ;
QualType QT
= Ctx . getTemplateSpecializationType ( TN ,
desArgs . data ( ) ,
desArgs . size ( ) ,
TSTRecord - > getCanonicalTypeInternal ( ) ) ;
2013-12-04 19:39:43 +04:00
return QT . getTypePtr ( ) ;
}
}
2012-12-11 12:26:00 +04:00
}
2013-12-04 19:39:43 +04:00
return typeptr ;
2012-12-11 12:26:00 +04:00
}
2013-12-04 19:39:43 +04:00
static NestedNameSpecifier * CreateOuterNNS ( const ASTContext & Ctx ,
2013-12-04 21:26:23 +04:00
const Decl * D ,
bool FullyQualify ) {
2013-12-04 19:39:43 +04:00
const DeclContext * DC = D - > getDeclContext ( ) ;
if ( const NamespaceDecl * NS = dyn_cast < NamespaceDecl > ( DC ) ) {
2014-01-12 19:59:12 +04:00
while ( NS & & NS - > isInline ( ) ) {
// Ignore inline namespace;
NS = dyn_cast_or_null < NamespaceDecl > ( NS - > getDeclContext ( ) ) ;
}
2013-12-04 19:39:43 +04:00
if ( NS - > getDeclName ( ) )
return TypeName : : CreateNestedNameSpecifier ( Ctx , NS ) ;
2014-01-06 21:04:47 +04:00
return 0 ; // no starting '::', no anonymous
2013-12-04 19:39:43 +04:00
} else if ( const TagDecl * TD = dyn_cast < TagDecl > ( DC ) ) {
2013-12-04 21:26:23 +04:00
return TypeName : : CreateNestedNameSpecifier ( Ctx , TD , FullyQualify ) ;
2014-01-06 21:04:47 +04:00
} else if ( const TypedefNameDecl * TDD = dyn_cast < TypedefNameDecl > ( DC ) ) {
return TypeName : : CreateNestedNameSpecifier ( Ctx , TDD , FullyQualify ) ;
2012-12-11 12:26:00 +04:00
}
2013-12-05 19:21:12 +04:00
return 0 ; // no starting '::'
2012-12-11 12:26:00 +04:00
}
2013-12-04 19:39:43 +04:00
2013-03-01 21:59:59 +04:00
static
NestedNameSpecifier * GetFullyQualifiedNameSpecifier ( const ASTContext & Ctx ,
NestedNameSpecifier * scope ) {
// Return a fully qualified version of this name specifier
2014-01-06 21:04:47 +04:00
if ( scope - > getKind ( ) = = NestedNameSpecifier : : Global ) {
// Already fully qualified.
2013-12-21 18:06:08 +04:00
return scope ;
2013-03-01 21:59:59 +04:00
}
2014-01-06 21:04:47 +04:00
if ( const Type * type = scope - > getAsType ( ) ) {
2013-03-01 21:59:59 +04:00
// Find decl context.
2014-01-06 21:04:47 +04:00
const TagDecl * TD = 0 ;
if ( const TagType * tagdecltype = dyn_cast < TagType > ( type ) ) {
TD = tagdecltype - > getDecl ( ) ;
2013-03-01 21:59:59 +04:00
} else {
2014-01-06 21:04:47 +04:00
TD = type - > getAsCXXRecordDecl ( ) ;
2013-03-01 21:59:59 +04:00
}
2014-01-06 21:04:47 +04:00
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*/ ) ;
2013-03-01 21:59:59 +04:00
}
2014-01-06 21:04:47 +04:00
} 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 ) ;
2013-03-01 21:59:59 +04:00
}
return scope ;
}
2013-12-05 19:21:12 +04:00
2013-03-01 21:59:59 +04:00
static
NestedNameSpecifier * SelectPrefix ( const ASTContext & Ctx ,
2013-03-01 22:06:58 +04:00
const DeclContext * declContext ,
2013-03-01 21:59:59 +04:00
NestedNameSpecifier * original_prefix ,
2013-09-03 08:44:24 +04:00
const Transform : : Config & TypeConfig ) {
2013-03-01 21:59:59 +04:00
// 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).
2013-03-01 22:12:48 +04:00
const NamespaceDecl * new_ns = dyn_cast < NamespaceDecl > ( declContext ) ;
2013-03-01 21:59:59 +04:00
if ( new_ns ) {
new_ns = new_ns - > getCanonicalDecl ( ) ;
NamespaceDecl * old_ns = 0 ;
if ( original_prefix ) {
original_prefix - > getAsNamespace ( ) ;
2013-09-06 06:36:00 +04:00
if ( NamespaceAliasDecl * alias =
2013-03-01 21:59:59 +04:00
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 {
2013-12-04 19:39:43 +04:00
prefix = TypeName : : CreateNestedNameSpecifier ( Ctx ,
2013-03-01 21:59:59 +04:00
dyn_cast < NamespaceDecl > ( new_ns ) ) ;
}
}
} else {
2013-03-01 22:12:48 +04:00
const CXXRecordDecl * newtype = dyn_cast < CXXRecordDecl > ( declContext ) ;
2013-03-01 21:59:59 +04:00
if ( newtype & & original_prefix ) {
// Deal with a class
2013-03-01 22:06:58 +04:00
const Type * oldtype = original_prefix - > getAsType ( ) ;
2013-03-01 21:59:59 +04:00
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.
2013-09-03 08:44:24 +04:00
prefix = GetPartiallyDesugaredNNS ( Ctx , original_prefix , TypeConfig ) ;
2013-03-01 21:59:59 +04:00
} else {
2013-03-01 22:12:48 +04:00
const TagDecl * tdecl = dyn_cast < TagDecl > ( declContext ) ;
2013-03-01 21:59:59 +04:00
if ( tdecl ) {
2013-12-04 21:26:23 +04:00
prefix = TypeName : : CreateNestedNameSpecifier ( Ctx , tdecl ,
false /*FullyQualified*/ ) ;
2013-03-01 21:59:59 +04:00
}
}
} 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.
2013-03-01 22:12:48 +04:00
const TagDecl * tdecl = dyn_cast < TagDecl > ( declContext ) ;
2013-03-01 21:59:59 +04:00
if ( tdecl ) {
2013-12-04 21:26:23 +04:00
prefix = TypeName : : CreateNestedNameSpecifier ( Ctx , tdecl ,
false /*FullyQualified*/ ) ;
2013-03-01 21:59:59 +04:00
}
}
}
} else {
prefix = GetFullyQualifiedNameSpecifier ( Ctx , original_prefix ) ;
}
return prefix ;
}
static
2012-12-11 12:26:00 +04:00
NestedNameSpecifier * SelectPrefix ( const ASTContext & Ctx ,
const ElaboratedType * etype ,
NestedNameSpecifier * original_prefix ,
2013-09-03 08:44:24 +04:00
const Transform : : Config & TypeConfig ) {
2012-12-11 12:26:00 +04:00
// We have to also desugar the prefix.
2013-12-05 19:21:12 +04:00
2012-12-11 12:26:00 +04:00
NestedNameSpecifier * prefix = etype - > getQualifier ( ) ;
2013-02-15 16:42:09 +04:00
if ( original_prefix & & prefix ) {
2012-12-11 12:26:00 +04:00
// 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.
2013-03-01 22:06:58 +04:00
const Type * newtype = prefix - > getAsType ( ) ;
2012-12-11 12:26:00 +04:00
if ( newtype ) {
// Deal with a class
2013-03-01 22:06:58 +04:00
const Type * oldtype = original_prefix - > getAsType ( ) ;
2013-12-05 19:21:12 +04:00
if ( oldtype & &
2012-12-11 12:26:00 +04:00
// NOTE: Should we compare the RecordDecl instead?
oldtype - > getAsCXXRecordDecl ( ) = = newtype - > getAsCXXRecordDecl ( ) )
2013-12-05 19:21:12 +04:00
{
2012-12-11 12:26:00 +04:00
// This is the same type, use the original prefix as a starting
// point.
2013-09-03 08:44:24 +04:00
prefix = GetPartiallyDesugaredNNS ( Ctx , original_prefix , TypeConfig ) ;
2012-12-11 12:26:00 +04:00
} else {
2013-09-03 08:44:24 +04:00
prefix = GetPartiallyDesugaredNNS ( Ctx , prefix , TypeConfig ) ;
2012-12-11 12:26:00 +04:00
}
} 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 ( ) ;
2013-12-05 19:21:12 +04:00
}
2013-02-15 16:42:09 +04:00
else if ( NamespaceAliasDecl * alias = prefix - > getAsNamespaceAlias ( ) )
2012-12-11 12:26:00 +04:00
{
new_ns = alias - > getNamespace ( ) - > getCanonicalDecl ( ) ;
}
if ( new_ns ) {
const NamespaceDecl * old_ns = original_prefix - > getAsNamespace ( ) ;
if ( old_ns ) {
old_ns = old_ns - > getCanonicalDecl ( ) ;
}
2013-12-05 19:21:12 +04:00
else if ( NamespaceAliasDecl * alias =
2012-12-11 12:26:00 +04:00
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.
2013-03-01 21:59:59 +04:00
prefix = GetFullyQualifiedNameSpecifier ( Ctx , original_prefix ) ;
} else {
prefix = GetFullyQualifiedNameSpecifier ( Ctx , prefix ) ;
2012-12-11 12:26:00 +04:00
}
2013-03-01 21:59:59 +04:00
} else {
prefix = GetFullyQualifiedNameSpecifier ( Ctx , prefix ) ;
2012-12-11 12:26:00 +04:00
}
}
}
return prefix ;
}
2013-12-05 19:21:12 +04:00
2012-09-05 13:37:39 +04:00
static
2013-09-03 08:44:24 +04:00
NestedNameSpecifier * GetPartiallyDesugaredNNS ( const ASTContext & Ctx ,
2013-12-05 19:21:12 +04:00
NestedNameSpecifier * scope ,
2013-09-03 08:44:24 +04:00
const Transform : : Config & TypeConfig ) {
2012-09-05 13:37:39 +04:00
// Desugar the scope qualifier if needed.
2013-03-01 21:59:59 +04:00
if ( const Type * scope_type = scope - > getAsType ( ) ) {
2013-12-05 19:21:12 +04:00
2012-09-05 13:37:39 +04:00
// this is not a namespace, so we might need to desugar
2013-08-29 02:02:57 +04:00
QualType desugared = GetPartiallyDesugaredTypeImpl ( Ctx ,
QualType ( scope_type , 0 ) ,
2013-09-03 08:44:24 +04:00
TypeConfig ,
2013-08-29 02:02:57 +04:00
/*qualifyType=*/ false ,
/*qualifyTmpltArg=*/ true ) ;
2013-03-01 21:59:59 +04:00
2012-09-05 13:37:39 +04:00
NestedNameSpecifier * outer_scope = scope - > getPrefix ( ) ;
2013-03-01 21:59:59 +04:00
const ElaboratedType * etype
2013-03-01 22:12:48 +04:00
= dyn_cast < ElaboratedType > ( desugared . getTypePtr ( ) ) ;
2013-03-01 21:59:59 +04:00
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.
2013-12-05 19:21:12 +04:00
2013-03-01 21:59:59 +04:00
if ( outer_scope ) {
2013-09-03 08:44:24 +04:00
outer_scope = SelectPrefix ( Ctx , etype , outer_scope , TypeConfig ) ;
2013-03-01 21:59:59 +04:00
} else {
outer_scope = GetPartiallyDesugaredNNS ( Ctx , etype - > getQualifier ( ) ,
2013-09-03 08:44:24 +04:00
TypeConfig ) ;
2013-03-01 21:59:59 +04:00
}
desugared = etype - > getNamedType ( ) ;
2012-12-11 12:26:00 +04:00
} else {
2013-12-05 19:21:12 +04:00
2013-03-01 21:59:59 +04:00
Decl * decl = 0 ;
const TypedefType * typedeftype =
2013-03-01 22:12:48 +04:00
dyn_cast_or_null < TypedefType > ( & ( * desugared ) ) ;
2012-12-11 12:26:00 +04:00
if ( typedeftype ) {
decl = typedeftype - > getDecl ( ) ;
} else {
// There are probably other cases ...
2013-03-01 21:59:59 +04:00
const TagType * tagdecltype = dyn_cast_or_null < TagType > ( & ( * desugared ) ) ;
2012-12-11 12:26:00 +04:00
if ( tagdecltype ) {
decl = tagdecltype - > getDecl ( ) ;
} else {
2013-03-01 21:59:59 +04:00
decl = desugared - > getAsCXXRecordDecl ( ) ;
2012-12-11 12:26:00 +04:00
}
}
if ( decl ) {
2013-03-01 21:59:59 +04:00
NamedDecl * outer
= dyn_cast_or_null < NamedDecl > ( decl - > getDeclContext ( ) ) ;
2012-12-11 12:26:00 +04:00
NamespaceDecl * outer_ns
2013-03-01 21:59:59 +04:00
= dyn_cast_or_null < NamespaceDecl > ( decl - > getDeclContext ( ) ) ;
2012-12-11 12:26:00 +04:00
if ( outer
& & ! ( outer_ns & & outer_ns - > isAnonymousNamespace ( ) )
& & outer - > getName ( ) . size ( ) ) {
2013-03-01 21:59:59 +04:00
outer_scope = SelectPrefix ( Ctx , decl - > getDeclContext ( ) ,
2013-09-03 08:44:24 +04:00
outer_scope , TypeConfig ) ;
2013-03-01 21:59:59 +04:00
} else {
outer_scope = 0 ;
2012-12-11 12:26:00 +04:00
}
2013-03-01 21:59:59 +04:00
} else if ( outer_scope ) {
2013-09-03 08:44:24 +04:00
outer_scope = GetPartiallyDesugaredNNS ( Ctx , outer_scope , TypeConfig ) ;
2013-03-01 21:59:59 +04:00
}
2012-09-05 13:37:39 +04:00
}
return NestedNameSpecifier : : Create ( Ctx , outer_scope ,
false /* template keyword wanted */ ,
desugared . getTypePtr ( ) ) ;
2013-03-01 21:59:59 +04:00
} else {
return GetFullyQualifiedNameSpecifier ( Ctx , scope ) ;
2012-09-05 13:37:39 +04:00
}
}
2013-12-13 02:03:43 +04:00
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 ;
}
2013-09-03 09:28:58 +04:00
static bool IsCompilerDetails ( const TagType * tagTy )
2013-02-14 21:23:47 +04:00
{
// Return true if the TagType is a 'details' of the std implementation.
2013-12-13 01:00:52 +04:00
// (For now it means declared in __gnu_cxx or starting with underscore).
2013-12-05 19:21:12 +04:00
2013-02-14 21:23:47 +04:00
const TagDecl * decl = tagTy - > getDecl ( ) ;
assert ( decl ) ;
2013-09-03 09:28:58 +04:00
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.
2013-02-14 21:23:47 +04:00
const NamedDecl * outer = dyn_cast_or_null < NamedDecl > ( decl - > getDeclContext ( ) ) ;
while ( outer & & outer - > getName ( ) . size ( ) ) {
2013-09-03 09:28:58 +04:00
if ( outer - > getName ( ) . compare ( " __gnu_cxx " ) = = 0 ) {
2013-02-14 21:23:47 +04:00
return true ;
}
outer = dyn_cast_or_null < NamedDecl > ( outer - > getDeclContext ( ) ) ;
}
return false ;
}
2013-12-05 19:21:12 +04:00
2013-02-14 21:23:47 +04:00
static bool ShouldKeepTypedef ( QualType QT ,
2012-09-23 01:30:24 +04:00
const llvm : : SmallSet < const Type * , 4 > & TypesToSkip )
{
// Return true, if we should keep this typedef rather than desugaring it.
2013-09-03 08:44:24 +04:00
if ( 0 ! = TypesToSkip . count ( QT . getTypePtr ( ) ) )
2012-09-23 01:30:24 +04:00
return true ;
2013-12-05 19:21:12 +04:00
const TypedefType * typedeftype =
2013-03-01 22:12:48 +04:00
dyn_cast_or_null < TypedefType > ( QT . getTypePtr ( ) ) ;
2012-09-23 01:30:24 +04:00
const TypedefNameDecl * decl = typedeftype ? typedeftype - > getDecl ( ) : 0 ;
if ( decl ) {
2013-12-05 19:21:12 +04:00
const NamedDecl * outer
2013-03-01 22:12:48 +04:00
= dyn_cast_or_null < NamedDecl > ( decl - > getDeclContext ( ) ) ;
2013-02-14 21:23:47 +04:00
// 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.
2013-12-05 19:21:12 +04:00
2013-02-14 21:23:47 +04:00
while ( outer & & outer - > getName ( ) . size ( ) ) {
// NOTE: Net is being cast too widely, replace by a lookup.
// or by using Sema::getStdNamespace
2014-01-20 09:21:53 +04:00
if ( outer - > getDeclContext ( ) - > isTranslationUnit ( )
& & outer - > getName ( ) . compare ( " std " ) = = 0 ) {
2013-02-14 21:23:47 +04:00
// And now let's check that the target is also within std.
2013-12-05 19:21:12 +04:00
const Type * underlyingType
= decl - > getUnderlyingType ( ) . getSplitDesugaredType ( ) . Ty ;
2013-02-14 21:23:47 +04:00
const ElaboratedType * elTy = dyn_cast < ElaboratedType > ( underlyingType ) ;
if ( elTy ) {
underlyingType = elTy - > getNamedType ( ) . getTypePtr ( ) ;
}
const TagType * tagTy = underlyingType - > getAs < TagType > ( ) ;
if ( tagTy ) {
2013-09-03 09:28:58 +04:00
bool details = IsCompilerDetails ( tagTy ) ;
2013-02-14 21:23:47 +04:00
if ( details ) return true ;
2013-01-04 21:26:48 +04:00
}
}
2013-02-14 21:23:47 +04:00
outer = dyn_cast_or_null < NamedDecl > ( outer - > getDeclContext ( ) ) ;
2012-09-23 01:30:24 +04:00
}
}
return false ;
}
2013-12-13 02:03:14 +04:00
static bool SingleStepPartiallyDesugarTypeImpl ( QualType & QT )
2012-11-30 01:40:44 +04:00
{
// 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 : {
2013-02-08 02:56:10 +04:00
const SubstTemplateTypeParmType * Ty =
llvm : : cast < SubstTemplateTypeParmType > ( QTy ) ;
QT = Ty - > desugar ( ) ;
return true ;
2012-11-30 01:40:44 +04:00
}
case Type : : Elaborated : {
2013-03-01 05:33:38 +04:00
const ElaboratedType * Ty = llvm : : cast < ElaboratedType > ( QTy ) ;
QT = Ty - > desugar ( ) ;
return true ;
2012-11-30 01:40:44 +04:00
}
//
// 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 ;
}
2012-12-02 00:37:09 +04:00
bool Transform : : SingleStepPartiallyDesugarType ( QualType & QT ,
const ASTContext & Context ) {
2013-12-05 19:21:12 +04:00
Qualifiers quals = QT . getQualifiers ( ) ;
2012-12-02 00:37:09 +04:00
bool desugared = SingleStepPartiallyDesugarTypeImpl ( QT ) ;
if ( desugared ) {
// If the types has been desugared it also lost its qualifiers.
QT = Context . getQualifiedType ( QT , quals ) ;
}
return desugared ;
}
2013-12-05 19:21:12 +04:00
static QualType GetPartiallyDesugaredTypeImpl ( const ASTContext & Ctx ,
2013-09-03 08:44:24 +04:00
QualType QT , const Transform : : Config & TypeConfig ,
2013-12-05 19:21:12 +04:00
bool fullyQualifyType , bool fullyQualifyTmpltArg )
2012-11-30 01:40:44 +04:00
{
2013-12-02 12:49:39 +04:00
if ( QT . isNull ( ) )
return QT ;
2012-11-30 01:40:44 +04:00
// If there are no constraints, then use the standard desugaring.
2013-09-03 08:44:24 +04:00
if ( TypeConfig . empty ( ) & & ! fullyQualifyType & & ! fullyQualifyTmpltArg )
2012-09-05 13:37:39 +04:00
return QT . getDesugaredType ( Ctx ) ;
// In case of Int_t* we need to strip the pointer first, desugar and attach
// the pointer once again.
2012-10-19 17:24:46 +04:00
if ( isa < PointerType > ( QT . getTypePtr ( ) ) ) {
2012-09-05 13:37:39 +04:00
// Get the qualifiers.
2013-12-05 19:21:12 +04:00
Qualifiers quals = QT . getQualifiers ( ) ;
QT = GetPartiallyDesugaredTypeImpl ( Ctx , QT - > getPointeeType ( ) , TypeConfig ,
2013-08-29 02:02:57 +04:00
fullyQualifyType , fullyQualifyTmpltArg ) ;
2012-09-05 13:37:39 +04:00
QT = Ctx . getPointerType ( QT ) ;
// Add back the qualifiers.
QT = Ctx . getQualifiedType ( QT , quals ) ;
2012-09-23 01:30:24 +04:00
return QT ;
2012-09-05 13:37:39 +04:00
}
2013-12-05 19:21:12 +04:00
2013-02-12 22:38:58 +04:00
while ( isa < SubstTemplateTypeParmType > ( QT . getTypePtr ( ) ) ) {
// Get the qualifiers.
2013-12-05 19:21:12 +04:00
Qualifiers quals = QT . getQualifiers ( ) ;
2013-02-12 22:38:58 +04:00
2013-02-08 02:56:10 +04:00
QT = dyn_cast < SubstTemplateTypeParmType > ( QT . getTypePtr ( ) ) - > desugar ( ) ;
2013-02-12 22:38:58 +04:00
// Add back the qualifiers.
QT = Ctx . getQualifiedType ( QT , quals ) ;
2013-02-08 02:56:10 +04:00
}
2012-09-05 13:37:39 +04:00
// In case of Int_t& we need to strip the pointer first, desugar and attach
// the pointer once again.
2012-10-19 17:24:46 +04:00
if ( isa < ReferenceType > ( QT . getTypePtr ( ) ) ) {
2012-09-05 13:37:39 +04:00
// Get the qualifiers.
bool isLValueRefTy = isa < LValueReferenceType > ( QT . getTypePtr ( ) ) ;
Qualifiers quals = QT . getQualifiers ( ) ;
2013-12-05 19:21:12 +04:00
QT = GetPartiallyDesugaredTypeImpl ( Ctx , QT - > getPointeeType ( ) , TypeConfig ,
2013-08-29 02:02:57 +04:00
fullyQualifyType , fullyQualifyTmpltArg ) ;
2012-11-30 01:40:44 +04:00
// Add the r- or l-value reference type back to the desugared one.
2012-09-05 13:37:39 +04:00
if ( isLValueRefTy )
QT = Ctx . getLValueReferenceType ( QT ) ;
else
QT = Ctx . getRValueReferenceType ( QT ) ;
// Add back the qualifiers.
QT = Ctx . getQualifiedType ( QT , quals ) ;
2012-09-23 01:30:24 +04:00
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.
2013-12-05 19:21:12 +04:00
// for example for std::vector<int>::iterator, we work on
2012-09-23 01:30:24 +04:00
// 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 ;
2013-03-01 22:06:58 +04:00
Qualifiers prefix_qualifiers ;
2013-12-05 19:21:12 +04:00
const ElaboratedType * etype_input
2013-03-01 22:12:48 +04:00
= dyn_cast < ElaboratedType > ( QT . getTypePtr ( ) ) ;
2012-09-23 01:30:24 +04:00
if ( etype_input ) {
2012-12-01 22:02:54 +04:00
// 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.
2012-09-23 01:30:24 +04:00
original_prefix = etype_input - > getQualifier ( ) ;
2012-10-26 23:51:56 +04:00
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).
2013-08-29 02:02:57 +04:00
fullyQualifyType = true ;
2012-10-26 23:51:56 +04:00
prefix_qualifiers = QT . getLocalQualifiers ( ) ;
QT = QualType ( etype_input - > getNamedType ( ) . getTypePtr ( ) , 0 ) ;
} else {
original_prefix = 0 ;
}
}
2012-09-05 13:37:39 +04:00
}
2012-11-30 01:40:44 +04:00
// Desugar QT until we cannot desugar any more, or
// we hit one of the special typedefs.
while ( 1 ) {
if ( llvm : : isa < TypedefType > ( QT . getTypePtr ( ) ) & &
2013-09-03 08:44:24 +04:00
ShouldKeepTypedef ( QT , TypeConfig . m_toSkip ) ) {
2013-08-29 02:02:57 +04:00
if ( ! fullyQualifyType & & ! fullyQualifyTmpltArg ) {
2012-11-30 01:40:44 +04:00
return QT ;
}
2012-11-28 21:18:16 +04:00
// We might have stripped the namespace/scope part,
2012-11-30 01:40:44 +04:00
// so we must go on to add it back.
2012-11-28 21:18:16 +04:00
break ;
2012-11-30 01:40:44 +04:00
}
2013-08-29 02:02:57 +04:00
bool wasDesugared = Transform : : SingleStepPartiallyDesugarType ( QT , Ctx ) ;
2013-09-03 08:44:24 +04:00
// 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 ( ) ;
2013-12-04 19:39:43 +04:00
QT = QualType ( iter - > second , 0 ) ;
2013-09-03 08:44:24 +04:00
QT = Ctx . getQualifiedType ( QT , quals ) ;
break ;
}
2012-11-30 01:40:44 +04:00
if ( ! wasDesugared ) {
// No more work to do, stop now.
break ;
}
2012-11-28 20:14:29 +04:00
}
2012-09-23 01:30:24 +04:00
2012-10-19 17:24:46 +04:00
// If we have a reference or pointer we still need to
// desugar what they point to.
2013-03-01 21:59:59 +04:00
if ( isa < PointerType > ( QT . getTypePtr ( ) ) | |
2012-10-19 17:24:46 +04:00
isa < ReferenceType > ( QT . getTypePtr ( ) ) ) {
2013-12-05 19:21:12 +04:00
return GetPartiallyDesugaredTypeImpl ( Ctx , QT , TypeConfig ,
2013-08-29 02:02:57 +04:00
fullyQualifyType ,
fullyQualifyTmpltArg ) ;
2012-10-19 17:24:46 +04:00
}
2012-09-05 13:37:39 +04:00
NestedNameSpecifier * prefix = 0 ;
2013-12-05 19:21:12 +04:00
const ElaboratedType * etype
2013-03-01 22:12:48 +04:00
= dyn_cast < ElaboratedType > ( QT . getTypePtr ( ) ) ;
2012-09-05 13:37:39 +04:00
if ( etype ) {
2012-12-11 12:26:00 +04:00
2013-09-03 08:44:24 +04:00
prefix = SelectPrefix ( Ctx , etype , original_prefix , TypeConfig ) ;
2013-12-05 19:21:12 +04:00
2012-09-25 23:35:24 +04:00
prefix_qualifiers . addQualifiers ( QT . getLocalQualifiers ( ) ) ;
QT = QualType ( etype - > getNamedType ( ) . getTypePtr ( ) , 0 ) ;
2013-12-05 19:21:12 +04:00
2013-08-29 02:02:57 +04:00
} else if ( fullyQualifyType ) {
2012-09-05 13:37:39 +04:00
// 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 ...
2012-09-23 01:30:24 +04:00
Decl * decl = 0 ;
2013-12-05 19:21:12 +04:00
const TypedefType * typedeftype =
2013-03-01 22:12:48 +04:00
dyn_cast_or_null < TypedefType > ( QT . getTypePtr ( ) ) ;
2012-09-23 01:30:24 +04:00
if ( typedeftype ) {
decl = typedeftype - > getDecl ( ) ;
} else {
// There are probably other cases ...
2013-12-05 19:21:12 +04:00
const TagType * tagdecltype = dyn_cast_or_null < TagType > ( QT . getTypePtr ( ) ) ;
2012-09-23 01:30:24 +04:00
if ( tagdecltype ) {
decl = tagdecltype - > getDecl ( ) ;
} else {
decl = QT - > getAsCXXRecordDecl ( ) ;
}
}
if ( decl ) {
2013-12-05 19:21:12 +04:00
NamedDecl * outer
2013-03-01 22:12:48 +04:00
= dyn_cast_or_null < NamedDecl > ( decl - > getDeclContext ( ) ) ;
2012-10-26 23:51:56 +04:00
NamespaceDecl * outer_ns
2013-03-01 22:12:48 +04:00
= dyn_cast_or_null < NamespaceDecl > ( decl - > getDeclContext ( ) ) ;
2012-10-26 23:51:56 +04:00
if ( outer
& & ! ( outer_ns & & outer_ns - > isAnonymousNamespace ( ) )
& & outer - > getName ( ) . size ( ) ) {
2012-09-26 12:01:21 +04:00
if ( original_prefix ) {
2013-03-01 22:06:58 +04:00
const Type * oldtype = original_prefix - > getAsType ( ) ;
2012-09-26 12:01:21 +04:00
if ( oldtype ) {
if ( oldtype - > getAsCXXRecordDecl ( ) = = outer ) {
// Same type, use the original spelling
2013-12-05 19:21:12 +04:00
prefix
= GetPartiallyDesugaredNNS ( Ctx , original_prefix , TypeConfig ) ;
2012-09-26 12:01:21 +04:00
outer = 0 ; // Cancel the later creation.
}
} else {
const NamespaceDecl * old_ns = original_prefix - > getAsNamespace ( ) ;
if ( old_ns ) {
old_ns = old_ns - > getCanonicalDecl ( ) ;
}
2013-12-05 19:21:12 +04:00
else if ( NamespaceAliasDecl * alias =
2012-09-26 12:01:21 +04:00
original_prefix - > getAsNamespaceAlias ( ) )
{
old_ns = alias - > getNamespace ( ) - > getCanonicalDecl ( ) ;
}
2013-03-01 22:12:48 +04:00
const NamespaceDecl * new_ns = dyn_cast < NamespaceDecl > ( outer ) ;
2012-09-26 12:01:21 +04:00
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.
2013-03-01 21:59:59 +04:00
prefix = GetFullyQualifiedNameSpecifier ( Ctx , original_prefix ) ;
2012-09-26 12:01:21 +04:00
outer = 0 ; // Cancel the later creation.
}
2012-09-23 01:30:24 +04:00
}
2012-09-26 12:01:21 +04:00
} else { // if (!original_prefix)
2013-12-05 19:21:12 +04:00
// move qualifiers on the outer type (avoid 'std::const string'!)
2012-09-26 12:01:21 +04:00
prefix_qualifiers = QT . getLocalQualifiers ( ) ;
QT = QualType ( QT . getTypePtr ( ) , 0 ) ;
2012-09-23 01:30:24 +04:00
}
2012-09-26 12:01:21 +04:00
if ( outer ) {
if ( decl - > getDeclContext ( ) - > isNamespace ( ) ) {
2013-12-04 19:39:43 +04:00
prefix = TypeName : : CreateNestedNameSpecifier ( Ctx ,
2013-03-01 21:59:59 +04:00
dyn_cast < NamespaceDecl > ( outer ) ) ;
2012-09-26 12:01:21 +04:00
} else {
2012-11-21 03:19:48 +04:00
// We should only create the nested name specifier
// if the outer scope is really a TagDecl.
// It could also be a CXXMethod for example.
2013-03-01 22:12:48 +04:00
TagDecl * tdecl = dyn_cast < TagDecl > ( outer ) ;
2012-12-01 22:02:54 +04:00
if ( tdecl ) {
2013-12-04 21:26:23 +04:00
prefix = TypeName : : CreateNestedNameSpecifier ( Ctx , tdecl ,
false /*FullyQualified*/ ) ;
2013-09-03 08:44:24 +04:00
prefix = GetPartiallyDesugaredNNS ( Ctx , prefix , TypeConfig ) ;
2012-12-01 22:02:54 +04:00
}
2012-09-26 12:01:21 +04:00
}
2012-09-23 01:30:24 +04:00
}
}
2012-09-05 13:37:39 +04:00
}
}
2013-12-05 19:21:12 +04:00
// In case of template specializations iterate over the arguments and
2012-09-05 13:37:39 +04:00
// desugar them as well.
2013-12-05 19:21:12 +04:00
if ( const TemplateSpecializationType * TST
2012-09-05 13:37:39 +04:00
= dyn_cast < const TemplateSpecializationType > ( QT . getTypePtr ( ) ) ) {
2013-12-05 19:21:12 +04:00
2012-09-05 13:37:39 +04:00
bool mightHaveChanged = false ;
llvm : : SmallVector < TemplateArgument , 4 > desArgs ;
2013-10-30 16:23:58 +04:00
unsigned int argi = 0 ;
2012-09-05 13:37:39 +04:00
for ( TemplateSpecializationType : : iterator I = TST - > begin ( ) , E = TST - > end ( ) ;
2013-10-30 16:23:58 +04:00
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 ;
}
}
}
2012-11-17 11:36:22 +04:00
if ( I - > getKind ( ) ! = TemplateArgument : : Type ) {
2012-09-28 16:28:14 +04:00
desArgs . push_back ( * I ) ;
continue ;
2012-09-05 13:37:39 +04:00
}
2012-09-28 16:28:14 +04:00
QualType SubTy = I - > getAsType ( ) ;
2012-09-05 13:37:39 +04:00
// Check if the type needs more desugaring and recurse.
2013-12-05 19:21:12 +04:00
if ( isa < TypedefType > ( SubTy )
2012-09-05 13:37:39 +04:00
| | isa < TemplateSpecializationType > ( SubTy )
2012-09-25 23:35:24 +04:00
| | isa < ElaboratedType > ( SubTy )
2013-08-29 02:02:57 +04:00
| | fullyQualifyTmpltArg ) {
2012-09-05 13:37:39 +04:00
mightHaveChanged = true ;
2013-12-05 19:21:12 +04:00
QualType PDQT
= GetPartiallyDesugaredTypeImpl ( Ctx , SubTy , TypeConfig ,
fullyQualifyType ,
fullyQualifyTmpltArg ) ;
desArgs . push_back ( TemplateArgument ( PDQT ) ) ;
} else {
2012-09-05 13:37:39 +04:00
desArgs . push_back ( * I ) ;
2013-12-05 19:21:12 +04:00
}
2012-09-05 13:37:39 +04:00
}
2013-12-05 19:21:12 +04:00
2012-09-05 13:37:39 +04:00
// If desugaring happened allocate new type in the AST.
if ( mightHaveChanged ) {
2012-09-26 12:01:21 +04:00
Qualifiers qualifiers = QT . getLocalQualifiers ( ) ;
2013-12-05 19:21:12 +04:00
QT = Ctx . getTemplateSpecializationType ( TST - > getTemplateName ( ) ,
2012-09-19 16:39:06 +04:00
desArgs . data ( ) ,
desArgs . size ( ) ,
TST - > getCanonicalTypeInternal ( ) ) ;
2012-09-26 12:01:21 +04:00
QT = Ctx . getQualifiedType ( QT , qualifiers ) ;
2012-09-05 13:37:39 +04:00
}
2013-08-29 02:02:57 +04:00
} else if ( fullyQualifyTmpltArg ) {
2013-12-05 19:21:12 +04:00
2013-02-08 02:56:10 +04:00
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.
2013-12-05 19:21:12 +04:00
2013-02-08 02:56:10 +04:00
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 ) {
2013-10-30 16:23:58 +04:00
2013-02-08 02:56:10 +04:00
if ( templateArgs [ I ] . getKind ( ) ! = TemplateArgument : : Type ) {
desArgs . push_back ( templateArgs [ I ] ) ;
continue ;
}
2013-12-05 19:21:12 +04:00
2013-02-08 02:56:10 +04:00
QualType SubTy = templateArgs [ I ] . getAsType ( ) ;
// Check if the type needs more desugaring and recurse.
if ( isa < TypedefType > ( SubTy )
| | isa < TemplateSpecializationType > ( SubTy )
| | isa < ElaboratedType > ( SubTy )
2013-08-29 02:02:57 +04:00
| | fullyQualifyTmpltArg ) {
2013-02-08 02:56:10 +04:00
mightHaveChanged = true ;
2013-12-05 19:21:12 +04:00
QualType PDQT
= GetPartiallyDesugaredTypeImpl ( Ctx , SubTy , TypeConfig ,
/*fullyQualifyType=*/ true ,
/*fullyQualifyTmpltArg=*/ true ) ;
desArgs . push_back ( TemplateArgument ( PDQT ) ) ;
} else {
2013-02-08 02:56:10 +04:00
desArgs . push_back ( templateArgs [ I ] ) ;
2013-12-05 19:21:12 +04:00
}
2013-02-08 02:56:10 +04:00
}
2013-12-05 19:21:12 +04:00
2013-02-08 02:56:10 +04:00
// If desugaring happened allocate new type in the AST.
if ( mightHaveChanged ) {
Qualifiers qualifiers = QT . getLocalQualifiers ( ) ;
2013-12-05 19:21:12 +04:00
TemplateName TN ( TSTdecl - > getSpecializedTemplate ( ) ) ;
QT = Ctx . getTemplateSpecializationType ( TN , desArgs . data ( ) ,
2013-02-08 02:56:10 +04:00
desArgs . size ( ) ,
2013-10-30 16:23:58 +04:00
TSTRecord - > getCanonicalTypeInternal ( ) ) ;
2013-02-08 02:56:10 +04:00
QT = Ctx . getQualifiedType ( QT , qualifiers ) ;
}
}
}
2012-09-05 13:37:39 +04:00
}
if ( prefix ) {
2012-12-01 22:02:54 +04:00
// We intentionally always use ETK_None, we never want
// the keyword (humm ... what about anonymous types?)
2012-09-25 23:35:24 +04:00
QT = Ctx . getElaboratedType ( ETK_None , prefix , QT ) ;
2012-09-26 12:01:21 +04:00
QT = Ctx . getQualifiedType ( QT , prefix_qualifiers ) ;
2013-11-06 20:04:33 +04:00
} else if ( original_prefix ) {
QT = Ctx . getQualifiedType ( QT , prefix_qualifiers ) ;
2012-09-05 13:37:39 +04:00
}
2013-12-05 19:21:12 +04:00
return QT ;
2012-09-05 13:37:39 +04:00
}
2013-12-05 19:21:12 +04:00
QualType Transform : : GetPartiallyDesugaredType ( const ASTContext & Ctx ,
2013-09-03 08:44:24 +04:00
QualType QT , const Transform : : Config & TypeConfig ,
2013-08-29 02:02:57 +04:00
bool fullyQualify /*=true*/ )
{
2013-09-03 08:44:24 +04:00
return GetPartiallyDesugaredTypeImpl ( Ctx , QT , TypeConfig ,
2013-08-29 02:02:57 +04:00
/*qualifyType*/ fullyQualify ,
/*qualifyTmpltArg*/ fullyQualify ) ;
}
2013-12-05 19:21:12 +04:00
2012-09-05 13:37:39 +04:00
NamespaceDecl * Lookup : : Namespace ( Sema * S , const char * Name ,
2012-11-20 23:13:06 +04:00
const DeclContext * Within ) {
2012-09-05 13:37:39 +04:00
DeclarationName DName = & S - > Context . Idents . get ( Name ) ;
LookupResult R ( * S , DName , SourceLocation ( ) ,
Sema : : LookupNestedNameSpecifierName ) ;
2013-12-02 17:15:19 +04:00
R . suppressDiagnostics ( ) ;
2012-09-05 13:37:39 +04:00
if ( ! Within )
S - > LookupName ( R , S - > TUScope ) ;
else
2012-11-20 23:13:06 +04:00
S - > LookupQualifiedName ( R , const_cast < DeclContext * > ( Within ) ) ;
2012-09-05 13:37:39 +04:00
if ( R . empty ( ) )
return 0 ;
R . resolveKind ( ) ;
return dyn_cast < NamespaceDecl > ( R . getFoundDecl ( ) ) ;
}
2012-11-20 23:13:06 +04:00
NamedDecl * Lookup : : Named ( Sema * S , const char * Name ,
const DeclContext * Within ) {
2012-09-05 13:37:39 +04:00
DeclarationName DName = & S - > Context . Idents . get ( Name ) ;
2012-10-09 13:41:26 +04:00
return Lookup : : Named ( S , DName , Within ) ;
}
2012-09-05 13:37:39 +04:00
2013-12-05 19:21:12 +04:00
NamedDecl * Lookup : : Named ( Sema * S , const DeclarationName & Name ,
2012-11-20 23:13:06 +04:00
const DeclContext * Within ) {
2012-10-09 13:41:26 +04:00
LookupResult R ( * S , Name , SourceLocation ( ) , Sema : : LookupOrdinaryName ,
2012-09-05 13:37:39 +04:00
Sema : : ForRedeclaration ) ;
2013-12-02 17:15:19 +04:00
R . suppressDiagnostics ( ) ;
2012-09-05 13:37:39 +04:00
if ( ! Within )
S - > LookupName ( R , S - > TUScope ) ;
else
2012-11-20 23:13:06 +04:00
S - > LookupQualifiedName ( R , const_cast < DeclContext * > ( Within ) ) ;
2012-09-05 13:37:39 +04:00
if ( R . empty ( ) )
return 0 ;
R . resolveKind ( ) ;
return R . getFoundDecl ( ) ;
}
2013-12-04 19:39:43 +04:00
static NestedNameSpecifier *
CreateNestedNameSpecifierForScopeOf ( const ASTContext & Ctx ,
2013-12-04 21:26:23 +04:00
const Type * TypePtr ,
bool FullyQualified )
2013-12-04 19:39:43 +04:00
{
// 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 ( ) ) ) {
2013-12-05 19:21:12 +04:00
2013-12-04 19:39:43 +04:00
if ( CXXRecordDecl * cxxdecl
= llvm : : dyn_cast < CXXRecordDecl > ( decl - > getDeclContext ( ) ) ) {
2013-12-05 19:21:12 +04:00
2013-12-04 19:39:43 +04:00
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 ) ;
2014-01-20 17:37:13 +04:00
} else if ( const TagDecl * TD = llvm : : dyn_cast < TagDecl > ( outer ) ) {
return TypeName : : CreateNestedNameSpecifier ( Ctx , TD , FullyQualified ) ;
2013-12-04 19:39:43 +04:00
}
}
return 0 ;
}
NestedNameSpecifier *
TypeName : : CreateNestedNameSpecifier ( const ASTContext & Ctx ,
const NamespaceDecl * Namesp ) {
2014-01-12 19:59:12 +04:00
while ( Namesp & & Namesp - > isInline ( ) ) {
// Ignore inline namespace;
Namesp = dyn_cast_or_null < NamespaceDecl > ( Namesp - > getDeclContext ( ) ) ;
}
if ( ! Namesp ) return 0 ;
2013-12-04 21:26:23 +04:00
bool FullyQualified = true ; // doesn't matter, DeclContexts are namespaces
return NestedNameSpecifier : : Create ( Ctx , CreateOuterNNS ( Ctx , Namesp ,
FullyQualified ) ,
Namesp ) ;
2013-12-04 19:39:43 +04:00
}
2013-12-05 19:21:12 +04:00
2014-01-06 21:04:47 +04:00
NestedNameSpecifier *
TypeName : : CreateNestedNameSpecifier ( const ASTContext & Ctx ,
const TypedefNameDecl * TD ,
bool FullyQualify ) {
return NestedNameSpecifier : : Create ( Ctx , CreateOuterNNS ( Ctx , TD ,
FullyQualify ) ,
true /*Template*/ ,
TD - > getTypeForDecl ( ) ) ;
}
2013-12-04 19:39:43 +04:00
NestedNameSpecifier *
TypeName : : CreateNestedNameSpecifier ( const ASTContext & Ctx ,
2013-12-04 21:26:23 +04:00
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 ) ,
2013-12-04 19:39:43 +04:00
false /* template keyword wanted */ ,
2013-12-04 21:26:23 +04:00
Ty ) ;
2013-12-04 19:39:43 +04:00
}
2013-12-05 19:21:12 +04:00
2013-12-04 19:39:43 +04:00
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 ( ) ;
2013-12-21 18:06:08 +04:00
if ( prefix ! = NestedNameSpecifier : : GlobalSpecifier ( Ctx )
& & ! ( ns & & ns - > isAnonymousNamespace ( ) ) ) {
2013-12-04 19:39:43 +04:00
prefix_qualifiers = QT . getLocalQualifiers ( ) ;
2013-12-20 18:16:50 +04:00
prefix = GetFullyQualifiedNameSpecifier ( Ctx , prefix ) ;
2013-12-04 19:39:43 +04:00
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.
2013-12-04 21:26:23 +04:00
prefix = CreateNestedNameSpecifierForScopeOf ( Ctx , QT . getTypePtr ( ) ,
true /*FullyQualified*/ ) ;
2013-12-04 19:39:43 +04:00
// 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 ) ;
}
2013-12-05 19:21:12 +04:00
return QT ;
2013-12-04 19:39:43 +04:00
}
2013-12-05 19:21:12 +04:00
std : : string TypeName : : GetFullyQualifiedName ( QualType QT ,
const ASTContext & Ctx ) {
2013-12-04 19:39:43 +04:00
QualType FQQT = GetFullyQualifiedType ( QT , Ctx ) ;
2013-12-05 19:21:12 +04:00
PrintingPolicy Policy ( Ctx . getPrintingPolicy ( ) ) ;
2013-12-04 19:39:43 +04:00
Policy . SuppressScope = false ;
Policy . AnonymousTagLocations = false ;
return FQQT . getAsString ( Policy ) ;
}
2012-09-05 13:37:39 +04:00
} // end namespace utils
} // end namespace cling