Do not allocate Values/strings for printing simple types.
Still missing is calling a printValue(std::string) overload from printUnpackedClingValue. That is needed for optimizing the generic printValue() invocation through the interpreter: it should not have to create a *second* Value for printing the string returned from printValue().
This commit is contained in:
parent
93869de6c7
commit
e25880b49d
@ -209,150 +209,6 @@ static std::string printQualType(clang::ASTContext& Ctx, clang::QualType QT) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
template<typename T>
|
||||
static std::string executePrintValue(const Value &V, const T &val) {
|
||||
Interpreter *Interp = V.getInterpreter();
|
||||
Value printValueV;
|
||||
|
||||
{
|
||||
// Use an llvm::raw_ostream to prepend '0x' in front of the pointer value.
|
||||
|
||||
cling::ostrstream Strm;
|
||||
Strm << "cling::printValue(";
|
||||
Strm << getTypeString(V);
|
||||
Strm << (const void*) &val;
|
||||
Strm << ");";
|
||||
|
||||
// We really don't care about protected types here (ROOT-7426)
|
||||
AccessCtrlRAII_t AccessCtrlRAII(*Interp);
|
||||
clang::DiagnosticsEngine& Diag = Interp->getDiagnostics();
|
||||
bool oldSuppDiags = Diag.getSuppressAllDiagnostics();
|
||||
Diag.setSuppressAllDiagnostics(true);
|
||||
Interp->evaluate(Strm.str(), printValueV);
|
||||
Diag.setSuppressAllDiagnostics(oldSuppDiags);
|
||||
}
|
||||
|
||||
if (!printValueV.isValid() || printValueV.getPtr() == nullptr) {
|
||||
// That didn't work. We probably diagnosed the issue as part of evaluate().
|
||||
cling::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.");
|
||||
|
||||
return "ERROR in cling::executePrintValue(): missing value string.";
|
||||
}
|
||||
|
||||
return *(std::string *) printValueV.getPtr();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
static std::string printAddress(const void* Ptr, const char Prfx = 0) {
|
||||
if (!Ptr)
|
||||
@ -367,80 +223,6 @@ static std::string printAddress(const void* Ptr, const char Prfx = 0) {
|
||||
return Strm.str();
|
||||
}
|
||||
|
||||
static std::string printUnpackedClingValue(const Value &V) {
|
||||
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(), '@');
|
||||
} 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());
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
|
||||
// General fallback - prints the address
|
||||
@ -614,7 +396,7 @@ namespace cling {
|
||||
std::string printValue(const std::string *val) {
|
||||
return "\"" + *val + "\"";
|
||||
}
|
||||
|
||||
|
||||
static std::string quoteString(std::string Str, const char Prefix) {
|
||||
// No wrap
|
||||
if (!Prefix)
|
||||
@ -681,7 +463,7 @@ namespace cling {
|
||||
Result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * N);
|
||||
char *ResultPtr = &Result[0],
|
||||
*ResultEnd = ResultPtr + Result.size();
|
||||
|
||||
|
||||
CharTraits<T>::convert(&Bgn, End, &ResultPtr, ResultEnd, lenientConversion);
|
||||
Result.resize(ResultPtr - &Result[0]);
|
||||
return quoteString(std::move(Result), Prfx);
|
||||
@ -791,7 +573,256 @@ namespace cling {
|
||||
std::string printValue(const wchar_t *Val) {
|
||||
return toUnicode(Val, 'L', 'x');
|
||||
}
|
||||
} // end namespace cling
|
||||
|
||||
|
||||
template<typename T, bool> struct ExecutePrintValue;
|
||||
|
||||
template<typename T>
|
||||
struct ExecutePrintValue<T, false> {
|
||||
std::string operator()(const Value &V, const T &val) {
|
||||
Interpreter *Interp = V.getInterpreter();
|
||||
Value printValueV;
|
||||
|
||||
{
|
||||
// Use an llvm::raw_ostream to prepend '0x' in front of the pointer value.
|
||||
|
||||
cling::ostrstream Strm;
|
||||
Strm << "cling::printValue(";
|
||||
Strm << getTypeString(V);
|
||||
Strm << (const void*) &val;
|
||||
Strm << ");";
|
||||
|
||||
// We really don't care about protected types here (ROOT-7426)
|
||||
AccessCtrlRAII_t AccessCtrlRAII(*Interp);
|
||||
clang::DiagnosticsEngine& Diag = Interp->getDiagnostics();
|
||||
bool oldSuppDiags = Diag.getSuppressAllDiagnostics();
|
||||
Diag.setSuppressAllDiagnostics(true);
|
||||
Interp->evaluate(Strm.str(), printValueV);
|
||||
Diag.setSuppressAllDiagnostics(oldSuppDiags);
|
||||
}
|
||||
|
||||
if (printValueV.isValid() && printValueV.getPtr())
|
||||
return *(std::string *) printValueV.getPtr();
|
||||
|
||||
// That didn't work. We probably diagnosed the issue as part of evaluate().
|
||||
cling::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.");
|
||||
|
||||
return "ERROR in cling::executePrintValue(): missing value string.";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct ExecutePrintValue<T, true> {
|
||||
std::string operator()(const Value &V, const T &val) {
|
||||
return printValue(&val);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::string executePrintValue(const Value &V, const T &val) {
|
||||
return ExecutePrintValue<T, HasExplicitPrintValue<const T>::value>()(V, val);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
static std::string printUnpackedClingValue(const Value &V) {
|
||||
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(), '@');
|
||||
} 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*, false>()(V, V.getPtr());
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
// cling::Value
|
||||
std::string printValue(const Value *value) {
|
||||
cling::smallstream strm;
|
||||
|
Loading…
x
Reference in New Issue
Block a user