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>
2013-01-17 19:27:14 +04:00
# include <cstdio>
2013-01-18 14:34:51 +04:00
// Fragment copied from LLVM's raw_ostream.cpp
# if defined(_MSC_VER)
# ifndef STDIN_FILENO
# define STDIN_FILENO 0
# endif
# ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
# endif
# ifndef STDERR_FILENO
# define STDERR_FILENO 2
# endif
# else
//#if defined(HAVE_UNISTD_H)
# include <unistd.h>
//#endif
# endif
2012-09-05 13:37:39 +04:00
2015-08-17 14:04:00 +03:00
// For address validation
# ifdef LLVM_ON_WIN32
# include <Windows.h>
# else
# include <unistd.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
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
}
2015-08-20 17:33:36 +03:00
static std : : string getTypeString ( const Value & V ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream strm ;
clang : : ASTContext & C = V . getASTContext ( ) ;
clang : : QualType Ty = V . getType ( ) . getDesugaredType ( C ) . getNonReferenceType ( ) ;
std : : string type = cling : : utils : : TypeName : : GetFullyQualifiedName ( Ty , C ) ;
std : : ostringstream typeWithOptDeref ;
2015-08-20 17:33:36 +03:00
if ( llvm : : dyn_cast < clang : : BuiltinType > ( Ty . getCanonicalType ( ) ) ) {
typeWithOptDeref < < " ( " < < type < < " *) " ;
2015-08-13 17:23:59 +03:00
} else if ( Ty - > isPointerType ( ) ) {
if ( Ty - > getPointeeType ( ) - > isCharType ( ) ) {
2015-08-14 23:49:01 +03:00
// Print char pointers as strings.
2015-08-20 17:33:36 +03:00
typeWithOptDeref < < " ( " < < type < < " *) " ;
2015-08-13 17:23:59 +03:00
} else {
2015-08-14 23:49:01 +03:00
// Fallback to void pointer for other pointers and print the address.
2015-08-20 17:33:36 +03:00
typeWithOptDeref < < " (const void**) " ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
}
else if ( Ty - > isArrayType ( ) ) {
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
if ( ElementTy - > isCharType ( ) ) {
typeWithOptDeref < < " (const char **) " ;
} else if ( Ty - > isConstantArrayType ( ) ) {
const clang : : ConstantArrayType * CArrTy = C . getAsConstantArrayType ( Ty ) ;
const llvm : : APInt & APSize = CArrTy - > getSize ( ) ;
size_t size = ( size_t ) APSize . getZExtValue ( ) ;
// typeWithOptDeref example for int[40] array: "((int(*)[40])*(void**)0x5c8f260)"
typeWithOptDeref < < " ( " < < cling : : utils : : TypeName : : GetFullyQualifiedName ( ElementTy , C ) < < " (*)[ " < < size < < " ])*(void**) " ;
2015-08-13 17:23:59 +03:00
} else {
2015-08-20 17:33:36 +03:00
typeWithOptDeref < < " (void**) " ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
}
else {
2015-08-14 23:49:01 +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.
2015-08-20 17:33:36 +03:00
typeWithOptDeref < < " *( " < < type < < " **) " ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
strm < < typeWithOptDeref . str ( ) ;
2015-08-13 17:23:59 +03:00
return strm . str ( ) ;
}
2015-08-20 17:33:36 +03:00
template < typename T >
static std : : string executePrintValue ( const Value & V , const T & val ) {
Interpreter * Interp = V . getInterpreter ( ) ;
std : : stringstream printValueSS ;
printValueSS < < " cling::printValue( " ;
printValueSS < < getTypeString ( V ) ;
printValueSS < < ( const void * ) & val ;
printValueSS < < " ); " ;
Value printValueV ;
Interp - > evaluate ( printValueSS . str ( ) , printValueV ) ;
assert ( printValueV . isValid ( ) & & " Must return valid value. " ) ;
2015-10-09 19:43:39 +03:00
if ( ! printValueV . isValid ( ) | | printValueV . getPtr ( ) = = nullptr )
return " Error in ValuePrinter: missing output string. " ;
else
return * ( std : : string * ) printValueV . getPtr ( ) ;
2015-08-20 17:33:36 +03:00
}
static std : : string invokePrintValueOverload ( const Value & V ) {
clang : : ASTContext & C = V . getASTContext ( ) ;
2015-09-24 11:54:10 +03:00
clang : : QualType Ty = V . getType ( ) . getDesugaredType ( C ) . getCanonicalType ( ) ;
2015-08-20 17:33:36 +03:00
if ( const clang : : BuiltinType * BT
2015-09-24 11:54:10 +03:00
= llvm : : dyn_cast < clang : : BuiltinType > ( Ty . getTypePtr ( ) ) ) {
2015-08-20 17:33:36 +03:00
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 :
return executePrintValue < void * > ( V , V . getPtr ( ) ) ;
}
}
else if ( Ty - > isIntegralOrEnumerationType ( ) ) {
return executePrintValue < long long > ( V , V . getLL ( ) ) ;
}
else if ( Ty - > isFunctionType ( ) ) {
return executePrintValue < const void * > ( V , & V ) ;
}
else if ( Ty - > isPointerType ( )
| | Ty - > isReferenceType ( )
| | Ty - > isArrayType ( ) ) {
return executePrintValue < void * > ( V , V . getPtr ( ) ) ;
}
else {
// struct case.
return executePrintValue < void * > ( V , V . getPtr ( ) ) ;
}
}
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 ( ) ;
uint64_t value = * ( const uint64_t * ) & V ;
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
}
}
2015-08-20 17:33:36 +03:00
enumString < < " : (int) " < < 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 ) ;
o < < " Function @ " < < ptr < < ' \n ' ;
2015-08-20 17:33:36 +03:00
clang : : ASTContext & C = V . getASTContext ( ) ;
Interpreter & Interp = * const_cast < Interpreter * > ( V . getInterpreter ( ) ) ;
const Transaction * T = Interp . getLastTransaction ( ) ;
2015-08-13 17:23:59 +03:00
assert ( T - > getWrapperFD ( ) & & " Must have a wrapper. " ) ;
2015-08-20 17:33:36 +03:00
clang : : FunctionDecl * WrapperFD = T - > getWrapperFD ( ) ;
2015-08-13 17:23:59 +03:00
2015-08-20 17:33:36 +03:00
const clang : : FunctionDecl * FD = 0 ;
2015-08-13 17:23:59 +03:00
// CE should be the setValueNoAlloc call expr.
2015-08-20 17:33:36 +03:00
if ( const clang : : CallExpr * CallE
2015-08-13 17:23:59 +03:00
= llvm : : dyn_cast_or_null < clang : : CallExpr > (
utils : : Analyze : : GetOrCreateLastExpr ( WrapperFD ,
/*foundAtPos*/ 0 ,
/*omitDS*/ false ,
& Interp . getSema ( ) ) ) ) {
2015-08-20 17:33:36 +03:00
if ( const clang : : FunctionDecl * FDsetValue
= llvm : : dyn_cast_or_null < clang : : FunctionDecl > ( CallE - > getCalleeDecl ( ) ) ) {
2015-08-13 17:23:59 +03:00
if ( FDsetValue - > getNameAsString ( ) = = " setValueNoAlloc " & &
CallE - > getNumArgs ( ) = = 5 ) {
2015-08-20 17:33:36 +03:00
const clang : : Expr * Arg4 = CallE - > getArg ( 4 ) ;
while ( const clang : : CastExpr * CastE
2015-08-13 17:23:59 +03:00
= clang : : dyn_cast < clang : : CastExpr > ( Arg4 ) )
Arg4 = CastE - > getSubExpr ( ) ;
2015-08-20 17:33:36 +03:00
if ( const clang : : DeclRefExpr * DeclRefExp
2015-08-13 17:23:59 +03:00
= llvm : : dyn_cast < clang : : DeclRefExpr > ( Arg4 ) )
FD = llvm : : dyn_cast < clang : : FunctionDecl > ( DeclRefExp - > getDecl ( ) ) ;
}
}
}
if ( FD ) {
clang : : SourceRange SRange = FD - > getSourceRange ( ) ;
2015-08-20 17:33:36 +03:00
const char * cBegin = 0 ;
const char * cEnd = 0 ;
2015-08-13 17:23:59 +03:00
bool Invalid ;
if ( SRange . isValid ( ) ) {
2015-08-20 17:33:36 +03:00
clang : : SourceManager & SM = C . getSourceManager ( ) ;
2015-08-13 17:23:59 +03:00
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 {
2015-08-20 17:33:36 +03:00
const clang : : FunctionDecl * FDef ;
2015-08-13 17:23:59 +03:00
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 ' ;
functionString = o . str ( ) ;
return functionString ;
}
2015-08-20 17:33:36 +03:00
static std : : string printUnpackedClingValue ( const Value & V ) {
2015-08-17 14:17:11 +03:00
std : : stringstream strm ;
2015-08-20 17:33:36 +03:00
clang : : ASTContext & C = V . getASTContext ( ) ;
2015-08-17 14:17:11 +03:00
clang : : QualType QT = V . getType ( ) ;
clang : : QualType Ty = QT . getDesugaredType ( C ) . getNonReferenceType ( ) ;
2015-08-20 17:33:36 +03:00
if ( Ty - > isNullPtrType ( ) ) {
2015-08-17 14:17:11 +03:00
// special case nullptr_t
2015-08-18 19:02:07 +03:00
strm < < " nullptr_t " ;
2015-08-17 14:17:11 +03:00
} else if ( Ty - > isEnumeralType ( ) ) {
// special case enum printing, using compiled information
strm < < printEnumValue ( V ) ;
} else if ( Ty - > isFunctionType ( ) ) {
// special case function printing, using compiled information
strm < < printFunctionValue ( V , & V , Ty ) ;
} else if ( ( Ty - > isPointerType ( ) | | Ty - > isMemberPointerType ( ) ) & & Ty - > getPointeeType ( ) - > isFunctionProtoType ( ) ) {
// special case function printing, using compiled information
strm < < printFunctionValue ( V , V . getPtr ( ) , Ty - > getPointeeType ( ) ) ;
2015-08-20 17:33:36 +03:00
} else if ( clang : : CXXRecordDecl * CXXRD = Ty - > getAsCXXRecordDecl ( ) ) {
if ( CXXRD - > isLambda ( ) ) {
strm < < " @ " < < V . getPtr ( ) ;
} else {
// default case, modular printing using cling::printValue
strm < < invokePrintValueOverload ( V ) ;
}
2015-08-17 14:17:11 +03:00
} else {
2015-08-20 17:33:36 +03:00
// default case, modular printing using cling::printValue
2015-08-17 14:17:11 +03:00
strm < < invokePrintValueOverload ( V ) ;
}
return strm . str ( ) ;
}
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 ) {
2015-08-13 17:23:59 +03:00
if ( ! ptr ) {
2015-08-18 18:48:45 +03:00
return " nullptr " ;
2015-08-13 17:23:59 +03:00
} else {
2015-08-18 18:48:45 +03:00
std : : ostringstream strm ;
2015-08-20 17:33:36 +03:00
strm < < " @ " < < ptr ;
2015-12-08 15:26:13 +03:00
if ( ! utils : : isAddressValid ( ptr ) )
2015-08-18 18:48:45 +03:00
strm < < " <invalid memory address> " ;
return strm . str ( ) ;
2015-08-13 17:23:59 +03:00
}
}
2015-08-20 17:33:36 +03:00
// void pointer
std : : string printValue ( const void * * ptr ) {
if ( ! * ptr ) {
return " nullptr " ;
} else {
std : : ostringstream strm ;
strm < < * ptr ;
2015-12-08 15:26:13 +03:00
if ( ! utils : : isAddressValid ( * ptr ) )
2015-08-20 17:33:36 +03:00
strm < < " <invalid memory address> " ;
return strm . str ( ) ;
}
}
2015-08-13 17:23:59 +03:00
// Bool
2015-08-20 17:33:36 +03:00
std : : string printValue ( const bool * val ) {
2015-08-21 13:17:17 +03:00
return * val ? " true " : " false " ;
2015-08-13 17:23:59 +03:00
}
// Chars
2015-08-20 17:33:36 +03:00
static std : : string printChar ( signed char val , bool apostrophe ) {
2015-08-13 17:23:59 +03:00
std : : ostringstream strm ;
2015-08-18 18:48:45 +03:00
if ( val > 0x1F & & val < 0x7F ) {
if ( apostrophe )
strm < < " ' " ;
strm < < val ;
if ( apostrophe )
strm < < " ' " ;
} else {
strm < < " 0x " < < std : : hex < < ( int ) val ;
}
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 ) {
return printChar ( * val , true ) ;
2015-08-18 18:48:45 +03:00
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const signed char * val ) {
return printChar ( * val , true ) ;
2015-08-13 17:23:59 +03:00
}
2015-08-20 17:33:36 +03:00
std : : string printValue ( const unsigned char * val ) {
return printChar ( * val , true ) ;
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 ) {
2015-08-18 18:48:45 +03:00
return " nullptr " ;
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 ) {
2015-08-18 18:48:45 +03:00
strm < < printChar ( * cobj , false ) ;
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 ;
2015-08-20 17:33:36 +03:00
if ( ! value - > isValid ( ) ) {
strm < < " <<<invalid>>> @ " < < value ;
2015-08-13 17:23:59 +03:00
} else {
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 [ " ;
strm < < " ( "
2015-08-17 14:20:20 +03:00
< < cling : : utils : : TypeName : : GetFullyQualifiedName ( QT , C )
2015-08-13 17:23:59 +03:00
< < " ) " ;
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 < < " ] " ;
}
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 ) {
using namespace clang ;
std : : ostringstream strm ;
clang : : ASTContext & C = V . getASTContext ( ) ;
QualType QT = V . getType ( ) . getNonReferenceType ( ) ;
std : : string ValueTyStr ;
if ( const TypedefType * TDTy = dyn_cast < TypedefType > ( QT ) )
ValueTyStr = TDTy - > getDecl ( ) - > getQualifiedNameAsString ( ) ;
else if ( const TagType * TTy = dyn_cast < TagType > ( QT ) )
ValueTyStr = TTy - > getDecl ( ) - > getQualifiedNameAsString ( ) ;
if ( ValueTyStr . empty ( ) )
ValueTyStr = cling : : utils : : TypeName : : GetFullyQualifiedName ( QT , C ) ;
else if ( QT . hasQualifiers ( ) )
ValueTyStr = QT . getQualifiers ( ) . getAsString ( ) + " " + ValueTyStr ;
strm < < " ( " ;
strm < < ValueTyStr ;
if ( V . getType ( ) - > isReferenceType ( ) )
strm < < " & " ;
strm < < " ) " ;
return strm . str ( ) ;
}
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