diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 970e0245417b5..3be29bd75cfca 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -149,6 +149,8 @@ class Interpreter { CompilerInstance *getCompilerInstance(); llvm::Expected getExecutionEngine(); + Sema &getSema() const; + llvm::Expected Parse(llvm::StringRef Code); llvm::Error Execute(PartialTranslationUnit &T); llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr); diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h index d70e8f8719026..186299a84db44 100644 --- a/clang/include/clang/Interpreter/Value.h +++ b/clang/include/clang/Interpreter/Value.h @@ -35,6 +35,7 @@ #include "llvm/Support/Compiler.h" #include +#include // NOTE: Since the REPL itself could also include this runtime, extreme caution // should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW @@ -117,6 +118,8 @@ class REPL_EXTERNAL_VISIBILITY Value { Value &operator=(Value &&RHS) noexcept; ~Value(); + std::string printValueInternal() const; + void printType(llvm::raw_ostream &Out) const; void printData(llvm::raw_ostream &Out) const; void print(llvm::raw_ostream &Out) const; @@ -126,7 +129,7 @@ class REPL_EXTERNAL_VISIBILITY Value { ASTContext &getASTContext(); const ASTContext &getASTContext() const; Interpreter &getInterpreter(); - const Interpreter &getInterpreter() const; + Interpreter &getInterpreter() const; QualType getType() const; bool isValid() const { return ValueKind != K_Unspecified; } @@ -136,6 +139,8 @@ class REPL_EXTERNAL_VISIBILITY Value { Kind getKind() const { return ValueKind; } void setKind(Kind K) { ValueKind = K; } void setOpaqueType(void *Ty) { OpaqueType = Ty; } + void setName(std::string name) { Name = name; } + std::string getName() const { return Name; } void *getPtr() const; void setPtr(void *Ptr) { Data.m_Ptr = Ptr; } @@ -197,6 +202,7 @@ class REPL_EXTERNAL_VISIBILITY Value { Storage Data; Kind ValueKind = K_Unspecified; bool IsManuallyAlloc = false; + std::string Name; }; template <> inline void *Value::as() const { diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 9065f998f73c4..ea00bdc80f595 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -20,6 +20,7 @@ add_clang_library(clangInterpreter Interpreter.cpp InterpreterUtils.cpp Value.cpp + ValuePrinter.cpp DEPENDS intrinsics_gen diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h index e13b74c7f6594..c9acc59b1ed60 100644 --- a/clang/lib/Interpreter/IncrementalParser.h +++ b/clang/lib/Interpreter/IncrementalParser.h @@ -67,6 +67,7 @@ class IncrementalParser { CompilerInstance *getCI() { return CI.get(); } CodeGenerator *getCodeGen() const; + Parser &getParser() const { return *P; } /// Parses incremental input by creating an in-memory file. ///\returns a \c PartialTranslationUnit which holds information about the diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index cf31456b6950a..aa6f6657670bc 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -336,6 +336,8 @@ llvm::Expected Interpreter::getExecutionEngine() { return IncrExecutor->GetExecutionEngine(); } +Sema &Interpreter::getSema() const { return getCompilerInstance()->getSema(); } + ASTContext &Interpreter::getASTContext() { return getCompilerInstance()->getASTContext(); } @@ -427,7 +429,7 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { } llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) { - + std::string name = Code.str(); auto PTU = Parse(Code); if (!PTU) return PTU.takeError(); @@ -437,10 +439,12 @@ llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) { if (LastValue.isValid()) { if (!V) { + LastValue.setName(name); LastValue.dump(); LastValue.clear(); - } else + } else { *V = std::move(LastValue); + } } return llvm::Error::success(); } diff --git a/clang/lib/Interpreter/InterpreterUtils.cpp b/clang/lib/Interpreter/InterpreterUtils.cpp index c19cf6aa3156c..cba64add8c54a 100644 --- a/clang/lib/Interpreter/InterpreterUtils.cpp +++ b/clang/lib/Interpreter/InterpreterUtils.cpp @@ -102,7 +102,7 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name, return nullptr; } -std::string GetFullTypeName(ASTContext &Ctx, QualType QT) { +std::string GetFullTypeName(const ASTContext &Ctx, QualType QT) { PrintingPolicy Policy(Ctx.getPrintingPolicy()); Policy.SuppressScope = false; Policy.AnonymousTagLocations = false; diff --git a/clang/lib/Interpreter/InterpreterUtils.h b/clang/lib/Interpreter/InterpreterUtils.h index 8df158c17d491..5699060754fb4 100644 --- a/clang/lib/Interpreter/InterpreterUtils.h +++ b/clang/lib/Interpreter/InterpreterUtils.h @@ -48,7 +48,7 @@ NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name, NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name, const DeclContext *Within); -std::string GetFullTypeName(ASTContext &Ctx, QualType QT); +std::string GetFullTypeName(const ASTContext &Ctx, QualType QT); } // namespace clang #endif diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp index eb2ce9c9fd330..ca11093481be8 100644 --- a/clang/lib/Interpreter/Value.cpp +++ b/clang/lib/Interpreter/Value.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Interpreter/Value.h" +#include "InterpreterUtils.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" #include "clang/Interpreter/Interpreter.h" @@ -222,6 +223,7 @@ void Value::clear() { OpaqueType = nullptr; Interp = nullptr; IsManuallyAlloc = false; + Name = ""; } Value::~Value() { clear(); } @@ -241,7 +243,7 @@ Interpreter &Value::getInterpreter() { return *Interp; } -const Interpreter &Value::getInterpreter() const { +Interpreter &Value::getInterpreter() const { assert(Interp != nullptr && "Can't get interpreter from a default constructed value"); return *Interp; @@ -256,14 +258,17 @@ const ASTContext &Value::getASTContext() const { void Value::dump() const { print(llvm::outs()); } void Value::printType(llvm::raw_ostream &Out) const { - Out << "Not implement yet.\n"; + Out << "(" << GetFullTypeName(getASTContext(), getType()) << ")\n"; } + void Value::printData(llvm::raw_ostream &Out) const { - Out << "Not implement yet.\n"; + Out << printValueInternal() << "\n"; } + void Value::print(llvm::raw_ostream &Out) const { assert(OpaqueType != nullptr && "Can't print default Value"); - Out << "Not implement yet.\n"; + Out << "(" << GetFullTypeName(getASTContext(), getType()) << ")" << ' ' + << printValueInternal() << "\n"; } } // namespace clang diff --git a/clang/lib/Interpreter/ValuePrinter.cpp b/clang/lib/Interpreter/ValuePrinter.cpp new file mode 100644 index 0000000000000..84269eff75589 --- /dev/null +++ b/clang/lib/Interpreter/ValuePrinter.cpp @@ -0,0 +1,751 @@ +//===--- ValuePrinter.cpp - Value Printer -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements some value printer functions for clang-repl. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Interpreter/Interpreter.h" +#include "clang/Interpreter/Value.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedAttr.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_os_ostream.h" +#include "llvm/Support/raw_ostream.h" + +#include "InterpreterUtils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace clang { + +std::string printAddress(const void *Ptr, const char Prefix = 0) { + if (!Ptr) { + return "nullptr"; + } + std::ostringstream ostr; + if (Prefix) { + ostr << Prefix; + } + ostr << Ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const void *ptr) { return printAddress(ptr, '@'); } + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const void **ptr) { return printAddress(*ptr); } + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const bool *ptr) { return *ptr ? "true" : "false"; } + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const char *ptr) { + std::string value = "'"; + switch (*ptr) { + case '\t': + value += "\\t"; + break; + case '\n': + value += "\\n"; + break; + case '\r': + value += "\\r"; + break; + case '\f': + value += "\\f"; + break; + case '\v': + value += "\\v"; + break; + default: + value += *ptr; + } + value += "'"; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const signed char *ptr) { + std::string value = "'"; + switch (*ptr) { + case '\t': + value += "\\t"; + break; + case '\n': + value += "\\n"; + break; + case '\r': + value += "\\r"; + break; + case '\f': + value += "\\f"; + break; + case '\v': + value += "\\v"; + break; + default: + value += *ptr; + } + value += "'"; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const unsigned char *ptr) { + std::string value = "'"; + switch (*ptr) { + case '\t': + value += "\\t"; + break; + case '\n': + value += "\\n"; + break; + case '\r': + value += "\\r"; + break; + case '\f': + value += "\\f"; + break; + case '\v': + value += "\\v"; + break; + default: + value += *ptr; + } + value += "'"; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const wchar_t *ptr) { + std::string value = "'"; + switch (*ptr) { + case '\t': + value += "\\t"; + break; + case '\n': + value += "\\n"; + break; + case '\r': + value += "\\r"; + break; + case '\f': + value += "\\f"; + break; + case '\v': + value += "\\v"; + break; + default: + value += *ptr; + } + value += "'"; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const char16_t *ptr) { + std::string value = "'"; + switch (*ptr) { + case '\t': + value += "\\t"; + break; + case '\n': + value += "\\n"; + break; + case '\r': + value += "\\r"; + break; + case '\f': + value += "\\f"; + break; + case '\v': + value += "\\v"; + break; + default: + value += *ptr; + } + value += "'"; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const char32_t *ptr) { + std::string value = "'"; + switch (*ptr) { + case '\t': + value += "\\t"; + break; + case '\n': + value += "\\n"; + break; + case '\r': + value += "\\r"; + break; + case '\f': + value += "\\f"; + break; + case '\v': + value += "\\v"; + break; + default: + value += *ptr; + } + value += "'"; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const unsigned short *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const short *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const unsigned int *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const int *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const unsigned long *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const long *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const unsigned long long *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const long long *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const float *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const double *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const long double *ptr) { + std::ostringstream ostr; + ostr << *ptr; + return ostr.str(); +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(char *ptr, bool seq) { + std::string value = "\""; + char *p = ptr; + while (*p != '\0') { + value += *p; + p++; + } + value += "\""; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(signed char *ptr, bool seq) { + std::string value = "\""; + signed char *p = ptr; + while (*p != '\0') { + value += *p; + p++; + } + value += "\""; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(unsigned char *ptr, bool seq) { + std::string value = "\""; + unsigned char *p = ptr; + while (*p != '\0') { + value += *p; + p++; + } + value += "\""; + return value; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(wchar_t *ptr, bool seq) { + std::wstring value; + wchar_t *p = ptr; + while (*p != '\0') { + value += *p; + p++; + } + std::wstring_convert, wchar_t> converter; + return "\"" + converter.to_bytes(value) + "\""; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(char16_t *ptr, bool seq) { + std::u16string value; + char16_t *p = ptr; + while (*p != '\0') { + value += *p; + p++; + } + std::wstring_convert, char16_t> converter; + return "\"" + converter.to_bytes(value) + "\""; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(char32_t *ptr, bool seq) { + std::u32string value; + char32_t *p = ptr; + while (*p != '\0') { + value += *p; + p++; + } + std::wstring_convert, char32_t> converter; + return "\"" + converter.to_bytes(value) + "\""; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const std::string *ptr) { return "\"" + *ptr + "\""; } + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const std::wstring *ptr) { + std::wstring_convert, wchar_t> converter; + return "\"" + converter.to_bytes(*ptr) + "\""; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const std::u16string *ptr) { + std::wstring_convert, char16_t> converter; + return "\"" + converter.to_bytes(*ptr) + "\""; +} + +REPL_EXTERNAL_VISIBILITY +std::string printValue(const std::u32string *ptr) { + std::wstring_convert, char32_t> converter; + return "\"" + converter.to_bytes(*ptr) + "\""; +} + +std::string printBuiltinTypeValue(const Value &V, BuiltinType::Kind Kind) { + switch (Kind) { + case BuiltinType::Bool: + return V.convertTo() ? "true" : "false"; + case BuiltinType::Char_U: + case BuiltinType::UChar: { + auto val = V.convertTo(); + return printValue(&val); + } + case BuiltinType::Char_S: + case BuiltinType::SChar: { + auto val = V.convertTo(); + return printValue(&val); + } + case BuiltinType::WChar_S: { + auto val = V.convertTo(); + return printValue(&val); + } + case BuiltinType::Char16: { + auto val = V.convertTo(); + return printValue(&val); + } + case BuiltinType::Char32: { + auto val = V.convertTo(); + return printValue(&val); + } + case BuiltinType::UShort: + return std::to_string(V.convertTo()); + case BuiltinType::Short: + return std::to_string(V.convertTo()); + case BuiltinType::UInt: + return std::to_string(V.convertTo()); + case BuiltinType::Int: + return std::to_string(V.convertTo()); + case BuiltinType::ULong: + return std::to_string(V.convertTo()); + case BuiltinType::Long: + return std::to_string(V.convertTo()); + case BuiltinType::ULongLong: + return std::to_string(V.convertTo()); + case BuiltinType::LongLong: + return std::to_string(V.convertTo()); + case BuiltinType::Float: + return std::to_string(V.convertTo()); + case BuiltinType::Double: + return std::to_string(V.convertTo()); + case BuiltinType::LongDouble: + return std::to_string(V.convertTo()); + default: + break; + } + return ""; +} + +std::string printValueByPtr(void *Ptr, QualType Type, uint64_t Offset) { + if (const BuiltinType *bt = + llvm::dyn_cast(Type.getCanonicalType().getTypePtr())) { + std::ostringstream os; + Ptr = (void *)((char *)Ptr + Offset); + switch (bt->getKind()) { + case BuiltinType::Bool: + return printValue((bool *)Ptr); + case BuiltinType::Char_U: + return printValue((unsigned char *)Ptr); + case BuiltinType::UChar: + return printValue((unsigned char *)Ptr); + case BuiltinType::Char_S: + return printValue((signed char *)Ptr); + case BuiltinType::SChar: + return printValue((signed char *)Ptr); + case BuiltinType::WChar_S: + return printValue((wchar_t *)Ptr); + case BuiltinType::Char16: + return printValue((char16_t *)Ptr); + case BuiltinType::Char32: + return printValue((char32_t *)Ptr); + case BuiltinType::UShort: + return printValue((unsigned short *)Ptr); + case BuiltinType::Short: + return printValue((short *)Ptr); + case BuiltinType::UInt: + return printValue((unsigned int *)Ptr); + case BuiltinType::Int: + return printValue((int *)Ptr); + case BuiltinType::ULong: + return printValue((unsigned long *)Ptr); + case BuiltinType::Long: + return printValue((long *)Ptr); + case BuiltinType::ULongLong: + return printValue((unsigned long long *)Ptr); + case BuiltinType::LongLong: + return printValue((long long *)Ptr); + case BuiltinType::Float: + return printValue((float *)Ptr); + case BuiltinType::Double: + return printValue((double *)Ptr); + case BuiltinType::LongDouble: + return printValue((long double *)Ptr); + default: + break; + } + } + if (!Ptr) { + return "nullptr"; + } + return printAddress(Ptr, '@'); +} + +std::string printEnumValue(const Value &V, QualType Type) { + std::ostringstream ostr; + const ASTContext &C = V.getASTContext(); + const EnumType *EnumTy = Type->getAs(); + assert(EnumTy && "printEnumValue invoked for a non enum type"); + EnumDecl *decl = EnumTy->getDecl(); + uint64_t value = V.getULongLong(); + bool isFirst = true; + llvm::APSInt valAsAPSInt = C.MakeIntValue(value, Type); + for (EnumDecl::enumerator_iterator I = decl->enumerator_begin(), + E = decl->enumerator_end(); + I != E; ++I) { + if (I->getInitVal() == valAsAPSInt) { + if (!isFirst) { + ostr << " ? "; + } + ostr << "(" << I->getQualifiedNameAsString() << ")"; + isFirst = false; + } + } + ostr << " : " << decl->getIntegerType().getAsString() << " " + << llvm::toString(valAsAPSInt, 10); + return ostr.str(); +} + +std::string printArrayValue(const Value &V, QualType Type) { + if (const ArrayType *decl = Type->getAsArrayTypeUnsafe()) { + if (const ConstantArrayType *cdecl = + dyn_cast(decl)) { + QualType elemType = decl->getElementType(); + uint64_t size = cdecl->getSize().getZExtValue(); + std::ostringstream ostr; + ostr << "{ "; + const ASTContext &C = V.getASTContext(); + uint64_t elemSize = C.getTypeSize(elemType) / 8; + for (uint64_t i = 0; i < size; i++) { + ostr << printValueByPtr(V.getPtr(), elemType, i * elemSize); + if (i != size - 1) { + ostr << ", "; + } + } + ostr << " }"; + return ostr.str(); + } + } + + if (Type->isPointerType()) { + QualType elemType = Type->getPointeeType(); + if (elemType->isPointerType()) { + return ""; + } + const BuiltinType *bt = llvm::dyn_cast(elemType.getTypePtr()); + BuiltinType::Kind Kind = bt->getKind(); + switch (Kind) { + case BuiltinType::Char_U: + return printValue((unsigned char *)V.getPtr(), true); + case BuiltinType::UChar: + return printValue((unsigned char *)V.getPtr(), true); + case BuiltinType::Char_S: + return printValue((signed char *)V.getPtr(), true); + case BuiltinType::SChar: + return printValue((signed char *)V.getPtr(), true); + case BuiltinType::WChar_S: + return printValue((wchar_t *)V.getPtr(), true); + case BuiltinType::Char16: + return printValue((char16_t *)V.getPtr(), true); + case BuiltinType::Char32: + return printValue((char32_t *)V.getPtr(), true); + default: + break; + } + } + return ""; +} + +std::string printStringValue(const Value &V, QualType Type) { + const ASTContext &C = V.getASTContext(); + std::string typeStr = GetFullTypeName(C, Type); + std::string stringVal = ""; + if (typeStr == "std::string") + stringVal = printValue((std::string *)V.getPtr()); + if (typeStr == "std::wstring") + stringVal = printValue((std::wstring *)V.getPtr()); + if (typeStr == "std::u16string") + stringVal = printValue((std::u16string *)V.getPtr()); + if (typeStr == "std::u32string") + stringVal = printValue((std::u32string *)V.getPtr()); + return stringVal; +} + +template std::string printVectorValue(void *ptr) { + std::vector *vecPtr = static_cast *>(ptr); + std::ostringstream ostr; + ostr << "{ "; + for (uint64_t i = 0; i < vecPtr->size(); i++) { + ostr << (*vecPtr)[i]; + if (i != vecPtr->size() - 1) { + ostr << ", "; + } + } + ostr << " }"; + return ostr.str(); +} + +std::string printRecordValue(const Value &V, const CXXRecordDecl *RecordDecl) { + const ASTContext &C = V.getASTContext(); + Sema &S = V.getInterpreter().getSema(); + std::string Name = V.getName(); + NamedDecl *namedDecl = LookupNamed(S, Name, nullptr); + + ValueDecl *valueDecl = llvm::dyn_cast(namedDecl); + if (valueDecl != nullptr) { + QualType Type = valueDecl->getType(); + std::string str = printStringValue(V, Type); + if (!str.empty()) { + return str; + } + + if (llvm::StringRef(GetFullTypeName(C, Type)).starts_with("std::vector")) { + const auto *specDecl = + dyn_cast(RecordDecl); + if (specDecl) { + const TemplateArgumentList &tplArgs = specDecl->getTemplateArgs(); + assert(tplArgs.size() != 0); + const TemplateArgument &tplArg = tplArgs[0]; + if (tplArg.getKind() == TemplateArgument::Type) { + if (const BuiltinType *BT = + dyn_cast(tplArg.getAsType().getTypePtr())) { + void *ptr = V.getPtr(); + switch (BT->getKind()) { + case BuiltinType::Bool: + return printVectorValue(ptr); + case BuiltinType::Char_U: + case BuiltinType::UChar: + return printVectorValue(ptr); + case BuiltinType::Char_S: + case BuiltinType::SChar: + return printVectorValue(ptr); + case BuiltinType::WChar_S: + return printVectorValue(ptr); + case BuiltinType::Char16: + return printVectorValue(ptr); + case BuiltinType::Char32: + return printVectorValue(ptr); + case BuiltinType::UShort: + return printVectorValue(ptr); + case BuiltinType::Short: + return printVectorValue(ptr); + case BuiltinType::UInt: + return printVectorValue(ptr); + case BuiltinType::Int: + return printVectorValue(ptr); + case BuiltinType::ULong: + return printVectorValue(ptr); + case BuiltinType::Long: + return printVectorValue(ptr); + case BuiltinType::ULongLong: + return printVectorValue(ptr); + case BuiltinType::LongLong: + return printVectorValue(ptr); + case BuiltinType::Float: + return printVectorValue(ptr); + case BuiltinType::Double: + return printVectorValue(ptr); + case BuiltinType::LongDouble: + return printVectorValue(ptr); + default: + break; + } + } + } + } + + return ""; + } + } + + std::ostringstream values; + auto fields = RecordDecl->fields(); + for (auto I = fields.begin(), E = fields.end(), tmp = I; I != E; + ++I, tmp = I) { + FieldDecl *field = *I; + QualType fieldType = field->getType(); + size_t offset = C.getFieldOffset(field) /* bits */ / 8; + values << field->getNameAsString() << ": " + << printValueByPtr(V.getPtr(), fieldType, offset); + if (++tmp != E) { + values << ", "; + } + } + if (!values.str().empty()) { + return "{ " + values.str() + " }"; + } + return ""; +} + +std::string printUnpackedValue(const Value &V) { + const ASTContext &C = V.getASTContext(); + const QualType Td = V.getType().getDesugaredType(C); + const QualType Ty = Td.getNonReferenceType(); + + if (!V.getPtr()) { + return "nullptr"; + } + if (Ty->isNullPtrType()) { + return "nullptr_t"; + } + if (Ty->isEnumeralType()) { + return printEnumValue(V, Ty); + } + if (CXXRecordDecl *RecordDecl = Ty->getAsCXXRecordDecl()) { + if (RecordDecl->isLambda()) { + return printAddress(V.getPtr(), '@'); + } + std::string str = printRecordValue(V, RecordDecl); + if (!str.empty()) { + return str; + } + } else if (const BuiltinType *BT = llvm::dyn_cast( + Td.getCanonicalType().getTypePtr())) { + BuiltinType::Kind Kind = BT->getKind(); + std::string str = printBuiltinTypeValue(V, Kind); + if (!str.empty()) { + return str; + } + } else { + std::string str = printArrayValue(V, Ty); + if (!str.empty()) { + return str; + } + } + return printAddress(V.getPtr(), '@'); +} + +std::string Value::printValueInternal() const { + return printUnpackedValue(*this); +} + +} // namespace clang