================
@@ -0,0 +1,504 @@
+//===-- RPCCommon.cpp 
-----------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "RPCCommon.h"
+
+#include "clang/AST/AST.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Lex/Lexer.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+// We intentionally do not generate some classes because they are currently
+// inconvenient, they aren't really used by most consumers, or we're not sure
+// why they exist.
+static constexpr llvm::StringRef DisallowedClasses[] = {
+    "SBCommunication", // This class is pretty much unused by consumers, so we
+                       // skip it.
+    "SBInputReader",   // This class is pretty much unused by consumers, so we
+                       // skip it.
+    "SBCommandPluginInterface", // This class uses virtual functions, and the 
SB
+                                // API should not have those, so we skip this
+                                // class.
+    "SBCommand", // There's nothing too difficult about this one, but many of
+                 // its methods take a SBCommandPluginInterface pointer so
+                 // there's no reason to support this.
+};
+
+// NOTE: In lldb-rpc-gen, we use mangled names when we need to work with
+// functions. We do this because we support many functions that have overloads,
+// and mangled names have no ambiguity which makes it easier to keep track of.
+// This is also possible since the LLDB SB API is stable.
+
+// We intentionally avoid generating certain methods either because they are
+// difficult to support correctly or they aren't really used much from C++.
+// NOTE: These methods are marked as deprecated using LLDB_DEPRECATED.
+// Normally this macro defines to the deprecated annotation, but this
+// functionality is removed in SBDefines.h when generating SWIG bindings which
+// we use for testing. Because of this, there is no annotation for the tool to
+// pick up on so this list will be used while we have this restriction in
+// SBDefines.h.
+static constexpr llvm::StringRef DisallowedMethods[] = {
+    // The threading functionality in SBHostOS is deprecated and thus we do not
+    // generate them. It would be ideal to add the annotations to the methods
+    // and then support not generating deprecated methods. However, without
+    // annotations the generator generates most things correctly. This one is
+    // problematic because it returns a pointer to an "opaque" structure
+    // (thread_t) that is not `void *`, so special casing it is more effort 
than
+    // it's worth.
+    "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS13ThreadCreatedEPKc",
+};
+
+static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = {
+    "SBHostOS",
+    "SBReproducer",
+};
+
+static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = {
+    "SBHostOS",
+    "SBReproducer",
+    "SBStream",
+    "SBProgress",
+};
+
+static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = {
+    "_ZN4lldb6SBData11ReadRawDataERNS_7SBErrorEyPvm",
+    "_ZN4lldb6SBData7SetDataERNS_7SBErrorEPKvmNS_9ByteOrderEh",
+    "_ZN4lldb6SBData20SetDataWithOwnershipERNS_7SBErrorEPKvmNS_9ByteOrderEh",
+    "_ZN4lldb6SBData25CreateDataFromUInt64ArrayENS_9ByteOrderEjPym",
+    "_ZN4lldb6SBData25CreateDataFromUInt32ArrayENS_9ByteOrderEjPjm",
+    "_ZN4lldb6SBData25CreateDataFromSInt64ArrayENS_9ByteOrderEjPxm",
+    "_ZN4lldb6SBData25CreateDataFromSInt32ArrayENS_9ByteOrderEjPim",
+    "_ZN4lldb6SBData25CreateDataFromDoubleArrayENS_9ByteOrderEjPdm",
+    "_ZN4lldb6SBData22SetDataFromUInt64ArrayEPym",
+    "_ZN4lldb6SBData22SetDataFromUInt32ArrayEPjm",
+    "_ZN4lldb6SBData22SetDataFromSInt64ArrayEPxm",
+    "_ZN4lldb6SBData22SetDataFromSInt32ArrayEPim",
+    "_ZN4lldb6SBData22SetDataFromDoubleArrayEPdm",
+    "_ZN4lldb10SBDebugger22GetDefaultArchitectureEPcm",
+    "_ZN4lldb10SBDebugger13DispatchInputEPvPKvm",
+    "_ZN4lldb10SBDebugger13DispatchInputEPKvm",
+    "_ZN4lldb6SBFile4ReadEPhmPm",
+    "_ZN4lldb6SBFile5WriteEPKhmPm",
+    "_ZNK4lldb10SBFileSpec7GetPathEPcm",
+    "_ZN4lldb10SBFileSpec11ResolvePathEPKcPcm",
+    "_ZN4lldb8SBModule10GetVersionEPjj",
+    "_ZN4lldb12SBModuleSpec12SetUUIDBytesEPKhm",
+    "_ZNK4lldb9SBProcess9GetSTDOUTEPcm",
+    "_ZNK4lldb9SBProcess9GetSTDERREPcm",
+    "_ZNK4lldb9SBProcess19GetAsyncProfileDataEPcm",
+    "_ZN4lldb9SBProcess10ReadMemoryEyPvmRNS_7SBErrorE",
+    "_ZN4lldb9SBProcess11WriteMemoryEyPKvmRNS_7SBErrorE",
+    "_ZN4lldb9SBProcess21ReadCStringFromMemoryEyPvmRNS_7SBErrorE",
+    "_ZNK4lldb16SBStructuredData14GetStringValueEPcm",
+    "_ZN4lldb8SBTarget23BreakpointCreateByNamesEPPKcjjRKNS_"
+    "14SBFileSpecListES6_",
+    "_ZN4lldb8SBTarget10ReadMemoryENS_9SBAddressEPvmRNS_7SBErrorE",
+    "_ZN4lldb8SBTarget15GetInstructionsENS_9SBAddressEPKvm",
+    "_ZN4lldb8SBTarget25GetInstructionsWithFlavorENS_9SBAddressEPKcPKvm",
+    "_ZN4lldb8SBTarget15GetInstructionsEyPKvm",
+    "_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm",
+    "_ZN4lldb8SBThread18GetStopDescriptionEPcm",
+    // The below mangled names are used for dummy methods in shell tests
+    // that test the emitters' output. If you're adding any new mangled names
+    // from the actual SB API to this list please add them above.
+    "_ZN4lldb33SBRPC_"
+    "CHECKCONSTCHARPTRPTRWITHLEN27CheckConstCharPtrPtrWithLenEPPKcm",
+    "_ZN4lldb19SBRPC_CHECKARRAYPTR13CheckArrayPtrEPPKcm",
+    "_ZN4lldb18SBRPC_CHECKVOIDPTR12CheckVoidPtrEPvm",
+};
+
+// These methods should take a connection parameter according to our logic in
+// RequiresConnectionParameter() but in the handwritten version they
+// don't take a connection. These methods need to have their implementation
+// changed but for now, we just have an exception list of functions that will
+// never be a given connection parameter.
+//
+// FIXME: Change the implementation of these methods so that they can be given 
a
+// connection parameter.
+static constexpr llvm::StringRef
+    MethodsThatUnconditionallyDoNotNeedConnection[] = {
+        "_ZN4lldb16SBBreakpointNameC1ERNS_8SBTargetEPKc",
+        "_ZN4lldb10SBDebugger7DestroyERS0_",
+        "_ZN4lldb18SBExecutionContextC1ENS_8SBThreadE",
+};
+
+// These classes inherit from rpc::ObjectRef directly (as opposed to
+// rpc::LocalObjectRef). Changing them from ObjectRef to LocalObjectRef is ABI
+// breaking, so we preserve that compatibility here.
+//
+// lldb-rpc-gen emits classes as LocalObjectRefs by default.
+//
+// FIXME: Does it matter which one it emits by default?
+static constexpr llvm::StringRef ClassesThatInheritFromObjectRef[] = {
+    "SBAddress",
+    "SBBreakpointName",
+    "SBCommandInterpreter",
+    "SBCommandReturnObject",
+    "SBError",
+    "SBExecutionContext",
+    "SBExpressionOptions",
+    "SBFileSpec",
+    "SBFileSpecList",
+    "SBFormat",
+    "SBFunction",
+    "SBHistoricalFrame",
+    "SBHistoricalLineEntry",
+    "SBHistoricalLineEntryList",
+    "SBLineEntry",
+    "SBStream",
+    "SBStringList",
+    "SBStructuredData",
+    "SBSymbolContext",
+    "SBSymbolContextList",
+    "SBTypeMember",
+    "SBTypeSummaryOptions",
+    "SBValueList",
+};
+
+QualType lldb_rpc_gen::GetUnderlyingType(QualType T) {
+  QualType UnderlyingType;
+  if (T->isPointerType())
+    UnderlyingType = T->getPointeeType();
+  else if (T->isReferenceType())
+    UnderlyingType = T.getNonReferenceType();
+  else
+    UnderlyingType = T;
+
+  return UnderlyingType;
+}
+
+QualType lldb_rpc_gen::GetUnqualifiedUnderlyingType(QualType T) {
+  return GetUnderlyingType(T).getUnqualifiedType();
+}
+
+std::string lldb_rpc_gen::GetMangledName(ASTContext &Context,
+                                         CXXMethodDecl *MDecl) {
+  std::string Mangled;
+  llvm::raw_string_ostream MangledStream(Mangled);
+
+  GlobalDecl GDecl;
+  if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(MDecl))
+    GDecl = GlobalDecl(CtorDecl, Ctor_Complete);
+  else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(MDecl))
+    GDecl = GlobalDecl(DtorDecl, Dtor_Deleting);
+  else
+    GDecl = GlobalDecl(MDecl);
+
+  MangleContext *MC = Context.createMangleContext();
+  MC->mangleName(GDecl, MangledStream);
+  return Mangled;
+}
+
+static auto CheckTypeForLLDBPrivate = [](const Type *Ty) {};
+bool lldb_rpc_gen::TypeIsFromLLDBPrivate(QualType T) {
+  CheckTypeForLLDBPrivate = { if (!Ty) return false;
+  const auto *CXXRDecl = Ty->getAsCXXRecordDecl();
+  if (!CXXRDecl)
+    return false;
+  const auto *NSDecl =
+      llvm::dyn_cast<NamespaceDecl>(CXXRDecl->getDeclContext());
+  if (!NSDecl)
+    return false;
+  return NSDecl->getName() == "lldb_private";
+};
+
+// First, get the underlying type (remove qualifications and strip off any
+// pointers/references). Then we'll need to desugar this type. This will
+// remove things like typedefs, so instead of seeing "lldb::DebuggerSP" we'll
+// actually see something like "std::shared_ptr<lldb_private::Debugger>".
+QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T);
+const Type *DesugaredType =
+    UnqualifiedUnderlyingType->getUnqualifiedDesugaredType();
+assert(DesugaredType && "DesugaredType from a valid Type is nullptr!");
+
+// Check the type itself.
+if (CheckTypeForLLDBPrivate(DesugaredType))
+  return true;
+
+// If that didn't work, it's possible that the type has a template argument
+// that is an lldb_private type.
+if (const auto *TemplateSDecl =
+        llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+            DesugaredType->getAsCXXRecordDecl())) {
+  for (const TemplateArgument &TA :
+       TemplateSDecl->getTemplateArgs().asArray()) {
+    if (TA.getKind() != TemplateArgument::Type)
+      continue;
+    if (CheckTypeForLLDBPrivate(TA.getAsType().getTypePtr()))
+      return true;
+  }
+}
+return false;
+}
+
+bool lldb_rpc_gen::TypeIsSBClass(QualType T) {
+  QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T);
+  const auto *CXXRDecl = UnqualifiedUnderlyingType->getAsCXXRecordDecl();
+  if (!CXXRDecl)
+    return false; // SB Classes are always C++ classes
+
+  return CXXRDecl->getName().starts_with("SB");
+}
+
+bool lldb_rpc_gen::TypeIsConstCharPtr(QualType T) {
+  if (!T->isPointerType())
+    return false;
+
+  QualType UnderlyingType = T->getPointeeType();
+  if (!UnderlyingType.isConstQualified())
+    return false;
+
+  // FIXME: We should be able to do `UnderlyingType->isCharType` but that will
+  // return true for `const uint8_t *` since that is effectively an unsigned
+  // char pointer. We currently do not support pointers other than `const char
+  // *` and `const char **`.
+  return UnderlyingType->isSpecificBuiltinType(BuiltinType::Char_S) ||
+         UnderlyingType->isSpecificBuiltinType(BuiltinType::SChar);
+}
+
+bool lldb_rpc_gen::TypeIsConstCharPtrPtr(QualType T) {
+  if (!T->isPointerType())
+    return false;
+
+  return TypeIsConstCharPtr(T->getPointeeType());
+}
+
+bool lldb_rpc_gen::TypeIsDisallowedClass(QualType T) {
+  QualType UUT = GetUnqualifiedUnderlyingType(T);
+  const auto *CXXRDecl = UUT->getAsCXXRecordDecl();
+  if (!CXXRDecl)
+    return false;
+
+  llvm::StringRef DeclName = CXXRDecl->getName();
+  for (const llvm::StringRef DisallowedClass : DisallowedClasses)
+    if (DeclName == DisallowedClass)
+      return true;
+  return false;
+}
+
+bool lldb_rpc_gen::TypeIsCallbackFunctionPointer(QualType T) {
+  return T->isFunctionPointerType();
+}
+
+bool lldb_rpc_gen::MethodIsDisallowed(ASTContext &Context,
+                                      CXXMethodDecl *MDecl) {
+  std::string MangledName = lldb_rpc_gen::GetMangledName(Context, MDecl);
+  if (llvm::is_contained(DisallowedMethods, MangledName))
+    return true;
+
+  return MDecl->isDeprecatedInAnyTargetPlatform();
+}
+
+bool lldb_rpc_gen::HasCallbackParameter(CXXMethodDecl *MDecl) {
+  bool HasCallbackParameter = false;
+  bool HasBatonParameter = false;
+  auto End = MDecl->parameters().end();
+  for (auto Iter = MDecl->parameters().begin(); Iter != End; Iter++) {
+    if ((*Iter)->getType()->isFunctionPointerType())
+      HasCallbackParameter = true;
+    else if ((*Iter)->getType()->isVoidPointerType())
+      HasBatonParameter = true;
+  }
+
+  return HasCallbackParameter && HasBatonParameter;
+}
+
+// FIXME: Find a better way to do this. Here is why it is written this way:
+// By the time we have already created a `Method` object, we have extracted the
+// `QualifiedName` and the relevant QualTypes for parameters/return types, many
+// of which contains "lldb::" in them. To change it in a way that would be
+// friendly to liblldbrpc, we would need to have a way of replacing that
+// namespace at the time of creating a Method, and only for liblldbrpc methods.
+// IMO this would complicate Method more than what I'm doing here, and not
+// necessarily for any more benefit.
+// In clang-tools-extra, there is a ChangeNamespaces tool which tries to do
+// something similar to this. It also operates primarily on string replacement,
+// but uses more sophisticated clang tooling to do so.
+// For now, this will do what we need it to do.
+std::string
+lldb_rpc_gen::ReplaceLLDBNamespaceWithRPCNamespace(std::string Name) {
+  auto Pos = Name.find("lldb::");
+  while (Pos != std::string::npos) {
+    constexpr size_t SizeOfLLDBNamespace = 6;
+    Name.replace(Pos, SizeOfLLDBNamespace, "lldb_rpc::");
+    Pos = Name.find("lldb::");
----------------
DavidSpickett wrote:

const char* lldb_namespace = "lldb::";
auto Pos = Name.find(lldb_namespace);

Then reuse the string later.

This one's pretty hard to mistake but in general, repeating a string is asking 
for typos.

https://github.com/llvm/llvm-project/pull/138031
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to