From 14b0deb699ab9717fa2d8b272e0564ef61ee0ca2 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Mon, 11 Jul 2022 17:32:17 +0800 Subject: [PATCH 1/8] feat:(wip) Add support for emitting class symbols. --- scip_indexer/SCIPIndexer.cc | 24 ++++++++++++++----- test/scip/testdata/arrays.snapshot.rb | 3 ++- test/scip/testdata/classes.rb | 10 ++++++++ test/scip/testdata/classes.snapshot.rb | 17 +++++++++++++ .../loops_and_conditionals.snapshot.rb | 2 ++ 5 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 test/scip/testdata/classes.rb create mode 100644 test/scip/testdata/classes.snapshot.rb diff --git a/scip_indexer/SCIPIndexer.cc b/scip_indexer/SCIPIndexer.cc index c808867f35..519fbf3aac 100644 --- a/scip_indexer/SCIPIndexer.cc +++ b/scip_indexer/SCIPIndexer.cc @@ -548,17 +548,29 @@ class CFGTraversal final { this->copyLocalsFromParents(bb, cfg); for (auto &binding : bb->exprs) { if (auto *aliasInstr = cfg::cast_instruction(binding.value)) { - auto aliasName = aliasInstr->name; - if (!aliasName.exists()) { - // TODO(varun): When does this happen? + if (!binding.loc.exists()) { + print_dbg("non-existent location for binding{}\n", binding.value.showRaw(gs, cfg)); + // This likely corresponds to some synthesized class (e.g. top-level), + // so don't emit a reference here. continue; } - auto aliasedSym = lookupRecursive(gs, method, aliasName); + if (binding.loc.empty()) { + print_dbg("empty location for binding {}\n", binding.value.showRaw(gs, cfg)); + continue; + } + auto aliasedSym = aliasInstr->what; if (!aliasedSym.exists()) { - print_err("# lookup for symbol {} failed starting from {}\n", aliasName.shortName(gs), - method.toString(gs)); + if (!aliasInstr->name.exists()) { + print_dbg("# alias name doesn't exist @ {}, what = {}\n", + core::Loc(this->ctx.file, binding.loc).showRaw(gs), aliasInstr->what.showRaw(gs)); + // TODO(varun): When does this happen? + continue; + } + print_dbg("# missing symbol for RHS {}\n", aliasInstr->name.shortName(gs)); continue; } + auto status = this->scipState.saveReference(gs, this->ctx.file, aliasedSym, binding.loc, 0); + ENFORCE(status.ok()); this->addLocal(bb, binding.bind.variable); continue; } diff --git a/test/scip/testdata/arrays.snapshot.rb b/test/scip/testdata/arrays.snapshot.rb index a455a4d3f4..bac2dbe024 100644 --- a/test/scip/testdata/arrays.snapshot.rb +++ b/test/scip/testdata/arrays.snapshot.rb @@ -16,8 +16,9 @@ def arrays(a, i) # ^ reference local 1~#513334479 # ^ reference local 2~#513334479 b = a[2..-1] -# ^ definition local 3~#513334479 +# ^ definition local 4~#513334479 # ^ reference local 1~#513334479 +# ^^^^^ reference scip-ruby gem TODO TODO # a << a[-1] # ^ reference local 1~#513334479 # ^ reference local 1~#513334479 diff --git a/test/scip/testdata/classes.rb b/test/scip/testdata/classes.rb new file mode 100644 index 0000000000..eb53537a5c --- /dev/null +++ b/test/scip/testdata/classes.rb @@ -0,0 +1,10 @@ +# typed: true + +_ = 0 + +class C1 + def f() + _ = C1.new + return + end +end diff --git a/test/scip/testdata/classes.snapshot.rb b/test/scip/testdata/classes.snapshot.rb new file mode 100644 index 0000000000..0b224922b7 --- /dev/null +++ b/test/scip/testdata/classes.snapshot.rb @@ -0,0 +1,17 @@ + # typed: true + + _ = 0 +#^ definition local 1~#119448696 +#^^^^^^^^^ definition scip-ruby gem TODO TODO (). + + class C1 +#^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ reference scip-ruby gem TODO TODO C1# + def f() +# ^^^^^^^ definition scip-ruby gem TODO TODO f(). + _ = C1.new +# ^ definition local 2~#3809224601 +# ^^ reference scip-ruby gem TODO TODO C1# + return + end + end diff --git a/test/scip/testdata/loops_and_conditionals.snapshot.rb b/test/scip/testdata/loops_and_conditionals.snapshot.rb index eec439230a..83b24cfee8 100644 --- a/test/scip/testdata/loops_and_conditionals.snapshot.rb +++ b/test/scip/testdata/loops_and_conditionals.snapshot.rb @@ -113,8 +113,10 @@ def for(xs) # ^ reference local 4~#2901640080 # ^ reference local 4~#2901640080 break if g == 2 +# ^^^^^ reference scip-ruby gem TODO TODO # # ^ reference local 4~#2901640080 break g+1 if g == 3 +# ^^^^^^^^^ reference scip-ruby gem TODO TODO # # ^ reference local 4~#2901640080 # ^ reference local 4~#2901640080 # NOTE: redo is unsupported (https://srb.help/3003) From b092e5b5f9450e166aae44f32bb6a01b7939fe57 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Mon, 11 Jul 2022 19:12:11 +0800 Subject: [PATCH 2/8] fix: Remove unnecessary references to symbols. --- scip_indexer/SCIPIndexer.cc | 47 ++++++++----------- test/scip/testdata/arrays.snapshot.rb | 3 +- .../loops_and_conditionals.snapshot.rb | 2 - 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/scip_indexer/SCIPIndexer.cc b/scip_indexer/SCIPIndexer.cc index 519fbf3aac..a4b69561e3 100644 --- a/scip_indexer/SCIPIndexer.cc +++ b/scip_indexer/SCIPIndexer.cc @@ -547,33 +547,6 @@ class CFGTraversal final { print_dbg("# Looking at block id: {} ptr: {}\n", bb->id, (void *)bb); this->copyLocalsFromParents(bb, cfg); for (auto &binding : bb->exprs) { - if (auto *aliasInstr = cfg::cast_instruction(binding.value)) { - if (!binding.loc.exists()) { - print_dbg("non-existent location for binding{}\n", binding.value.showRaw(gs, cfg)); - // This likely corresponds to some synthesized class (e.g. top-level), - // so don't emit a reference here. - continue; - } - if (binding.loc.empty()) { - print_dbg("empty location for binding {}\n", binding.value.showRaw(gs, cfg)); - continue; - } - auto aliasedSym = aliasInstr->what; - if (!aliasedSym.exists()) { - if (!aliasInstr->name.exists()) { - print_dbg("# alias name doesn't exist @ {}, what = {}\n", - core::Loc(this->ctx.file, binding.loc).showRaw(gs), aliasInstr->what.showRaw(gs)); - // TODO(varun): When does this happen? - continue; - } - print_dbg("# missing symbol for RHS {}\n", aliasInstr->name.shortName(gs)); - continue; - } - auto status = this->scipState.saveReference(gs, this->ctx.file, aliasedSym, binding.loc, 0); - ENFORCE(status.ok()); - this->addLocal(bb, binding.bind.variable); - continue; - } if (!binding.loc.exists() || binding.loc.empty()) { // TODO(varun): When can each case happen? continue; } @@ -639,7 +612,25 @@ class CFGTraversal final { break; } case cfg::Tag::Alias: { - ENFORCE(false, "already handled earlier"); + auto alias = cfg::cast_instruction(binding.value); + auto aliasedSym = alias->what; + if (!aliasedSym.exists()) { + if (!alias->name.exists()) { + print_dbg("# alias name doesn't exist @ {}, what = {}\n", + core::Loc(this->ctx.file, binding.loc).showRaw(gs), alias->what.showRaw(gs)); + break; + } + print_dbg("# missing symbol for RHS {}\n", alias->name.shortName(gs)); + break; + } else if (aliasedSym == core::Symbols::Magic()) { + break; + } + absl::Status status = + this->scipState.saveReference(gs, this->ctx.file, aliasedSym, binding.loc, 0); + print_err("# emitted ref for\n{}@ {}\n------------------\n", aliasedSym.toString(gs), + core::Loc(this->ctx.file, binding.loc).showRaw(gs)); + ENFORCE(status.ok()); + this->addLocal(bb, binding.bind.variable); break; } case cfg::Tag::Return: { diff --git a/test/scip/testdata/arrays.snapshot.rb b/test/scip/testdata/arrays.snapshot.rb index bac2dbe024..a455a4d3f4 100644 --- a/test/scip/testdata/arrays.snapshot.rb +++ b/test/scip/testdata/arrays.snapshot.rb @@ -16,9 +16,8 @@ def arrays(a, i) # ^ reference local 1~#513334479 # ^ reference local 2~#513334479 b = a[2..-1] -# ^ definition local 4~#513334479 +# ^ definition local 3~#513334479 # ^ reference local 1~#513334479 -# ^^^^^ reference scip-ruby gem TODO TODO # a << a[-1] # ^ reference local 1~#513334479 # ^ reference local 1~#513334479 diff --git a/test/scip/testdata/loops_and_conditionals.snapshot.rb b/test/scip/testdata/loops_and_conditionals.snapshot.rb index 83b24cfee8..eec439230a 100644 --- a/test/scip/testdata/loops_and_conditionals.snapshot.rb +++ b/test/scip/testdata/loops_and_conditionals.snapshot.rb @@ -113,10 +113,8 @@ def for(xs) # ^ reference local 4~#2901640080 # ^ reference local 4~#2901640080 break if g == 2 -# ^^^^^ reference scip-ruby gem TODO TODO # # ^ reference local 4~#2901640080 break g+1 if g == 3 -# ^^^^^^^^^ reference scip-ruby gem TODO TODO # # ^ reference local 4~#2901640080 # ^ reference local 4~#2901640080 # NOTE: redo is unsupported (https://srb.help/3003) From ae28514ac6ddb812ac81f83d1d99a4a9749df10d Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 12 Jul 2022 08:02:52 +0800 Subject: [PATCH 3/8] fix: Emit definition properly for classes. --- scip_indexer/SCIPIndexer.cc | 46 +++++++++++++++++++++----- test/scip/testdata/classes.snapshot.rb | 2 +- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/scip_indexer/SCIPIndexer.cc b/scip_indexer/SCIPIndexer.cc index a4b69561e3..fcddcc2ee9 100644 --- a/scip_indexer/SCIPIndexer.cc +++ b/scip_indexer/SCIPIndexer.cc @@ -321,7 +321,9 @@ class SCIPState { // Save definition when you have a sorbet Symbol. // Meant for methods, fields etc., but not local variables. - absl::Status saveDefinition(const core::GlobalState &gs, core::FileRef file, core::SymbolRef symRef) { + // TODO(varun): Should we always pass in the location instead of sometimes only? + absl::Status saveDefinition(const core::GlobalState &gs, core::FileRef file, core::SymbolRef symRef, + std::optional loc = std::nullopt) { // TODO:(varun) Should we cache here too to avoid emitting duplicate definitions? scip::Symbol symbol; auto status = symbolForExpr(gs, symRef, symbol); @@ -333,11 +335,19 @@ class SCIPState { return valueOrStatus.status(); } string &symbolString = *valueOrStatus.value(); - auto occLocStatus = occurrenceLoc(gs, symRef); - if (!occLocStatus.ok()) { - return occLocStatus.status(); + + core::Loc occLoc; + if (loc.has_value()) { + occLoc = core::Loc(file, loc.value()); + } else { + auto occLocStatus = occurrenceLoc(gs, symRef); + if (!occLocStatus.ok()) { + return occLocStatus.status(); + } + occLoc = occLocStatus.value(); } - return this->saveDefinitionImpl(gs, file, symbolString, occLocStatus.value()); + + return this->saveDefinitionImpl(gs, file, symbolString, occLoc); } absl::Status saveReference(const core::GlobalState &gs, core::FileRef file, OwnedLocal occ, int32_t symbol_roles) { @@ -404,6 +414,19 @@ core::SymbolRef lookupRecursive(const core::GlobalState &gs, const core::SymbolR return lookupRecursive(gs, owner.enclosingClass(gs), name); } +std::string format_ancestry(const core::GlobalState &gs, core::SymbolRef sym) { + UnorderedSet visited; + auto i = 0; + std::ostringstream out; + while (sym.exists() && !visited.contains(sym)) { + out << fmt::format("#{}{}{}\n", std::string(i * 2, ' '), i == 0 ? "" : "<- ", sym.name(gs).toString(gs)); + visited.insert(sym); + sym = sym.owner(gs); + i++; + } + return out.str(); +} + class CFGTraversal final { // A map from each basic block to the locals in it. // @@ -540,6 +563,7 @@ class CFGTraversal final { void traverse(const cfg::CFG &cfg) { auto &gs = this->ctx.state; auto method = this->ctx.owner; + auto isMethodFileStaticInit = method == gs.lookupStaticInitForFile(this->ctx.file); // I don't fully understand the doc comment for forwardsTopoSort; it seems backwards in practice. for (auto it = cfg.forwardsTopoSort.rbegin(); it != cfg.forwardsTopoSort.rend(); ++it) { @@ -625,10 +649,14 @@ class CFGTraversal final { } else if (aliasedSym == core::Symbols::Magic()) { break; } - absl::Status status = - this->scipState.saveReference(gs, this->ctx.file, aliasedSym, binding.loc, 0); - print_err("# emitted ref for\n{}@ {}\n------------------\n", aliasedSym.toString(gs), - core::Loc(this->ctx.file, binding.loc).showRaw(gs)); + absl::Status status; + if (aliasedSym.isClassOrModule() && + (isMethodFileStaticInit || + method == gs.lookupStaticInitForClass(aliasedSym.asClassOrModuleRef().data(gs)->owner))) { + status = this->scipState.saveDefinition(gs, this->ctx.file, aliasedSym, binding.loc); + } else { + status = this->scipState.saveReference(gs, this->ctx.file, aliasedSym, binding.loc, 0); + } ENFORCE(status.ok()); this->addLocal(bb, binding.bind.variable); break; diff --git a/test/scip/testdata/classes.snapshot.rb b/test/scip/testdata/classes.snapshot.rb index 0b224922b7..1a84bc320f 100644 --- a/test/scip/testdata/classes.snapshot.rb +++ b/test/scip/testdata/classes.snapshot.rb @@ -6,7 +6,7 @@ class C1 #^^^^^^^^^ definition scip-ruby gem TODO TODO (). -# ^^ reference scip-ruby gem TODO TODO C1# +# ^^ definition scip-ruby gem TODO TODO C1# def f() # ^^^^^^^ definition scip-ruby gem TODO TODO f(). _ = C1.new From c6793ccd67d1692955ab6f5f7683ad1ceefd1966 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 12 Jul 2022 08:12:47 +0800 Subject: [PATCH 4/8] test:(wip) Add test for class nested inside module. The occurrence source range for M::C isn't quite correct yet. --- test/scip/testdata/classes.rb | 8 +++++++- test/scip/testdata/classes.snapshot.rb | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/test/scip/testdata/classes.rb b/test/scip/testdata/classes.rb index eb53537a5c..c7195aa198 100644 --- a/test/scip/testdata/classes.rb +++ b/test/scip/testdata/classes.rb @@ -4,7 +4,13 @@ class C1 def f() - _ = C1.new + _a = C1.new + _b = M2::C2.new return end end + +module M2 + class C2 + end +end diff --git a/test/scip/testdata/classes.snapshot.rb b/test/scip/testdata/classes.snapshot.rb index 1a84bc320f..cc58ef0551 100644 --- a/test/scip/testdata/classes.snapshot.rb +++ b/test/scip/testdata/classes.snapshot.rb @@ -2,16 +2,29 @@ _ = 0 #^ definition local 1~#119448696 -#^^^^^^^^^ definition scip-ruby gem TODO TODO (). +#^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). class C1 -#^^^^^^^^^ definition scip-ruby gem TODO TODO (). +#^^^^^^^^^^ definition scip-ruby gem TODO TODO (). # ^^ definition scip-ruby gem TODO TODO C1# def f() # ^^^^^^^ definition scip-ruby gem TODO TODO f(). - _ = C1.new -# ^ definition local 2~#3809224601 -# ^^ reference scip-ruby gem TODO TODO C1# + _a = C1.new +# ^^ definition local 2~#3809224601 +# ^^ reference scip-ruby gem TODO TODO C1# + _b = M2::C2.new +# ^^ definition local 5~#3809224601 +# ^^ reference scip-ruby gem TODO TODO M2# +# ^^^^^^ reference scip-ruby gem TODO TODO C2# return end end + + module M2 +#^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO M2# + class C2 +# ^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO C2# + end + end From 77dce7b6688c3db39fd6b90c52922b42ccabde8d Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 12 Jul 2022 08:33:22 +0800 Subject: [PATCH 5/8] fix: Emit correct source range for qualified access. --- scip_indexer/SCIPIndexer.cc | 10 +++++++++- test/scip/testdata/classes.snapshot.rb | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scip_indexer/SCIPIndexer.cc b/scip_indexer/SCIPIndexer.cc index fcddcc2ee9..a70f0530ba 100644 --- a/scip_indexer/SCIPIndexer.cc +++ b/scip_indexer/SCIPIndexer.cc @@ -655,7 +655,15 @@ class CFGTraversal final { method == gs.lookupStaticInitForClass(aliasedSym.asClassOrModuleRef().data(gs)->owner))) { status = this->scipState.saveDefinition(gs, this->ctx.file, aliasedSym, binding.loc); } else { - status = this->scipState.saveReference(gs, this->ctx.file, aliasedSym, binding.loc, 0); + // When we have code like MyModule::MyClass, the source location in binding.loc corresponds + // to 'MyModule::MyClass', whereas we want a range for 'MyClass'. So we cut off the prefix. + auto loc = binding.loc; + auto source = this->ctx.locAt(binding.loc).source(gs); + if (source.has_value() && source.value().find("::"sv) != std::string::npos) { + loc.beginLoc = binding.loc.endPos() - + static_cast(aliasedSym.name(gs).shortName(gs).length()); + } + status = this->scipState.saveReference(gs, this->ctx.file, aliasedSym, loc, 0); } ENFORCE(status.ok()); this->addLocal(bb, binding.bind.variable); diff --git a/test/scip/testdata/classes.snapshot.rb b/test/scip/testdata/classes.snapshot.rb index cc58ef0551..ef4c307499 100644 --- a/test/scip/testdata/classes.snapshot.rb +++ b/test/scip/testdata/classes.snapshot.rb @@ -15,7 +15,7 @@ def f() _b = M2::C2.new # ^^ definition local 5~#3809224601 # ^^ reference scip-ruby gem TODO TODO M2# -# ^^^^^^ reference scip-ruby gem TODO TODO C2# +# ^^ reference scip-ruby gem TODO TODO C2# return end end From c472a2c6aa050f89932707370671f186b0e13eff Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 12 Jul 2022 08:39:33 +0800 Subject: [PATCH 6/8] fix: Emit correct source ranges for nested class definition. --- scip_indexer/SCIPIndexer.cc | 14 +++++++------- test/scip/testdata/classes.rb | 3 +++ test/scip/testdata/classes.snapshot.rb | 8 +++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/scip_indexer/SCIPIndexer.cc b/scip_indexer/SCIPIndexer.cc index a70f0530ba..06e294b2a5 100644 --- a/scip_indexer/SCIPIndexer.cc +++ b/scip_indexer/SCIPIndexer.cc @@ -650,19 +650,19 @@ class CFGTraversal final { break; } absl::Status status; + auto loc = binding.loc; + auto source = this->ctx.locAt(binding.loc).source(gs); + if (source.has_value() && source.value().find("::"sv) != std::string::npos) { + loc.beginLoc = binding.loc.endPos() - + static_cast(aliasedSym.name(gs).shortName(gs).length()); + } if (aliasedSym.isClassOrModule() && (isMethodFileStaticInit || method == gs.lookupStaticInitForClass(aliasedSym.asClassOrModuleRef().data(gs)->owner))) { - status = this->scipState.saveDefinition(gs, this->ctx.file, aliasedSym, binding.loc); + status = this->scipState.saveDefinition(gs, this->ctx.file, aliasedSym, loc); } else { // When we have code like MyModule::MyClass, the source location in binding.loc corresponds // to 'MyModule::MyClass', whereas we want a range for 'MyClass'. So we cut off the prefix. - auto loc = binding.loc; - auto source = this->ctx.locAt(binding.loc).source(gs); - if (source.has_value() && source.value().find("::"sv) != std::string::npos) { - loc.beginLoc = binding.loc.endPos() - - static_cast(aliasedSym.name(gs).shortName(gs).length()); - } status = this->scipState.saveReference(gs, this->ctx.file, aliasedSym, loc, 0); } ENFORCE(status.ok()); diff --git a/test/scip/testdata/classes.rb b/test/scip/testdata/classes.rb index c7195aa198..784b105270 100644 --- a/test/scip/testdata/classes.rb +++ b/test/scip/testdata/classes.rb @@ -14,3 +14,6 @@ module M2 class C2 end end + +class M3::C3 +end \ No newline at end of file diff --git a/test/scip/testdata/classes.snapshot.rb b/test/scip/testdata/classes.snapshot.rb index ef4c307499..913f1757ec 100644 --- a/test/scip/testdata/classes.snapshot.rb +++ b/test/scip/testdata/classes.snapshot.rb @@ -2,7 +2,7 @@ _ = 0 #^ definition local 1~#119448696 -#^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +#^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). class C1 #^^^^^^^^^^ definition scip-ruby gem TODO TODO (). @@ -28,3 +28,9 @@ class C2 # ^^ definition scip-ruby gem TODO TODO C2# end end + + class M3::C3 +#^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO M3# +# ^^ definition scip-ruby gem TODO TODO C3# + end From 95af9aad615bc7eb8553856762aea41223c13816 Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 12 Jul 2022 08:54:01 +0800 Subject: [PATCH 7/8] test: Add test for locally-defined classes. --- test/scip/testdata/classes.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/scip/testdata/classes.rb b/test/scip/testdata/classes.rb index 784b105270..0f77be4bc5 100644 --- a/test/scip/testdata/classes.rb +++ b/test/scip/testdata/classes.rb @@ -16,4 +16,15 @@ class C2 end class M3::C3 +end + +def local_class() + localClass = Class.new + # Technically, this is not supported by Sorbet (https://srb.help/3001), + # but make sure we don't crash or do something weird. + def localClass.myMethod() + ":)" + end + _c = localClass.new + _m = localClass.myMethod end \ No newline at end of file From d18c17886c0bb561529603d6ea4658b11824858e Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Tue, 12 Jul 2022 09:06:34 +0800 Subject: [PATCH 8/8] test: Add more tests for classes and modules. NOTE: Right now, some of the test output is incorrect. Specifically, method references emitted are not properly qualified. However, it is correct with respect to classes and modules. --- test/scip/testdata/classes.rb | 36 +++++++++++- test/scip/testdata/classes.snapshot.rb | 79 +++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/test/scip/testdata/classes.rb b/test/scip/testdata/classes.rb index 0f77be4bc5..7de2159ce7 100644 --- a/test/scip/testdata/classes.rb +++ b/test/scip/testdata/classes.rb @@ -27,4 +27,38 @@ def localClass.myMethod() end _c = localClass.new _m = localClass.myMethod -end \ No newline at end of file + return +end + +module M4 + K = 0 +end + +def module_access() + _ = M4::K + return +end + +module M5 + module M6 + def self.g() + end + end + + def self.h() + M6.g() + return + end +end + +class C7 + module M8 + def self.i() + end + end + + def j() + M8.j() + return + end +end diff --git a/test/scip/testdata/classes.snapshot.rb b/test/scip/testdata/classes.snapshot.rb index 913f1757ec..198126dc04 100644 --- a/test/scip/testdata/classes.snapshot.rb +++ b/test/scip/testdata/classes.snapshot.rb @@ -2,7 +2,7 @@ _ = 0 #^ definition local 1~#119448696 -#^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). class C1 #^^^^^^^^^^ definition scip-ruby gem TODO TODO (). @@ -34,3 +34,80 @@ class M3::C3 # ^^ definition scip-ruby gem TODO TODO M3# # ^^ definition scip-ruby gem TODO TODO C3# end + + def local_class() +#^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO local_class(). + localClass = Class.new +# ^^^^^^^^^^ definition local 2~#552113551 +# ^^^^^ reference scip-ruby gem TODO TODO Class# + # Technically, this is not supported by Sorbet (https://srb.help/3001), + # but make sure we don't crash or do something weird. + def localClass.myMethod() +# ^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO myMethod(). + ":)" + end + _c = localClass.new +# ^^ definition local 3~#552113551 +# ^^^^^^^^^^ reference local 2~#552113551 + _m = localClass.myMethod +# ^^ definition local 4~#552113551 +# ^^^^^^^^^^ reference local 2~#552113551 +# ^^^^^^^^ reference scip-ruby gem TODO TODO myMethod(). + return + end + + module M4 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO M4# + K = 0 +# ^ definition local 1~#119448696 +# ^^^^^ reference local 1~#119448696 + end + + def module_access() +#^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO module_access(). + _ = M4::K +# ^ definition local 2~#3353511840 +# ^^ reference scip-ruby gem TODO TODO M4# +# ^ reference scip-ruby gem TODO TODO K. + return + end + + module M5 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO M5# + module M6 +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO M6# + def self.g() +# ^^^^^^^^^^^^ definition scip-ruby gem TODO TODO g(). + end + end + + def self.h() +# ^^^^^^^^^^^^ definition scip-ruby gem TODO TODO h(). + M6.g() +# ^^ reference scip-ruby gem TODO TODO M6# + return + end + end + + class C7 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO C7# + module M8 +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition scip-ruby gem TODO TODO (). +# ^^ definition scip-ruby gem TODO TODO M8# + def self.i() +# ^^^^^^^^^^^^ definition scip-ruby gem TODO TODO i(). + end + end + + def j() +# ^^^^^^^ definition scip-ruby gem TODO TODO j(). + M8.j() +# ^^ reference scip-ruby gem TODO TODO M8# +# ^ reference scip-ruby gem TODO TODO j(). + return + end + end