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"
# 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"
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
# include "llvm/Support/raw_ostream.h"
2013-02-22 19:59:54 +04:00
# include "llvm/ExecutionEngine/GenericValue.h"
2012-09-05 13:37:39 +04:00
# include <string>
2014-02-19 17:47:03 +04:00
# include <sstream>
2015-08-17 14:04:00 +03:00
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
2013-01-17 19:27:14 +04:00
// We need stream that doesn't close its file descriptor, thus we are not
// using llvm::outs. Keeping file descriptor open we will be able to use
// the results in pipes (Savannah #99234).
2014-05-19 18:12:41 +04:00
//llvm::raw_fd_ostream outs (STDOUT_FILENO, /*ShouldClose*/false);
2013-01-17 19:27:14 +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 13:49:10 +03:00
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 " ,
* const kFalseStr = " false " ;
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
}
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 ( ) ) {
2015-08-20 17:33:36 +03:00
const clang : : ArrayType * ArrTy = Ty - > getAsArrayTypeUnsafe ( ) ;
2015-08-13 17:23:59 +03:00
clang : : QualType ElementTy = ArrTy - > getElementType ( ) ;
2015-08-20 17:33:36 +03:00
// In case of char ElementTy, printing as string
2016-10-06 04:30:26 +03:00
if ( ElementTy - > isCharType ( ) )
return " (const char **) " ;
if ( Ty - > isConstantArrayType ( ) ) {
2015-08-20 17:33:36 +03:00
const clang : : ConstantArrayType * CArrTy = C . getAsConstantArrayType ( Ty ) ;
const llvm : : APInt & APSize = CArrTy - > getSize ( ) ;
// typeWithOptDeref example for int[40] array: "((int(*)[40])*(void**)0x5c8f260)"
2016-10-06 23:41:33 +03:00
return enclose ( ElementTy , C , " ( " , " (*)[ " , 5 ) +
2016-10-06 04:30:26 +03:00
std : : to_string ( APSize . getZExtValue ( ) ) + " ])*(void**) " ;
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 ;
}
~ 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 )
llvm : : errs ( ) < < " ERROR in cling::executePrintValue(): "
" this typename cannot be spelled. \n " ;
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-01-29 00:52:04 +03:00
} // anonymous namespace
2015-08-20 17:33:36 +03:00
template < typename T >
static std : : string executePrintValue ( const Value & V , const T & val ) {
2016-01-28 22:39:36 +03:00
Interpreter * Interp = V . getInterpreter ( ) ;
2015-08-20 17:33:36 +03:00
Value printValueV ;
2016-01-16 22:15:37 +03:00
2016-01-28 22:39:36 +03:00
{
2016-10-06 04:30:47 +03:00
// Use an llvm::raw_ostream to prepend '0x' in front of the pointer value.
llvm : : SmallString < 512 > Buf ;
llvm : : raw_svector_ostream Strm ( Buf ) ;
Strm < < " cling::printValue( " ;
Strm < < getTypeString ( V ) ;
Strm < < ( const void * ) & val ;
Strm < < " ); " ;
2016-01-31 22:53:01 +03:00
// We really don't care about protected types here (ROOT-7426)
2016-01-28 22:39:36 +03:00
AccessCtrlRAII_t AccessCtrlRAII ( * Interp ) ;
clang : : DiagnosticsEngine & Diag = Interp - > getCI ( ) - > getDiagnostics ( ) ;
bool oldSuppDiags = Diag . getSuppressAllDiagnostics ( ) ;
Diag . setSuppressAllDiagnostics ( true ) ;
2016-10-06 04:30:47 +03:00
Interp - > evaluate ( Strm . str ( ) , printValueV ) ;
2016-01-28 22:39:36 +03:00
Diag . setSuppressAllDiagnostics ( oldSuppDiags ) ;
}
if ( ! printValueV . isValid ( ) | | printValueV . getPtr ( ) = = nullptr ) {
// That didn't work. We probably diagnosed the issue as part of evaluate().
llvm : : errs ( ) < < " ERROR in cling::executePrintValue(): cannot pass value! \n " ;
// 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. " ) ;
2016-03-30 13:27:04 +03:00
return " ERROR in cling::executePrintValue(): missing value string. " ;
2016-01-28 22:39:36 +03:00
}
return * ( std : : string * ) printValueV . getPtr ( ) ;
2015-08-20 17:33:36 +03:00
}
static std : : string printEnumValue ( const Value & V ) {
2015-08-13 17:23:59 +03:00
std : : stringstream enumString ;
2015-08-20 17:33:36 +03:00
clang : : ASTContext & C = V . getASTContext ( ) ;
2015-08-13 17:23:59 +03:00
clang : : QualType Ty = V . getType ( ) . getDesugaredType ( C ) ;
2015-08-17 14:55:35 +03:00
const clang : : EnumType * EnumTy = Ty . getNonReferenceType ( ) - > getAs < clang : : EnumType > ( ) ;
2015-08-20 17:33:36 +03:00
assert ( EnumTy & & " ValuePrinter.cpp: ERROR, printEnumValue invoked for a non enum type. " ) ;
clang : : EnumDecl * ED = EnumTy - > getDecl ( ) ;
2016-08-06 05:06:26 +03:00
uint64_t value = V . getULL ( ) ;
2015-08-20 17:33:36 +03:00
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 < < " ? " ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
enumString < < " ( " < < I - > getQualifiedNameAsString ( ) < < " ) " ;
IsFirst = false ;
2015-08-13 17:23:59 +03:00
}
}
2016-01-31 22:53:01 +03:00
enumString < < " : " < < printQualType ( C , ED - > getIntegerType ( ) ) < < " "
< < ValAsAPSInt . toString ( /*Radix = */ 10 ) ;
2015-08-13 17:23:59 +03:00
return enumString . str ( ) ;
}
2015-08-20 17:33:36 +03:00
static std : : string printFunctionValue ( const Value & V , const void * ptr , clang : : QualType Ty ) {
2015-08-13 17:23:59 +03:00
std : : string functionString ;
llvm : : raw_string_ostream o ( functionString ) ;
2016-07-14 11:01:22 +03:00
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.
2015-08-13 17:23:59 +03:00
2015-08-20 17:33:36 +03:00
Interpreter & Interp = * const_cast < Interpreter * > ( V . getInterpreter ( ) ) ;
const Transaction * T = Interp . getLastTransaction ( ) ;
2016-07-14 11:01:22 +03:00
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
2015-08-20 17:33:36 +03:00
= llvm : : dyn_cast_or_null < clang : : FunctionDecl > ( CallE - > getCalleeDecl ( ) ) ) {
2016-07-14 11:01:22 +03:00
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 ( ) ) ;
}
2015-08-13 17:23:59 +03:00
}
}
2016-07-14 11:01:22 +03:00
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 {
2015-08-13 17:23:59 +03:00
cBegin = 0 ;
2016-07-14 11:01:22 +03:00
}
}
if ( cBegin & & cEnd & & cEnd > cBegin & & cEnd - cBegin < 16 * 1024 ) {
o < < llvm : : StringRef ( cBegin , cEnd - cBegin + 1 ) ;
2015-08-13 17:23:59 +03:00
} else {
2016-07-14 11:01:22 +03:00
const clang : : FunctionDecl * FDef ;
if ( FD - > hasBody ( FDef ) )
FD = FDef ;
FD - > print ( o ) ;
//const clang::FunctionDecl* FD
// = llvm::cast<const clang::FunctionType>(Ty)->getDecl();
2015-08-13 17:23:59 +03:00
}
2016-07-14 11:01:22 +03:00
// type-based print() never and decl-based print() sometimes does not
// include a final newline:
o < < ' \n ' ;
2015-08-13 17:23:59 +03:00
}
}
functionString = o . str ( ) ;
return functionString ;
}
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
llvm : : SmallString < 256 > Buf ;
llvm : : raw_svector_ostream Strm ( Buf ) ;
if ( Prfx )
Strm < < Prfx ;
Strm < < Ptr ;
if ( ! utils : : isAddressValid ( Ptr ) )
Strm < < " <invalid memory address> " ;
return Strm . str ( ) ;
}
2015-08-17 14:17:11 +03:00
2016-10-03 03:14:51 +03:00
static std : : string printUnpackedClingValue ( const Value & V ) {
2016-10-10 20:47:03 +03:00
const clang : : ASTContext & C = V . getASTContext ( ) ;
const clang : : QualType Td = V . getType ( ) . getDesugaredType ( C ) ;
const clang : : QualType Ty = Td . getNonReferenceType ( ) ;
2015-08-17 14:17:11 +03:00
2015-08-20 17:33:36 +03:00
if ( Ty - > isNullPtrType ( ) ) {
2015-08-17 14:17:11 +03:00
// special case nullptr_t
2016-10-06 19:11:23 +03:00
return kNullPtrTStr ;
2015-08-17 14:17:11 +03:00
} else if ( Ty - > isEnumeralType ( ) ) {
// special case enum printing, using compiled information
2016-10-03 03:14:51 +03:00
return printEnumValue ( V ) ;
2015-08-17 14:17:11 +03:00
} else if ( Ty - > isFunctionType ( ) ) {
// special case function printing, using compiled information
2016-10-03 03:14:51 +03:00
return printFunctionValue ( V , & V , Ty ) ;
2015-08-17 14:17:11 +03:00
} else if ( ( Ty - > isPointerType ( ) | | Ty - > isMemberPointerType ( ) ) & & Ty - > getPointeeType ( ) - > isFunctionProtoType ( ) ) {
// special case function printing, using compiled information
2016-10-03 03:14:51 +03:00
return printFunctionValue ( V , V . getPtr ( ) , Ty - > getPointeeType ( ) ) ;
2015-08-20 17:33:36 +03:00
} else if ( clang : : CXXRecordDecl * CXXRD = Ty - > getAsCXXRecordDecl ( ) ) {
2016-10-03 03:14:51 +03:00
if ( CXXRD - > isLambda ( ) )
return printAddress ( V . getPtr ( ) , ' @ ' ) ;
2016-10-10 20:47:03 +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()
return executePrintValue < void * > ( V , V . getPtr ( ) ) ;
2015-08-17 14:17:11 +03:00
}
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-07-18 01:20:29 +03:00
static void printChar ( signed char val , std : : ostringstream & strm ) {
2015-08-18 18:48:45 +03:00
if ( val > 0x1F & & val < 0x7F ) {
strm < < val ;
} else {
2016-09-12 22:02:11 +03:00
std : : ios : : fmtflags prevFlags = strm . flags ( ) ;
2015-08-18 18:48:45 +03:00
strm < < " 0x " < < std : : hex < < ( int ) val ;
2016-09-12 22:02:11 +03:00
strm . flags ( prevFlags ) ;
2015-08-18 18:48:45 +03:00
}
2016-07-18 01:20:29 +03:00
}
static std : : string printOneChar ( signed char val ) {
std : : ostringstream strm ;
strm < < " ' " ;
printChar ( val , strm ) ;
strm < < " ' " ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream strm ;
2015-08-20 17:33:36 +03:00
strm < < std : : showpoint < < * 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream strm ;
2015-08-20 17:33:36 +03:00
strm < < std : : showpoint < < * 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 ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream strm ;
2015-08-20 17:33:36 +03:00
strm < < * val < < " L " ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
// Char pointers
2015-08-20 17:33:36 +03:00
std : : string printValue ( const char * const * val ) {
if ( ! * val ) {
2016-10-06 19:11:23 +03:00
return kNullPtrStr ;
2015-08-13 17:23:59 +03:00
} else {
2015-08-18 18:48:45 +03:00
std : : ostringstream strm ;
2015-08-13 17:23:59 +03:00
strm < < " \" " ;
2015-08-18 18:48:45 +03:00
// 10000 limit to prevent potential printing of the whole RAM / inf loop
2015-08-20 17:33:36 +03:00
for ( const char * cobj = * val ; * cobj ! = 0 & & cobj - * val < 10000 ; + + cobj ) {
2016-07-18 01:20:29 +03:00
printChar ( * cobj , strm ) ;
2015-08-13 17:23:59 +03:00
}
strm < < " \" " ;
2015-08-18 18:48:45 +03:00
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 ) {
return printValue ( ( const char * const * ) 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
}
2015-08-20 17:33:36 +03:00
// cling::Value
std : : string printValue ( const Value * value ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream strm ;
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