mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 17:45:07 +08:00
[LLDB][NativePDB] Create functions with mangled name (#149701)
Before, functions created using the NativePDB plugin would not know about their mangled name. This showed when printing a stacktrace. There, only the function name was shown. For https://github.com/llvm/llvm-project/issues/143149, the mangled function name is required to separate different parts. This PR adds that name if available. The Clang AST nodes also take in a mangled name, which was previously unset. I don't think this unblocks anything further, because Clang can mangle the function anyway.
This commit is contained in:
@@ -38,16 +38,18 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
|
||||
TypeIndex func_type_index,
|
||||
clang::FunctionDecl *&function_decl,
|
||||
lldb::opaque_compiler_type_t parent_ty,
|
||||
llvm::StringRef proc_name, CompilerType func_ct)
|
||||
llvm::StringRef proc_name, ConstString mangled_name,
|
||||
CompilerType func_ct)
|
||||
: m_index(m_index), m_clang(m_clang), func_type_index(func_type_index),
|
||||
function_decl(function_decl), parent_ty(parent_ty),
|
||||
proc_name(proc_name), func_ct(func_ct) {}
|
||||
proc_name(proc_name), mangled_name(mangled_name), func_ct(func_ct) {}
|
||||
PdbIndex &m_index;
|
||||
TypeSystemClang &m_clang;
|
||||
TypeIndex func_type_index;
|
||||
clang::FunctionDecl *&function_decl;
|
||||
lldb::opaque_compiler_type_t parent_ty;
|
||||
llvm::StringRef proc_name;
|
||||
ConstString mangled_name;
|
||||
CompilerType func_ct;
|
||||
|
||||
llvm::Error visitKnownMember(CVMemberRecord &cvr,
|
||||
@@ -87,8 +89,7 @@ struct CreateMethodDecl : public TypeVisitorCallbacks {
|
||||
bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
|
||||
MethodOptions::CompilerGenerated;
|
||||
function_decl = m_clang.AddMethodToCXXRecordType(
|
||||
parent_ty, proc_name,
|
||||
/*asm_label=*/{}, func_ct, /*access=*/access_type,
|
||||
parent_ty, proc_name, mangled_name, func_ct, /*access=*/access_type,
|
||||
/*is_virtual=*/is_virtual, /*is_static=*/is_static,
|
||||
/*is_inline=*/false, /*is_explicit=*/false,
|
||||
/*is_attr_used=*/false, /*is_artificial=*/is_artificial);
|
||||
@@ -892,6 +893,10 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
|
||||
tag_record = CVTagRecord::create(index.tpi().getType(*eti)).asTag();
|
||||
}
|
||||
}
|
||||
|
||||
ConstString mangled_name(
|
||||
pdb->FindMangledFunctionName(func_id).value_or(llvm::StringRef()));
|
||||
|
||||
if (!tag_record.FieldList.isSimple()) {
|
||||
CVType field_list_cvt = index.tpi().getType(tag_record.FieldList);
|
||||
FieldListRecord field_list;
|
||||
@@ -899,15 +904,15 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id,
|
||||
field_list_cvt, field_list))
|
||||
llvm::consumeError(std::move(error));
|
||||
CreateMethodDecl process(index, m_clang, func_ti, function_decl,
|
||||
parent_opaque_ty, func_name, func_ct);
|
||||
parent_opaque_ty, func_name, mangled_name,
|
||||
func_ct);
|
||||
if (llvm::Error err = visitMemberRecordStream(field_list.Data, process))
|
||||
llvm::consumeError(std::move(err));
|
||||
}
|
||||
|
||||
if (!function_decl) {
|
||||
function_decl = m_clang.AddMethodToCXXRecordType(
|
||||
parent_opaque_ty, func_name,
|
||||
/*asm_label=*/{}, func_ct,
|
||||
parent_opaque_ty, func_name, mangled_name, func_ct,
|
||||
/*access=*/lldb::AccessType::eAccessPublic,
|
||||
/*is_virtual=*/false, /*is_static=*/false,
|
||||
/*is_inline=*/false, /*is_explicit=*/false,
|
||||
|
||||
@@ -501,7 +501,9 @@ lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id,
|
||||
return nullptr;
|
||||
|
||||
PdbTypeSymId sig_id(proc.FunctionType, false);
|
||||
Mangled mangled(proc.Name);
|
||||
std::optional<llvm::StringRef> mangled_opt =
|
||||
FindMangledSymbol(SegmentOffset(proc.Segment, proc.CodeOffset));
|
||||
Mangled mangled(mangled_opt.value_or(proc.Name));
|
||||
FunctionSP func_sp = std::make_shared<Function>(
|
||||
&comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled,
|
||||
func_type.get(), func_addr,
|
||||
@@ -2662,6 +2664,31 @@ SymbolFileNativePDB::GetContextForType(TypeIndex ti) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
std::optional<llvm::StringRef>
|
||||
SymbolFileNativePDB::FindMangledFunctionName(PdbCompilandSymId func_id) {
|
||||
const CompilandIndexItem *cci =
|
||||
m_index->compilands().GetCompiland(func_id.modi);
|
||||
if (!cci)
|
||||
return std::nullopt;
|
||||
|
||||
CVSymbol sym_record = cci->m_debug_stream.readSymbolAtOffset(func_id.offset);
|
||||
if (sym_record.kind() != S_LPROC32 && sym_record.kind() != S_GPROC32)
|
||||
return std::nullopt;
|
||||
|
||||
ProcSym proc(static_cast<SymbolRecordKind>(sym_record.kind()));
|
||||
cantFail(SymbolDeserializer::deserializeAs<ProcSym>(sym_record, proc));
|
||||
return FindMangledSymbol(SegmentOffset(proc.Segment, proc.CodeOffset));
|
||||
}
|
||||
|
||||
std::optional<llvm::StringRef>
|
||||
SymbolFileNativePDB::FindMangledSymbol(SegmentOffset so) {
|
||||
auto symbol = m_index->publics().findByAddress(m_index->symrecords(),
|
||||
so.segment, so.offset);
|
||||
if (!symbol)
|
||||
return std::nullopt;
|
||||
return symbol->first.Name;
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::CacheUdtDeclarations() {
|
||||
for (CVType cvt : m_index->ipi().typeArray()) {
|
||||
switch (cvt.kind()) {
|
||||
|
||||
@@ -140,6 +140,12 @@ public:
|
||||
|
||||
std::optional<PdbCompilandSymId> FindSymbolScope(PdbCompilandSymId id);
|
||||
|
||||
/// Find the mangled name for a function
|
||||
///
|
||||
/// \param id A symbol ID of a S_LPROC32/S_GPROC32 record
|
||||
/// \returns The mangled name of the function (if available)
|
||||
std::optional<llvm::StringRef> FindMangledFunctionName(PdbCompilandSymId id);
|
||||
|
||||
void FindTypes(const lldb_private::TypeQuery &match,
|
||||
lldb_private::TypeResults &results) override;
|
||||
|
||||
@@ -269,6 +275,8 @@ private:
|
||||
void CacheUdtDeclarations();
|
||||
llvm::Expected<Declaration> ResolveUdtDeclaration(PdbTypeSymId type_id);
|
||||
|
||||
std::optional<llvm::StringRef> FindMangledSymbol(SegmentOffset so);
|
||||
|
||||
llvm::BumpPtrAllocator m_allocator;
|
||||
|
||||
lldb::addr_t m_obj_load_address = 0;
|
||||
|
||||
@@ -50,9 +50,9 @@ int main(int argc, char **argv) {
|
||||
// CHECK: 1: name = 'main', locations = 1
|
||||
// CHECK: 1.1: where = break-by-function.cpp.tmp.exe`main + {{[0-9]+}}
|
||||
// CHECK: 2: name = 'OvlGlobalFn', locations = 3
|
||||
// CHECK: 2.1: where = break-by-function.cpp.tmp.exe`OvlGlobalFn + {{[0-9]+}}
|
||||
// CHECK: 2.2: where = break-by-function.cpp.tmp.exe`OvlGlobalFn
|
||||
// CHECK: 2.3: where = break-by-function.cpp.tmp.exe`OvlGlobalFn + {{[0-9]+}}
|
||||
// CHECK: 2.1: where = break-by-function.cpp.tmp.exe`int OvlGlobalFn(int) + {{[0-9]+}}
|
||||
// CHECK: 2.2: where = break-by-function.cpp.tmp.exe`int OvlGlobalFn(int, int)
|
||||
// CHECK: 2.3: where = break-by-function.cpp.tmp.exe`int OvlGlobalFn(int, int, int) + {{[0-9]+}}
|
||||
// CHECK: 3: name = 'StaticFn', locations = 1
|
||||
// CHECK: 3.1: where = break-by-function.cpp.tmp.exe`StaticFn + {{[0-9]+}}
|
||||
// CHECK: 4: name = 'DoesntExist', locations = 0 (pending)
|
||||
|
||||
@@ -24,4 +24,4 @@ int main(int argc, char **argv) {
|
||||
// CHECK: (lldb) target create "{{.*}}break-by-line.cpp.tmp.exe"
|
||||
// CHECK: Current executable set to '{{.*}}break-by-line.cpp.tmp.exe'
|
||||
// CHECK: (lldb) break set -f break-by-line.cpp -l 15
|
||||
// CHECK: Breakpoint 1: where = break-by-line.cpp.tmp.exe`NS::NamespaceFn + {{[0-9]+}} at break-by-line.cpp:15
|
||||
// CHECK: Breakpoint 1: where = break-by-line.cpp.tmp.exe`int NS::NamespaceFn(int) + {{[0-9]+}} at break-by-line.cpp:15
|
||||
|
||||
@@ -25,7 +25,7 @@ int main(int argc, char **argv) {
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+12>: mov qword ptr [rsp + 0x28], rdx
|
||||
// CHECK-NEXT: disassembly.cpp.tmp.exe[{{.*}}] <+17>: mov dword ptr [rsp + 0x24], ecx
|
||||
// CHECK: ** 15 foo();
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; foo at disassembly.cpp:12
|
||||
// CHECK: disassembly.cpp.tmp.exe[{{.*}}] <+21>: call {{.*}} ; int foo(void) at disassembly.cpp:12
|
||||
// CHECK: ** 16 return 0;
|
||||
// CHECK-NEXT: 17 }
|
||||
// CHECK-NEXT: 18
|
||||
|
||||
@@ -148,11 +148,12 @@ int main(int argc, char **argv) {
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"
|
||||
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "Class::overloaded_method"
|
||||
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "int Class::overloaded_method(bool)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (void)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (int)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "int (_Bool)"
|
||||
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "overloaded_method"
|
||||
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "char overloaded_method(void)"
|
||||
// FIND-OVERLOAD-BASE-DAG: Function: id = {{.*}}, name = "char overloaded_method(int)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "char (void)"
|
||||
// FIND-OVERLOAD-BASE-DAG: FuncType: id = {{.*}}, compiler_type = "char (int)"
|
||||
|
||||
@@ -160,6 +161,6 @@ int main(int argc, char **argv) {
|
||||
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}"
|
||||
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "int (void)"
|
||||
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "int (char)"
|
||||
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "Class::overloaded_method"
|
||||
// FIND-OVERLOAD-METHOD-DAG: Function: id = {{.*}}, name = "bool Class::overloaded_method(void)"
|
||||
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (void)"
|
||||
// FIND-OVERLOAD-METHOD-DAG: FuncType: id = {{.*}}, compiler_type = "_Bool (int)"
|
||||
|
||||
@@ -55,7 +55,7 @@ int main(int argc, char **argv) {
|
||||
// CHECK-NEXT: (lldb) step
|
||||
// CHECK-NEXT: Process {{.*}} stopped
|
||||
// CHECK-NEXT: * thread #1, stop reason = step in
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: 6
|
||||
// CHECK-NEXT: 7
|
||||
// CHECK-NEXT: 8 int Function(int Param1, char Param2) {
|
||||
@@ -71,7 +71,7 @@ int main(int argc, char **argv) {
|
||||
// CHECK-NEXT: (lldb) step
|
||||
// CHECK-NEXT: Process {{.*}} stopped
|
||||
// CHECK-NEXT: * thread #1, stop reason = step in
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: 7
|
||||
// CHECK-NEXT: 8 int Function(int Param1, char Param2) {
|
||||
// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1;
|
||||
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
|
||||
// CHECK-NEXT: (lldb) step
|
||||
// CHECK-NEXT: Process {{.*}} stopped
|
||||
// CHECK-NEXT: * thread #1, stop reason = step in
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: 8 int Function(int Param1, char Param2) {
|
||||
// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1;
|
||||
// CHECK-NEXT: 10 char Local2 = Param2 + 1;
|
||||
@@ -109,7 +109,7 @@ int main(int argc, char **argv) {
|
||||
// CHECK-NEXT: (lldb) step
|
||||
// CHECK-NEXT: Process {{.*}} stopped
|
||||
// CHECK-NEXT: * thread #1, stop reason = step in
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1;
|
||||
// CHECK-NEXT: 10 char Local2 = Param2 + 1;
|
||||
// CHECK-NEXT: 11 ++Local1;
|
||||
@@ -129,7 +129,7 @@ int main(int argc, char **argv) {
|
||||
// CHECK-NEXT: (lldb) step
|
||||
// CHECK-NEXT: Process {{.*}} stopped
|
||||
// CHECK-NEXT: * thread #1, stop reason = step in
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`int Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}}
|
||||
// CHECK-NEXT: 10 char Local2 = Param2 + 1;
|
||||
// CHECK-NEXT: 11 ++Local1;
|
||||
// CHECK-NEXT: 12 ++Local2;
|
||||
|
||||
@@ -24,19 +24,19 @@ int main(int argc, char **argv) {
|
||||
|
||||
// CHECK: (lldb) thread backtrace
|
||||
// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1
|
||||
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20
|
||||
|
||||
|
||||
// CHECK: (lldb) thread backtrace
|
||||
// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1
|
||||
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20
|
||||
|
||||
// CHECK: (lldb) thread backtrace
|
||||
// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1
|
||||
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=4, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=4, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`void Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12
|
||||
// CHECK-NEXT: frame #3: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20
|
||||
|
||||
@@ -4,7 +4,7 @@ RUN: lldb-test symbols -find=function -file FunctionNestedBlockTest.cpp -line 4
|
||||
RUN: lldb-test symbols -find=block -file FunctionNestedBlockTest.cpp -line 4 %t.exe | FileCheck --check-prefix=CHECK-BLOCK %s
|
||||
|
||||
CHECK-FUNCTION: Found 1 functions:
|
||||
CHECK-FUNCTION: name = "{{.*}}", mangled = "{{_?}}main"
|
||||
CHECK-FUNCTION: name = "main"
|
||||
|
||||
CHECK-BLOCK: Found 1 blocks:
|
||||
CHECK-BLOCK: Blocks: id = {{.*}}, range = {{.*}}
|
||||
|
||||
@@ -42,7 +42,7 @@ GLOBALS-DAG: Variable{{.*}}, name = "g_Const"
|
||||
GLOBALS-SAME: scope = ??? (2)
|
||||
GLOBALS: Function
|
||||
|
||||
FUNC-F: Function{{.*}}, {{mangled = \?f@@YAHHH@Z|demangled = f}}
|
||||
FUNC-F: Function{{.*}}, mangled = ?f@@YAHHH@Z
|
||||
FUNC-F-NEXT: Block
|
||||
FUNC-F-NEXT: Variable{{.*}}, name = "var_arg1"
|
||||
FUNC-F-SAME: scope = parameter
|
||||
@@ -64,14 +64,14 @@ FUNC-MAIN-SAME: scope = local
|
||||
FUNC-MAIN-NEXT: Variable{{.*}}, name = "a"
|
||||
FUNC-MAIN-SAME: scope = local
|
||||
|
||||
FUNC-CONSTRUCTOR: Function{{.*}}, {{(de)?}}mangled = {{.*}}Class::Class{{.*}}
|
||||
FUNC-CONSTRUCTOR: Function{{.*}}, {{mangled = \?\?0Class@@QEAA@H@Z|demangled = .*Class::Class}}
|
||||
FUNC-CONSTRUCTOR-NEXT: Block
|
||||
FUNC-CONSTRUCTOR-NEXT: Variable{{.*}}, name = "this"
|
||||
FUNC-CONSTRUCTOR-SAME: scope = parameter
|
||||
FUNC-CONSTRUCTOR-NEXT: Variable{{.*}}, name = "a"
|
||||
FUNC-CONSTRUCTOR-SAME: scope = parameter
|
||||
|
||||
FUNC-MEMBER: Function{{.*}}, {{(de)?}}mangled = {{.*}}{{(Class::)?}}Func{{.*}}
|
||||
FUNC-MEMBER: Function{{.*}}, {{mangled = \?Func@Class@@QEAAXXZ|demangled = .*Class::Func}}
|
||||
FUNC-MEMBER-NEXT: Block
|
||||
FUNC-MEMBER-NEXT: Variable{{.*}}, name = "this"
|
||||
FUNC-MEMBER-SAME: scope = parameter
|
||||
|
||||
Reference in New Issue
Block a user