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
//------------------------------------------------------------------------------
2014-05-21 19:44:26 +04:00
# include "cling/Interpreter/Value.h"
2012-09-05 13:37:39 +04:00
# include "cling/Interpreter/CValuePrinter.h"
2014-05-16 19:40:27 +04:00
# include "cling/Interpreter/Interpreter.h"
2017-05-05 18:33:52 +03:00
# include "cling/Interpreter/LookupHelper.h"
2014-05-16 19:40:27 +04:00
# include "cling/Interpreter/Transaction.h"
2012-09-05 13:37:39 +04:00
# include "cling/Interpreter/Value.h"
2014-05-16 19:40:27 +04:00
# include "cling/Utils/AST.h"
2016-09-10 22:04:39 +03:00
# include "cling/Utils/Output.h"
2015-12-08 15:26:13 +03:00
# include "cling/Utils/Validation.h"
2012-09-05 13:37:39 +04:00
# include "clang/AST/ASTContext.h"
# include "clang/AST/Decl.h"
# include "clang/AST/DeclCXX.h"
# include "clang/AST/Expr.h"
# include "clang/AST/Type.h"
2014-05-28 20:01:48 +04:00
# include "clang/Frontend/CompilerInstance.h"
2012-09-05 13:37:39 +04:00
2016-09-10 22:04:39 +03:00
# include "llvm/Support/Format.h"
2013-02-22 19:59:54 +04:00
# include "llvm/ExecutionEngine/GenericValue.h"
2012-09-05 13:37:39 +04:00
2016-10-06 23:31:26 +03:00
# include <locale>
2012-09-05 13:37:39 +04:00
# include <string>
2015-08-17 14:04:00 +03:00
2016-12-20 22:15:54 +03:00
// GCC 4.x doesn't have the proper UTF-8 conversion routines. So use the
// LLVM conversion routines (which require a buffer 4x string length).
# if !defined(__GLIBCXX__) || (__GNUC__ >= 5)
# include <codecvt>
# else
# define LLVM_UTF8
# include "llvm/Support/ConvertUTF.h"
# endif
2012-11-12 14:27:13 +04:00
using namespace cling ;
2012-09-05 13:37:39 +04:00
// Implements the CValuePrinter interface.
2015-08-20 17:33:36 +03:00
extern " C " void cling_PrintValue ( void * /*cling::Value**/ V ) {
2014-05-19 18:12:41 +04:00
//Value* value = (Value*)V;
2012-09-05 13:37:39 +04:00
2015-08-18 18:48:45 +03:00
//std::string typeStr = printTypeInternal(*value);
//std::string valueStr = printValueInternal(*value);
2012-09-05 13:37:39 +04:00
}
2016-10-06 01:19:34 +03:00
// Exported for RuntimePrintValue.h
namespace cling {
namespace valuePrinterInternal {
2016-12-01 19:03:10 +03:00
extern const char * const kEmptyCollection = " {} " ;
2016-10-06 01:19:34 +03:00
}
}
2016-10-06 04:30:26 +03:00
namespace {
2016-10-06 19:11:23 +03:00
const static char
* const kNullPtrStr = " nullptr " ,
* const kNullPtrTStr = " nullptr_t " ,
* const kTrueStr = " true " ,
2016-10-07 04:07:00 +03:00
* const kFalseStr = " false " ,
* const kInvalidAddr = " <invalid memory address> " ;
2016-10-06 19:11:23 +03:00
2016-10-06 23:41:33 +03:00
static std : : string enclose ( std : : string Mid , const char * Begin ,
const char * End , size_t Hint = 0 ) {
Mid . reserve ( Mid . size ( ) + Hint ? Hint : ( : : strlen ( Begin ) + : : strlen ( End ) ) ) ;
Mid . insert ( 0 , Begin ) ;
Mid . append ( End ) ;
return Mid ;
2016-10-06 04:30:26 +03:00
}
static std : : string enclose ( const clang : : QualType & Ty , clang : : ASTContext & C ,
2016-10-06 23:41:33 +03:00
const char * Begin = " ( " , const char * End = " *) " ,
size_t Hint = 3 ) {
2016-10-06 04:30:26 +03:00
return enclose ( cling : : utils : : TypeName : : GetFullyQualifiedName ( Ty , C ) ,
2016-10-06 23:41:33 +03:00
Begin , End , Hint ) ;
2016-10-06 04:30:26 +03:00
}
2017-05-05 12:54:37 +03:00
static clang : : QualType
getElementTypeAndExtent ( const clang : : ConstantArrayType * CArrTy ,
std : : string & extent ) {
clang : : QualType ElementTy = CArrTy - > getElementType ( ) ;
const llvm : : APInt & APSize = CArrTy - > getSize ( ) ;
extent + = ' [ ' + std : : to_string ( APSize . getZExtValue ( ) ) + ' ] ' ;
if ( auto CArrElTy
= llvm : : dyn_cast < clang : : ConstantArrayType > ( ElementTy . getTypePtr ( ) ) ) {
return getElementTypeAndExtent ( CArrElTy , extent ) ;
}
return ElementTy ;
}
2015-08-20 17:33:36 +03:00
static std : : string getTypeString ( const Value & V ) {
2015-08-13 17:23:59 +03:00
clang : : ASTContext & C = V . getASTContext ( ) ;
clang : : QualType Ty = V . getType ( ) . getDesugaredType ( C ) . getNonReferenceType ( ) ;
2016-10-06 04:30:26 +03:00
if ( llvm : : dyn_cast < clang : : BuiltinType > ( Ty . getCanonicalType ( ) ) )
return enclose ( Ty , C ) ;
if ( Ty - > isPointerType ( ) ) {
// Print char pointers as strings.
if ( Ty - > getPointeeType ( ) - > isCharType ( ) )
return enclose ( Ty , C ) ;
// Fallback to void pointer for other pointers and print the address.
return " (const void**) " ;
2015-08-20 17:33:36 +03:00
}
2016-10-06 04:30:26 +03:00
if ( Ty - > isArrayType ( ) ) {
if ( Ty - > isConstantArrayType ( ) ) {
2017-05-05 12:54:37 +03:00
std : : string extent ( " (*) " ) ;
clang : : QualType InnermostElTy
= getElementTypeAndExtent ( C . getAsConstantArrayType ( Ty ) , extent ) ;
return enclose ( InnermostElTy , C , " ( " , ( extent + " ) * ( void * * ) " ).c_str()) ;
2015-08-13 17:23:59 +03:00
}
2016-10-06 04:30:26 +03:00
return " (void**) " ;
2015-08-20 17:33:36 +03:00
}
2016-10-06 04:30:26 +03:00
if ( Ty - > isObjCObjectPointerType ( ) )
return " (const void**) " ;
2015-08-13 17:23:59 +03:00
2016-10-06 04:30:26 +03:00
// In other cases, dereference the address of the object.
// If no overload or specific template matches,
// the general template will be used which only prints the address.
2016-10-06 23:41:33 +03:00
return enclose ( Ty , C , " *( " , " **) " , 5) ;
2015-08-13 17:23:59 +03:00
}
2016-01-28 22:39:36 +03:00
/// RAII object to disable and then re-enable access control in the LangOptions.
struct AccessCtrlRAII_t {
bool savedAccessControl ;
clang : : LangOptions & LangOpts ;
AccessCtrlRAII_t ( cling : : Interpreter & Interp ) :
LangOpts ( const_cast < clang : : LangOptions & > ( Interp . getCI ( ) - > getLangOpts ( ) ) ) {
savedAccessControl = LangOpts . AccessControl ;
2016-07-05 09:28:44 +03:00
LangOpts . AccessControl = false ;
2016-01-28 22:39:36 +03:00
}
~ AccessCtrlRAII_t ( ) {
LangOpts . AccessControl = savedAccessControl ;
}
} ;
# ifndef NDEBUG
/// Is typenam parsable?
bool canParseTypeName ( cling : : Interpreter & Interp , llvm : : StringRef typenam ) {
AccessCtrlRAII_t AccessCtrlRAII ( Interp ) ;
cling : : Interpreter : : CompilationResult Res
= Interp . declare ( " namespace { void* cling_printValue_Failure_Typename_check "
" = (void*) " + typenam . str ( ) + " nullptr; } " ) ;
if ( Res ! = cling : : Interpreter : : kSuccess )
2017-06-23 17:47:15 +03:00
cling : : errs ( ) < < " ERROR in cling::canParseTypeName(): "
2016-09-10 22:04:39 +03:00
" this typename cannot be spelled. \n " ;
2016-01-28 22:39:36 +03:00
return Res = = cling : : Interpreter : : kSuccess ;
}
# endif
2016-09-30 00:20:28 +03:00
static std : : string printDeclType ( const clang : : QualType & QT ,
const clang : : NamedDecl * D ) {
if ( ! QT . hasQualifiers ( ) )
return D - > getQualifiedNameAsString ( ) ;
return QT . getQualifiers ( ) . getAsString ( ) + " " + D - > getQualifiedNameAsString ( ) ;
}
2016-01-31 22:53:01 +03:00
static std : : string printQualType ( clang : : ASTContext & Ctx , clang : : QualType QT ) {
using namespace clang ;
2016-09-30 00:20:28 +03:00
const QualType QTNonRef = QT . getNonReferenceType ( ) ;
std : : string ValueTyStr ( " ( " ) ;
2016-10-14 04:21:36 +03:00
if ( const TagType * TTy = dyn_cast < TagType > ( QTNonRef ) )
2016-09-30 00:20:28 +03:00
ValueTyStr + = printDeclType ( QTNonRef , TTy - > getDecl ( ) ) ;
else if ( const RecordType * TRy = dyn_cast < RecordType > ( QTNonRef ) )
ValueTyStr + = printDeclType ( QTNonRef , TRy - > getDecl ( ) ) ;
2016-10-14 04:21:36 +03:00
else {
const QualType QTCanon = QTNonRef . getCanonicalType ( ) ;
if ( QTCanon - > isBuiltinType ( ) & & ! QTNonRef - > isFunctionPointerType ( )
& & ! QTNonRef - > isMemberPointerType ( ) ) {
ValueTyStr + = QTCanon . getAsString ( Ctx . getPrintingPolicy ( ) ) ;
}
else if ( const TypedefType * TDTy = dyn_cast < TypedefType > ( QTNonRef ) ) {
// FIXME: TemplateSpecializationType & SubstTemplateTypeParmType checks are
// predominately to get STL containers to print nicer and might be better
// handled in GetFullyQualifiedName.
//
// std::vector<Type>::iterator is a TemplateSpecializationType
// std::vector<Type>::value_type is a SubstTemplateTypeParmType
//
QualType SSDesugar = TDTy - > getLocallyUnqualifiedSingleStepDesugaredType ( ) ;
if ( dyn_cast < SubstTemplateTypeParmType > ( SSDesugar ) )
ValueTyStr + = utils : : TypeName : : GetFullyQualifiedName ( QTCanon , Ctx ) ;
else if ( dyn_cast < TemplateSpecializationType > ( SSDesugar ) )
ValueTyStr + = utils : : TypeName : : GetFullyQualifiedName ( QTNonRef , Ctx ) ;
else
ValueTyStr + = printDeclType ( QTNonRef , TDTy - > getDecl ( ) ) ;
}
else
ValueTyStr + = utils : : TypeName : : GetFullyQualifiedName ( QTNonRef , Ctx ) ;
}
2016-01-31 22:53:01 +03:00
if ( QT - > isReferenceType ( ) )
2016-09-30 00:20:28 +03:00
ValueTyStr + = " & " ;
return ValueTyStr + " ) " ;
2016-01-31 22:53:01 +03:00
}
2016-10-03 03:14:51 +03:00
static std : : string printAddress ( const void * Ptr , const char Prfx = 0 ) {
if ( ! Ptr )
2016-10-06 19:11:23 +03:00
return kNullPtrStr ;
2016-10-03 03:14:51 +03:00
2016-10-06 08:41:29 +03:00
cling : : smallstream Strm ;
2016-10-03 03:14:51 +03:00
if ( Prfx )
Strm < < Prfx ;
Strm < < Ptr ;
if ( ! utils : : isAddressValid ( Ptr ) )
2016-10-07 04:07:00 +03:00
Strm < < kInvalidAddr ;
2016-10-03 03:14:51 +03:00
return Strm . str ( ) ;
}
2015-08-17 14:17:11 +03:00
2017-06-06 22:22:10 +03:00
} // anonymous namespace
2012-09-05 13:37:39 +04:00
namespace cling {
2015-08-13 17:23:59 +03:00
2015-08-20 17:33:36 +03:00
// General fallback - prints the address
std : : string printValue ( const void * ptr ) {
2016-10-03 03:14:51 +03:00
return printAddress ( ptr , ' @ ' ) ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
// void pointer
std : : string printValue ( const void * * ptr ) {
2016-10-03 03:14:51 +03:00
return printAddress ( * ptr ) ;
2015-08-20 17:33:36 +03:00
}
2015-08-13 17:23:59 +03:00
// Bool
2015-08-20 17:33:36 +03:00
std : : string printValue ( const bool * val ) {
2016-10-06 19:11:23 +03:00
return * val ? kTrueStr : kFalseStr ;
2015-08-13 17:23:59 +03:00
}
// Chars
2016-10-07 04:07:00 +03:00
static std : : string printOneChar ( char Val ,
const std : : locale & Locale = std : : locale ( ) ) {
llvm : : SmallString < 128 > Buf ;
llvm : : raw_svector_ostream Strm ( Buf ) ;
2016-10-06 08:41:29 +03:00
Strm < < " ' " ;
2016-10-07 04:07:00 +03:00
if ( ! std : : isprint ( Val , Locale ) ) {
switch ( std : : isspace ( Val , Locale ) ? Val : 0 ) {
case ' \t ' : Strm < < " \\ t " ; break ;
case ' \n ' : Strm < < " \\ n " ; break ;
case ' \r ' : Strm < < " \\ r " ; break ;
case ' \f ' : Strm < < " \\ f " ; break ;
case ' \v ' : Strm < < " \\ v " ; break ;
default :
Strm < < llvm : : format_hex ( uint64_t ( Val ) & 0xff , 4 ) ;
}
}
else
Strm < < Val ;
2016-10-06 08:41:29 +03:00
Strm < < " ' " ;
return Strm . str ( ) ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const char * val ) {
2016-07-18 01:20:29 +03:00
return printOneChar ( * val ) ;
2015-08-18 18:48:45 +03:00
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const signed char * val ) {
2016-07-18 01:20:29 +03:00
return printOneChar ( * val ) ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const unsigned char * val ) {
2016-07-18 01:20:29 +03:00
return printOneChar ( * val ) ;
2015-08-13 17:23:59 +03:00
}
// Ints
2015-08-20 17:33:36 +03:00
std : : string printValue ( const short * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const unsigned short * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const int * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const unsigned int * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const long * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const unsigned long * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const long long * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const unsigned long long * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
// Reals
std : : string printValue ( const float * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
strm < < llvm : : format ( " %.5f " , * val ) < < ' f ' ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const double * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
strm < < llvm : : format ( " %.6f " , * val ) ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const long double * val ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
strm < < llvm : : format ( " %.8Lf " , * val ) < < ' L ' ;
//strm << llvm::format("%Le", *val) << 'L';
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
// Char pointers
2016-10-07 04:07:00 +03:00
std : : string printString ( const char * const * Ptr , size_t N = 10000 ) {
// Assumption is this is a string.
// N is limit to prevent endless loop if Ptr is not really a string.
const char * Start = * Ptr ;
if ( ! Start )
2016-10-06 19:11:23 +03:00
return kNullPtrStr ;
2016-10-07 04:07:00 +03:00
const char * End = Start + N ;
bool IsValid = utils : : isAddressValid ( Start ) ;
if ( IsValid ) {
// If we're gonnd do this, better make sure the end is valid too
// FIXME: getpagesize() & GetSystemInfo().dwPageSize might be better
enum { PAGE_SIZE = 1024 } ;
while ( ! ( IsValid = utils : : isAddressValid ( End ) ) & & N > 1024 ) {
N - = PAGE_SIZE ;
End = Start + N ;
2015-08-13 17:23:59 +03:00
}
}
2016-10-07 04:07:00 +03:00
if ( ! IsValid ) {
cling : : smallstream Strm ;
Strm < < static_cast < const void * > ( Start ) < < kInvalidAddr ;
return Strm . str ( ) ;
}
if ( * Start = = 0 )
return " \" \" " ;
// Copy the bytes until we get a null-terminator
llvm : : SmallString < 1024 > Buf ;
llvm : : raw_svector_ostream Strm ( Buf ) ;
Strm < < " \" " ;
while ( Start < End & & * Start )
Strm < < * Start + + ;
Strm < < " \" " ;
return Strm . str ( ) ;
}
std : : string printValue ( const char * const * val ) {
return printString ( val ) ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const char * * val ) {
2016-10-07 04:07:00 +03:00
return printString ( val ) ;
2015-08-13 17:23:59 +03:00
}
// std::string
2015-08-20 17:33:36 +03:00
std : : string printValue ( const std : : string * val ) {
return " \" " + * val + " \" " ;
2015-08-13 17:23:59 +03:00
}
2017-05-05 18:00:55 +03:00
2016-10-07 04:07:00 +03:00
static std : : string quoteString ( std : : string Str , const char Prefix ) {
// No wrap
if ( ! Prefix )
return Str ;
// Quoted wrap
if ( Prefix = = 1 )
return enclose ( std : : move ( Str ) , " \" " , " \" " , 2 ) ;
// Prefix quoted wrap
char Begin [ 3 ] = { Prefix , ' " ' , 0 } ;
return enclose ( std : : move ( Str ) , Begin , & Begin [ 1 ] , 3 ) ;
}
2015-08-13 17:23:59 +03:00
2016-12-20 22:15:54 +03:00
static std : : string quoteString ( const char * Str , size_t N , const char Prefix ) {
return quoteString ( std : : string ( Str , Str [ N - 1 ] = = 0 ? ( N - 1 ) : N ) , Prefix ) ;
}
# ifdef LLVM_UTF8
2017-06-02 14:36:23 +03:00
using llvm : : ConversionResult ;
using llvm : : ConversionFlags ;
using llvm : : lenientConversion ;
using llvm : : UTF8 ;
using llvm : : UTF16 ;
using llvm : : UTF32 ;
2016-12-20 22:15:54 +03:00
template < class T > struct CharTraits ;
template < > struct CharTraits < char16_t > {
2017-01-20 22:20:03 +03:00
static ConversionResult convert ( const char16_t * * begin , const char16_t * end ,
char * * d , char * dEnd , ConversionFlags F ) {
return ConvertUTF16toUTF8 ( reinterpret_cast < const UTF16 * * > ( begin ) ,
reinterpret_cast < const UTF16 * > ( end ) ,
reinterpret_cast < UTF8 * * > ( d ) ,
reinterpret_cast < UTF8 * > ( dEnd ) , F ) ;
2016-12-20 22:15:54 +03:00
}
} ;
template < > struct CharTraits < char32_t > {
2017-01-20 22:20:03 +03:00
static ConversionResult convert ( const char32_t * * begin , const char32_t * end ,
char * * d , char * dEnd , ConversionFlags F ) {
return ConvertUTF32toUTF8 ( reinterpret_cast < const UTF32 * * > ( begin ) ,
reinterpret_cast < const UTF32 * > ( end ) ,
reinterpret_cast < UTF8 * * > ( d ) ,
reinterpret_cast < UTF8 * > ( dEnd ) , F ) ;
2016-12-20 22:15:54 +03:00
}
} ;
template < > struct CharTraits < wchar_t > {
2017-01-20 22:20:03 +03:00
static ConversionResult convert ( const wchar_t * * src , const wchar_t * srcEnd ,
char * * dst , char * dEnd , ConversionFlags F ) {
2016-12-20 22:15:54 +03:00
switch ( sizeof ( wchar_t ) ) {
case sizeof ( char16_t ) :
2017-01-20 22:20:03 +03:00
return CharTraits < char16_t > : : convert (
reinterpret_cast < const char16_t * * > ( src ) ,
reinterpret_cast < const char16_t * > ( srcEnd ) ,
dst , dEnd , F ) ;
2016-12-20 22:15:54 +03:00
case sizeof ( char32_t ) :
2017-01-20 22:20:03 +03:00
return CharTraits < char32_t > : : convert (
reinterpret_cast < const char32_t * * > ( src ) ,
reinterpret_cast < const char32_t * > ( srcEnd ) ,
dst , dEnd , F ) ;
default : break ;
2016-12-20 22:15:54 +03:00
}
llvm_unreachable ( " wchar_t conversion failure " ) ;
}
} ;
template < typename T >
static std : : string encodeUTF8 ( const T * const Str , size_t N , const char Prfx ) {
2017-01-20 22:20:03 +03:00
const T * Bgn = Str ,
* End = Str + N ;
2016-12-20 22:15:54 +03:00
std : : string Result ;
Result . resize ( UNI_MAX_UTF8_BYTES_PER_CODE_POINT * N ) ;
char * ResultPtr = & Result [ 0 ] ,
* ResultEnd = ResultPtr + Result . size ( ) ;
2017-05-05 18:00:55 +03:00
2017-01-20 22:20:03 +03:00
CharTraits < T > : : convert ( & Bgn , End , & ResultPtr , ResultEnd , lenientConversion ) ;
Result . resize ( ResultPtr - & Result [ 0 ] ) ;
return quoteString ( std : : move ( Result ) , Prfx ) ;
2016-12-20 22:15:54 +03:00
}
# else // !LLVM_UTF8
2016-12-05 23:53:36 +03:00
template < class T > struct CharTraits { typedef T value_type ; } ;
# if defined(LLVM_ON_WIN32) // Likely only to be needed when _MSC_VER < 19??
template < > struct CharTraits < char16_t > { typedef unsigned short value_type ; } ;
template < > struct CharTraits < char32_t > { typedef unsigned int value_type ; } ;
# endif
2016-10-06 23:31:26 +03:00
template < typename T >
static std : : string encodeUTF8 ( const T * const Str , size_t N , const char Prfx ) {
2016-12-05 23:53:36 +03:00
typedef typename CharTraits < T > : : value_type value_type ;
std : : wstring_convert < std : : codecvt_utf8_utf16 < value_type > , value_type > Convert ;
const value_type * Src = reinterpret_cast < const value_type * > ( Str ) ;
return quoteString ( Convert . to_bytes ( Src , Src + N ) , Prfx ) ;
2016-10-06 23:31:26 +03:00
}
2016-12-20 22:15:54 +03:00
# endif // LLVM_UTF8
2016-10-06 23:31:26 +03:00
template < typename T >
2016-12-20 22:15:54 +03:00
std : : string utf8Value ( const T * const Str , size_t N , const char Prefix ,
std : : string ( * Func ) ( const T * const Str , size_t N ,
const char Prfx ) ) {
2016-10-06 23:31:26 +03:00
if ( ! Str )
return kNullPtrStr ;
if ( N = = 0 )
return printAddress ( Str , ' @ ' ) ;
// Drop the null terminator or else it will be encoded into the std::string.
2016-12-20 22:15:54 +03:00
return Func ( Str , Str [ N - 1 ] = = 0 ? ( N - 1 ) : N , Prefix ) ;
2016-10-06 23:31:26 +03:00
}
2016-12-20 22:15:54 +03:00
// declaration: cling/Utils/UTF8.h & cling/Interpreter/RuntimePrintValue.h
template < class T >
std : : string toUTF8 ( const T * const Str , size_t N , const char Prefix ) ;
2016-10-07 04:07:00 +03:00
template < >
2016-12-20 22:15:54 +03:00
std : : string toUTF8 < char16_t > ( const char16_t * const Str , size_t N ,
const char Prefix ) {
return utf8Value ( Str , N , Prefix , encodeUTF8 ) ;
}
2016-10-07 04:07:00 +03:00
2016-12-20 22:15:54 +03:00
template < >
std : : string toUTF8 < char32_t > ( const char32_t * const Str , size_t N ,
const char Prefix ) {
return utf8Value ( Str , N , Prefix , encodeUTF8 ) ;
}
template < >
std : : string toUTF8 < wchar_t > ( const wchar_t * const Str , size_t N ,
const char Prefix ) {
2017-02-03 00:59:34 +03:00
static_assert ( sizeof ( wchar_t ) = = sizeof ( char16_t ) | |
sizeof ( wchar_t ) = = sizeof ( char32_t ) , " Bad wchar_t size " ) ;
if ( sizeof ( wchar_t ) = = sizeof ( char32_t ) )
return toUTF8 ( reinterpret_cast < const char32_t * const > ( Str ) , N , Prefix ) ;
return toUTF8 ( reinterpret_cast < const char16_t * const > ( Str ) , N , Prefix ) ;
2016-12-20 22:15:54 +03:00
}
template < >
std : : string toUTF8 < char > ( const char * const Str , size_t N , const char Prefix ) {
return utf8Value ( Str , N , Prefix , quoteString ) ;
2016-10-07 04:07:00 +03:00
}
2016-10-06 23:31:26 +03:00
template < typename T >
static std : : string toUTF8 (
const std : : basic_string < T , std : : char_traits < T > , std : : allocator < T > > * Src ,
const char Prefix ) {
2016-12-20 22:15:54 +03:00
if ( ! Src )
return kNullPtrStr ;
2016-10-06 23:31:26 +03:00
return encodeUTF8 ( Src - > data ( ) , Src - > size ( ) , Prefix ) ;
}
std : : string printValue ( const std : : u16string * Val ) {
return toUTF8 ( Val , ' u ' ) ;
}
std : : string printValue ( const std : : u32string * Val ) {
return toUTF8 ( Val , ' U ' ) ;
}
std : : string printValue ( const std : : wstring * Val ) {
return toUTF8 ( Val , ' L ' ) ;
}
// Unicode chars
template < typename T >
static std : : string toUnicode ( const T * Src , const char Prefix , char Esc = 0 ) {
if ( ! Src )
return kNullPtrStr ;
if ( ! Esc )
Esc = Prefix ;
llvm : : SmallString < 128 > Buf ;
llvm : : raw_svector_ostream Strm ( Buf ) ;
Strm < < Prefix < < " ' \\ " < < Esc
< < llvm : : format_hex_no_prefix ( unsigned ( * Src ) , sizeof ( T ) * 2 ) < < " ' " ;
return Strm . str ( ) ;
}
std : : string printValue ( const char16_t * Val ) {
return toUnicode ( Val , ' u ' ) ;
}
std : : string printValue ( const char32_t * Val ) {
return toUnicode ( Val , ' U ' ) ;
}
std : : string printValue ( const wchar_t * Val ) {
return toUnicode ( Val , ' L ' , ' x ' ) ;
}
2017-05-05 18:00:55 +03:00
} // end namespace cling
2017-06-06 22:22:10 +03:00
namespace {
2017-05-05 18:00:55 +03:00
2017-06-04 00:01:09 +03:00
static std : : string callPrintValue ( const Value & V , const void * Val ) {
Interpreter * Interp = V . getInterpreter ( ) ;
Value printValueV ;
2017-05-05 18:00:55 +03:00
2017-06-04 00:01:09 +03:00
{
// Use an llvm::raw_ostream to prepend '0x' in front of the pointer value.
2017-05-05 18:00:55 +03:00
2017-06-04 00:01:09 +03:00
cling : : ostrstream Strm ;
Strm < < " cling::printValue( " ;
Strm < < getTypeString ( V ) ;
Strm < < & Val ;
Strm < < " ); " ;
2017-05-05 18:00:55 +03:00
2017-06-04 00:01:09 +03:00
// We really don't care about protected types here (ROOT-7426)
AccessCtrlRAII_t AccessCtrlRAII ( * Interp ) ;
Interp - > evaluate ( Strm . str ( ) , printValueV ) ;
2017-05-05 18:00:55 +03:00
}
2017-06-04 00:01:09 +03:00
if ( printValueV . isValid ( ) & & printValueV . getPtr ( ) )
return * ( std : : string * ) printValueV . getPtr ( ) ;
2017-05-05 18:00:55 +03:00
2017-06-04 00:01:09 +03:00
// That didn't work. We probably diagnosed the issue as part of evaluate().
2017-06-23 17:47:15 +03:00
cling : : errs ( ) < < " ERROR in cling's callPrintValue(): cannot pass value! \n " ;
2017-06-04 00:01:09 +03:00
// Check that the issue comes from an unparsable type name: lambdas, unnamed
// namespaces, types declared inside functions etc. Assert on everything
// else.
assert ( ! canParseTypeName ( * Interp , getTypeString ( V ) )
& & " printValue failed on a valid type name. " ) ;
2017-06-23 17:47:15 +03:00
return " ERROR in cling's callPrintValue(): missing value string. " ;
2017-06-04 00:01:09 +03:00
}
2017-05-05 18:00:55 +03:00
template < typename T >
class HasExplicitPrintValue {
template < typename C ,
typename = decltype ( cling : : printValue ( ( C * ) nullptr ) ) >
static std : : true_type test ( int ) ;
static std : : false_type test ( . . . ) ;
public :
static constexpr bool value = decltype ( test < T > ( 0 ) ) : : value ;
} ;
2017-06-04 00:01:09 +03:00
template < typename T > static
typename std : : enable_if < ! HasExplicitPrintValue < const T > : : value , std : : string > : : type
executePrintValue ( const Value & V , const T & val ) {
return callPrintValue ( V , & val ) ;
}
template < typename T > static
typename std : : enable_if < HasExplicitPrintValue < const T > : : value , std : : string > : : type
executePrintValue ( const Value & V , const T & val ) {
return printValue ( & val ) ;
2017-05-05 18:00:55 +03:00
}
static std : : string printEnumValue ( const Value & V ) {
cling : : ostrstream enumString ;
clang : : ASTContext & C = V . getASTContext ( ) ;
clang : : QualType Ty = V . getType ( ) . getDesugaredType ( C ) ;
const clang : : EnumType * EnumTy = Ty . getNonReferenceType ( ) - > getAs < clang : : EnumType > ( ) ;
assert ( EnumTy & & " ValuePrinter.cpp: ERROR, printEnumValue invoked for a non enum type. " ) ;
clang : : EnumDecl * ED = EnumTy - > getDecl ( ) ;
uint64_t value = V . getULL ( ) ;
bool IsFirst = true ;
llvm : : APSInt ValAsAPSInt = C . MakeIntValue ( value , Ty ) ;
for ( clang : : EnumDecl : : enumerator_iterator I = ED - > enumerator_begin ( ) ,
E = ED - > enumerator_end ( ) ; I ! = E ; + + I ) {
if ( I - > getInitVal ( ) = = ValAsAPSInt ) {
if ( ! IsFirst ) {
enumString < < " ? " ;
}
enumString < < " ( " < < I - > getQualifiedNameAsString ( ) < < " ) " ;
IsFirst = false ;
}
}
enumString < < " : " < < printQualType ( C , ED - > getIntegerType ( ) ) < < " "
< < ValAsAPSInt . toString ( /*Radix = */ 10 ) ;
return enumString . str ( ) ;
}
static std : : string printFunctionValue ( const Value & V , const void * ptr , clang : : QualType Ty ) {
cling : : largestream o ;
o < < " Function @ " < < ptr ;
// If a function is the first thing printed in a session,
// getLastTransaction() will point to the transaction that loaded the
// ValuePrinter, and won't have a wrapper FD.
// Even if it did have one it wouldn't be the one that was requested to print.
Interpreter & Interp = * const_cast < Interpreter * > ( V . getInterpreter ( ) ) ;
const Transaction * T = Interp . getLastTransaction ( ) ;
if ( clang : : FunctionDecl * WrapperFD = T - > getWrapperFD ( ) ) {
clang : : ASTContext & C = V . getASTContext ( ) ;
const clang : : FunctionDecl * FD = nullptr ;
// CE should be the setValueNoAlloc call expr.
if ( const clang : : CallExpr * CallE
= llvm : : dyn_cast_or_null < clang : : CallExpr > (
utils : : Analyze : : GetOrCreateLastExpr ( WrapperFD ,
/*foundAtPos*/ 0 ,
/*omitDS*/ false ,
& Interp . getSema ( ) ) ) ) {
if ( const clang : : FunctionDecl * FDsetValue
= llvm : : dyn_cast_or_null < clang : : FunctionDecl > ( CallE - > getCalleeDecl ( ) ) ) {
if ( FDsetValue - > getNameAsString ( ) = = " setValueNoAlloc " & &
CallE - > getNumArgs ( ) = = 5 ) {
const clang : : Expr * Arg4 = CallE - > getArg ( 4 ) ;
while ( const clang : : CastExpr * CastE
= clang : : dyn_cast < clang : : CastExpr > ( Arg4 ) )
Arg4 = CastE - > getSubExpr ( ) ;
if ( const clang : : DeclRefExpr * DeclRefExp
= llvm : : dyn_cast < clang : : DeclRefExpr > ( Arg4 ) )
FD = llvm : : dyn_cast < clang : : FunctionDecl > ( DeclRefExp - > getDecl ( ) ) ;
}
}
}
if ( FD ) {
o < < ' \n ' ;
clang : : SourceRange SRange = FD - > getSourceRange ( ) ;
const char * cBegin = 0 ;
const char * cEnd = 0 ;
bool Invalid ;
if ( SRange . isValid ( ) ) {
clang : : SourceManager & SM = C . getSourceManager ( ) ;
clang : : SourceLocation LocBegin = SRange . getBegin ( ) ;
LocBegin = SM . getExpansionRange ( LocBegin ) . first ;
o < < " at " < < SM . getFilename ( LocBegin ) ;
unsigned LineNo = SM . getSpellingLineNumber ( LocBegin , & Invalid ) ;
if ( ! Invalid )
o < < ' : ' < < LineNo ;
o < < " : \n " ;
bool Invalid = false ;
cBegin = SM . getCharacterData ( LocBegin , & Invalid ) ;
if ( ! Invalid ) {
clang : : SourceLocation LocEnd = SRange . getEnd ( ) ;
LocEnd = SM . getExpansionRange ( LocEnd ) . second ;
cEnd = SM . getCharacterData ( LocEnd , & Invalid ) ;
if ( Invalid )
cBegin = 0 ;
} else {
cBegin = 0 ;
}
}
if ( cBegin & & cEnd & & cEnd > cBegin & & cEnd - cBegin < 16 * 1024 ) {
o < < llvm : : StringRef ( cBegin , cEnd - cBegin + 1 ) ;
} else {
const clang : : FunctionDecl * FDef ;
if ( FD - > hasBody ( FDef ) )
FD = FDef ;
FD - > print ( o ) ;
//const clang::FunctionDecl* FD
// = llvm::cast<const clang::FunctionType>(Ty)->getDecl();
}
// type-based print() never and decl-based print() sometimes does not
// include a final newline:
o < < ' \n ' ;
}
}
return o . str ( ) ;
}
2017-06-04 07:18:01 +03:00
static std : : string printStringType ( const Value & V , const clang : : Type * Type ) {
switch ( V . getInterpreter ( ) - > getLookupHelper ( ) . getStringType ( Type ) ) {
case LookupHelper : : kStdString :
return executePrintValue < std : : string > ( V , * ( std : : string * ) V . getPtr ( ) ) ;
case LookupHelper : : kWCharString :
return executePrintValue < std : : wstring > ( V , * ( std : : wstring * ) V . getPtr ( ) ) ;
case LookupHelper : : kUTF16Str :
return executePrintValue < std : : u16string > ( V , * ( std : : u16string * ) V . getPtr ( ) ) ;
case LookupHelper : : kUTF32Str :
return executePrintValue < std : : u32string > ( V , * ( std : : u32string * ) V . getPtr ( ) ) ;
default :
break ;
}
return " " ;
}
2017-05-05 18:00:55 +03:00
static std : : string printUnpackedClingValue ( const Value & V ) {
2017-05-05 18:33:52 +03:00
// Find the Type for `std::string`. We are guaranteed to have that declared
// when this function is called; RuntimePrintValue.h #includes it.
2017-05-05 18:00:55 +03:00
const clang : : ASTContext & C = V . getASTContext ( ) ;
const clang : : QualType Td = V . getType ( ) . getDesugaredType ( C ) ;
const clang : : QualType Ty = Td . getNonReferenceType ( ) ;
if ( Ty - > isNullPtrType ( ) ) {
// special case nullptr_t
return kNullPtrTStr ;
} else if ( Ty - > isEnumeralType ( ) ) {
// special case enum printing, using compiled information
return printEnumValue ( V ) ;
} else if ( Ty - > isFunctionType ( ) ) {
// special case function printing, using compiled information
return printFunctionValue ( V , & V , Ty ) ;
} else if ( ( Ty - > isPointerType ( ) | | Ty - > isMemberPointerType ( ) ) & & Ty - > getPointeeType ( ) - > isFunctionProtoType ( ) ) {
// special case function printing, using compiled information
return printFunctionValue ( V , V . getPtr ( ) , Ty - > getPointeeType ( ) ) ;
} else if ( clang : : CXXRecordDecl * CXXRD = Ty - > getAsCXXRecordDecl ( ) ) {
if ( CXXRD - > isLambda ( ) )
return printAddress ( V . getPtr ( ) , ' @ ' ) ;
2017-06-04 07:18:01 +03:00
std : : string Str = printStringType ( V , CXXRD - > getTypeForDecl ( ) ) ;
if ( ! Str . empty ( ) )
return Str ;
2017-05-05 18:00:55 +03:00
} else if ( const clang : : BuiltinType * BT
= llvm : : dyn_cast < clang : : BuiltinType > ( Td . getCanonicalType ( ) . getTypePtr ( ) ) ) {
switch ( BT - > getKind ( ) ) {
case clang : : BuiltinType : : Bool :
return executePrintValue < bool > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : Char_S :
return executePrintValue < signed char > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : SChar :
return executePrintValue < signed char > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : Short :
return executePrintValue < short > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : Int :
return executePrintValue < int > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : Long :
return executePrintValue < long > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : LongLong :
return executePrintValue < long long > ( V , V . getLL ( ) ) ;
case clang : : BuiltinType : : Char_U :
return executePrintValue < unsigned char > ( V , V . getULL ( ) ) ;
case clang : : BuiltinType : : UChar :
return executePrintValue < unsigned char > ( V , V . getULL ( ) ) ;
case clang : : BuiltinType : : UShort :
return executePrintValue < unsigned short > ( V , V . getULL ( ) ) ;
case clang : : BuiltinType : : UInt :
return executePrintValue < unsigned int > ( V , V . getULL ( ) ) ;
case clang : : BuiltinType : : ULong :
return executePrintValue < unsigned long > ( V , V . getULL ( ) ) ;
case clang : : BuiltinType : : ULongLong :
return executePrintValue < unsigned long long > ( V , V . getULL ( ) ) ;
case clang : : BuiltinType : : Float :
return executePrintValue < float > ( V , V . getFloat ( ) ) ;
case clang : : BuiltinType : : Double :
return executePrintValue < double > ( V , V . getDouble ( ) ) ;
case clang : : BuiltinType : : LongDouble :
return executePrintValue < long double > ( V , V . getLongDouble ( ) ) ;
default :
break ;
}
} else
assert ( ! Ty - > isIntegralOrEnumerationType ( ) & & " Bad Type. " ) ;
if ( ! V . getPtr ( ) )
return kNullPtrStr ;
// Print all the other cases by calling into runtime 'cling::printValue()'.
// Ty->isPointerType() || Ty->isReferenceType() || Ty->isArrayType()
// Ty->isObjCObjectPointerType()
2017-06-04 00:01:09 +03:00
return callPrintValue ( V , V . getPtr ( ) ) ;
2017-05-05 18:00:55 +03:00
}
2017-06-06 22:22:10 +03:00
} // anonymous namespace
2017-05-05 18:00:55 +03:00
namespace cling {
2015-08-20 17:33:36 +03:00
// cling::Value
std : : string printValue ( const Value * value ) {
2016-10-06 08:41:29 +03:00
cling : : smallstream strm ;
2015-08-13 17:23:59 +03:00
2016-10-03 03:14:51 +03:00
if ( value - > isValid ( ) ) {
2015-08-20 17:33:36 +03:00
clang : : ASTContext & C = value - > getASTContext ( ) ;
clang : : QualType QT = value - > getType ( ) ;
2015-08-13 17:23:59 +03:00
strm < < " boxes [ " ;
2016-10-06 23:41:33 +03:00
strm < < enclose ( QT , C , " ( " , " ) " , 3 ) ;
2015-08-18 12:02:16 +03:00
if ( ! QT - > isVoidType ( ) ) {
2015-08-20 17:33:36 +03:00
strm < < printUnpackedClingValue ( * value ) ;
2015-08-18 12:02:16 +03:00
}
2015-08-13 17:23:59 +03:00
strm < < " ] " ;
2016-10-03 03:14:51 +03:00
} else
strm < < " <<<invalid>>> " < < printAddress ( value , ' @ ' ) ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
namespace valuePrinterInternal {
2015-08-13 17:23:59 +03:00
2015-08-20 17:33:36 +03:00
std : : string printTypeInternal ( const Value & V ) {
2016-01-31 22:53:01 +03:00
return printQualType ( V . getASTContext ( ) , V . getType ( ) ) ;
2015-08-20 17:33:36 +03:00
}
2015-08-13 17:23:59 +03:00
2015-08-20 17:33:36 +03:00
std : : string printValueInternal ( const Value & V ) {
static bool includedRuntimePrintValue = false ; // initialized only once as a static function variable
// Include "RuntimePrintValue.h" only on the first printing.
// This keeps the interpreter lightweight and reduces the startup time.
if ( ! includedRuntimePrintValue ) {
V . getInterpreter ( ) - > declare ( " #include \" cling/Interpreter/RuntimePrintValue.h \" " ) ;
includedRuntimePrintValue = true ;
}
return printUnpackedClingValue ( V ) ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
} // end namespace valuePrinterInternal
2012-09-05 13:37:39 +04:00
} // end namespace cling