[clang] [PATCH] [clang-repl] Builtin Type printing in ValuePrinter.cpp (PR #88729)

via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 15 06:43:28 PDT 2024


https://github.com/wlonestar updated https://github.com/llvm/llvm-project/pull/88729

>From c953691de3eda4b72e16d215a6a0e5d230742c59 Mon Sep 17 00:00:00 2001
From: wlonestar <68649094+wlonestar at users.noreply.github.com>
Date: Mon, 15 Apr 2024 13:12:55 +0000
Subject: [PATCH 1/2] [PATCH] [clang-repl] Builtin Type printing in
 ValuePrinter.cpp

---
 clang/include/clang/Interpreter/Interpreter.h |   2 +
 clang/include/clang/Interpreter/Value.h       |   8 +-
 clang/lib/Interpreter/CMakeLists.txt          |   1 +
 clang/lib/Interpreter/IncrementalParser.h     |   1 +
 clang/lib/Interpreter/Interpreter.cpp         |   8 +-
 clang/lib/Interpreter/InterpreterUtils.cpp    |   2 +-
 clang/lib/Interpreter/InterpreterUtils.h      |   2 +-
 clang/lib/Interpreter/Value.cpp               |  13 +-
 clang/lib/Interpreter/ValuePrinter.cpp        | 751 ++++++++++++++++++
 9 files changed, 779 insertions(+), 9 deletions(-)
 create mode 100644 clang/lib/Interpreter/ValuePrinter.cpp

diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 970e0245417b51..3be29bd75cfca7 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<llvm::orc::LLJIT &> getExecutionEngine();
 
+  Sema &getSema() const;
+
   llvm::Expected<PartialTranslationUnit &> 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 d70e8f8719026b..186299a84db444 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 <cstdint>
+#include <string>
 
 // 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 9065f998f73c47..ea00bdc80f595d 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 e13b74c7f65948..c9acc59b1ed602 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 cf31456b6950ac..aa6f6657670bca 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -336,6 +336,8 @@ llvm::Expected<llvm::orc::LLJIT &> 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 c19cf6aa3156c9..cba64add8c54a7 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 8df158c17d4919..5699060754fb4d 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 eb2ce9c9fd3302..ca11093481be89 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 00000000000000..19b9dcd3d89504
--- /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 <cassert>
+#include <codecvt>
+#include <cstddef>
+#include <cstdint>
+#include <locale>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+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<std::codecvt_utf8<wchar_t>, 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<std::codecvt_utf8_utf16<char16_t>, 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<std::codecvt_utf8<char32_t>, 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<std::codecvt_utf8<wchar_t>, wchar_t> converter;
+  return "\"" + converter.to_bytes(*ptr) + "\"";
+}
+
+REPL_EXTERNAL_VISIBILITY
+std::string printValue(const std::u16string *ptr) {
+  std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
+  return "\"" + converter.to_bytes(*ptr) + "\"";
+}
+
+REPL_EXTERNAL_VISIBILITY
+std::string printValue(const std::u32string *ptr) {
+  std::wstring_convert<std::codecvt_utf8_utf16<char32_t>, 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<bool>() ? "true" : "false";
+  case BuiltinType::Char_U:
+  case BuiltinType::UChar: {
+    auto val = V.convertTo<unsigned char>();
+    return printValue(&val);
+  }
+  case BuiltinType::Char_S:
+  case BuiltinType::SChar: {
+    auto val = V.convertTo<signed char>();
+    return printValue(&val);
+  }
+  case BuiltinType::WChar_S: {
+    auto val = V.convertTo<wchar_t>();
+    return printValue(&val);
+  }
+  case BuiltinType::Char16: {
+    auto val = V.convertTo<char16_t>();
+    return printValue(&val);
+  }
+  case BuiltinType::Char32: {
+    auto val = V.convertTo<char32_t>();
+    return printValue(&val);
+  }
+  case BuiltinType::UShort:
+    return std::to_string(V.convertTo<unsigned short>());
+  case BuiltinType::Short:
+    return std::to_string(V.convertTo<short>());
+  case BuiltinType::UInt:
+    return std::to_string(V.convertTo<unsigned int>());
+  case BuiltinType::Int:
+    return std::to_string(V.convertTo<int>());
+  case BuiltinType::ULong:
+    return std::to_string(V.convertTo<unsigned long>());
+  case BuiltinType::Long:
+    return std::to_string(V.convertTo<long>());
+  case BuiltinType::ULongLong:
+    return std::to_string(V.convertTo<unsigned long long>());
+  case BuiltinType::LongLong:
+    return std::to_string(V.convertTo<long long>());
+  case BuiltinType::Float:
+    return std::to_string(V.convertTo<float>());
+  case BuiltinType::Double:
+    return std::to_string(V.convertTo<double>());
+  case BuiltinType::LongDouble:
+    return std::to_string(V.convertTo<long double>());
+  default:
+    break;
+  }
+  return "";
+}
+
+std::string printValueByPtr(void *Ptr, QualType Type, uint64_t Offset) {
+  if (const BuiltinType *bt =
+          llvm::dyn_cast<BuiltinType>(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<EnumType>();
+  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<const ConstantArrayType>(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<BuiltinType>(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 <typename T> std::string printVectorValue(void *ptr) {
+  std::vector<T> *vecPtr = static_cast<std::vector<T> *>(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<ValueDecl>(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<ClassTemplateSpecializationDecl>(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<BuiltinType>(tplArg.getAsType().getTypePtr())) {
+            void *ptr = V.getPtr();
+            switch (BT->getKind()) {
+            case BuiltinType::Bool:
+              return printVectorValue<bool>(ptr);
+            case BuiltinType::Char_U:
+            case BuiltinType::UChar:
+              return printVectorValue<unsigned char>(ptr);
+            case BuiltinType::Char_S:
+            case BuiltinType::SChar:
+              return printVectorValue<signed char>(ptr);
+            case BuiltinType::WChar_S:
+              return printVectorValue<wchar_t>(ptr);
+            case BuiltinType::Char16:
+              return printVectorValue<char16_t>(ptr);
+            case BuiltinType::Char32:
+              return printVectorValue<char32_t>(ptr);
+            case BuiltinType::UShort:
+              return printVectorValue<unsigned short>(ptr);
+            case BuiltinType::Short:
+              return printVectorValue<short>(ptr);
+            case BuiltinType::UInt:
+              return printVectorValue<unsigned int>(ptr);
+            case BuiltinType::Int:
+              return printVectorValue<int>(ptr);
+            case BuiltinType::ULong:
+              return printVectorValue<unsigned long>(ptr);
+            case BuiltinType::Long:
+              return printVectorValue<long>(ptr);
+            case BuiltinType::ULongLong:
+              return printVectorValue<unsigned long long>(ptr);
+            case BuiltinType::LongLong:
+              return printVectorValue<long long>(ptr);
+            case BuiltinType::Float:
+              return printVectorValue<float>(ptr);
+            case BuiltinType::Double:
+              return printVectorValue<double>(ptr);
+            case BuiltinType::LongDouble:
+              return printVectorValue<long double>(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<BuiltinType>(
+                 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

>From 157d1744ece696da80f8562ae537a8e97f27b28b Mon Sep 17 00:00:00 2001
From: wlonestar <68649094+wlonestar at users.noreply.github.com>
Date: Mon, 15 Apr 2024 21:43:21 +0800
Subject: [PATCH 2/2] [clang-repl] fix bugs in method call

---
 clang/lib/Interpreter/ValuePrinter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Interpreter/ValuePrinter.cpp b/clang/lib/Interpreter/ValuePrinter.cpp
index 19b9dcd3d89504..84269eff755893 100644
--- a/clang/lib/Interpreter/ValuePrinter.cpp
+++ b/clang/lib/Interpreter/ValuePrinter.cpp
@@ -633,7 +633,7 @@ std::string printRecordValue(const Value &V, const CXXRecordDecl *RecordDecl) {
           dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl);
       if (specDecl) {
         const TemplateArgumentList &tplArgs = specDecl->getTemplateArgs();
-        assert(tplArgs.size != 0);
+        assert(tplArgs.size() != 0);
         const TemplateArgument &tplArg = tplArgs[0];
         if (tplArg.getKind() == TemplateArgument::Type) {
           if (const BuiltinType *BT =



More information about the cfe-commits mailing list