Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions __tests__/default-export-declaration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,19 @@ export function check(s: string, ok: boolean) {
return s
}
export default Main
`,
'src/gen/multi.ts': `export function helper() { return 1; }
export default (
value
) => value;
`,
'src/gen/use.ts': `import Issue from "./issue"
import Render from "./render"
import Write from "./write"
import Persisted from "./model"
import Plain from "./plain"
import Unbalanced from "./unbalanced"
import Multi from "./multi"

export function generate() {
Issue()
Expand All @@ -288,6 +294,7 @@ export function generate() {
new Persisted()
Plain()
Unbalanced()
Multi()
}
`,
'src/use.tsx': `import handler from "./api/vans"
Expand Down Expand Up @@ -442,6 +449,10 @@ describe('an `export default` line inside a template literal', () => {
expect(generated()).toContain('src/gen/model.ts:Model');
});

it('binds a multiline anonymous arrow default to nothing, not to a function beside it', () => {
expect(generated()).not.toContain('src/gen/multi.ts:helper');
});

it('leaves regexes, strings and division alone, and a scan it cannot finish', () => {
const targets = generated();
expect(targets).toContain('src/gen/plain.ts:Main');
Expand Down
23 changes: 23 additions & 0 deletions __tests__/ruby-constructed-receivers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ class OtherWriter
false
end
end

class ParentWriter
def flush
nil
end
end

class ChildWriter < ParentWriter
def self.flush
nil
end
end
`,
'app/billing.rb': `module Billing
class Card
Expand Down Expand Up @@ -120,6 +132,10 @@ end
def outside(env)
Request.new(env).preferred_type
end

def inherited_flush
ChildWriter.new.flush
end
end
`,
'lib/rack/show_exceptions.rb': `module Rack
Expand Down Expand Up @@ -249,6 +265,13 @@ describe('Ruby bang and question methods, and calls on .new (#684)', () => {
expect(callsAt(graph, 'app/counter.rb', 25)).toEqual(['Billing::Card::charge!:3']);
});

it('links an instance method a superclass declares before a class method its child defines', async () => {
const graph = await index();
// `ChildWriter.new` is an instance: its own `self.flush` is a class
// method, so the call reaches `ParentWriter#flush` instead.
expect(callsAt(graph, 'app/counter.rb', 41)).toEqual(['ParentWriter::flush:38']);
});

it('links nothing for a class the project does not declare', async () => {
const graph = await index();
expect(callsAt(graph, 'app/counter.rb', 37)).toEqual([]);
Expand Down
18 changes: 18 additions & 0 deletions __tests__/ruby-ivar-receivers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ module Mixin
@writer.flush
end
end
`,
'app/wide.rb': `class WideHolder
def initialize
@wide = CacheWriter.new
@label = "${'x'.repeat(184)}é"
end

def via_wide
@wide.flush
end
end
`,
};

Expand Down Expand Up @@ -149,4 +160,11 @@ describe('Ruby calls on an instance variable initialize types', () => {
expect(callsAt(graph, 'app/holder.rb', 32)).toEqual([]);
expect(callsAt(graph, 'app/holder.rb', 38)).toEqual([]);
});

it('still types an ivar when a multibyte character sits at the scan edge of its initializer', async () => {
const graph = await index();
// `@wide`'s tail crosses byte 200 inside `é`; a byte-indexed slice would
// panic (caught per-ref) and leave the call unresolved.
expect(callsAt(graph, 'app/wide.rb', 8)).toEqual(['CacheWriter::flush:2']);
});
});
7 changes: 5 additions & 2 deletions codegraph-kernel/src/resolve/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,8 +599,11 @@ impl KernelResolver {
if !marker_lines.is_empty() {
let mut anonymous = false;
for &line in marker_lines.iter() {
let head = text.split('\n').nth(line.saturating_sub(1) as usize).unwrap_or("");
if export_default_head_is_anonymous(head) {
// A default's head may span lines (`export default (\n x\n) => x`):
// upstream's readDefaultExport scans the whole statement, so the
// classifier gets the source from the marker's line to the end.
let head = text.split('\n').skip(line.saturating_sub(1) as usize).collect::<Vec<_>>().join("\n");
if export_default_head_is_anonymous(&head) {
anonymous = true;
} else {
default_expr = true;
Expand Down
9 changes: 6 additions & 3 deletions codegraph-kernel/src/resolve/ruby_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ impl KernelResolver {
let own: Vec<Arc<KNode>> = self
.nodes_by_qualified_name(&format!("{owner_qn}::{name}"))?
.iter()
.filter(|n| n.language == "ruby" && n.kind == "method" && !(production && super::resolver_upstream::test_suite_path(&n.file_path)))
// A receiver bound to an instance (`new C().m`, a typed `@x`) can
// only reach instance methods: an own class method does not stand
// in for one an ancestor declares.
.filter(|n| n.language == "ruby" && n.kind == "method" && !(kind == "instance" && n.is_static) && !(production && super::resolver_upstream::test_suite_path(&n.file_path)))
.cloned()
.collect();
let own_pick = if kind == "value" {
Expand Down Expand Up @@ -454,10 +457,10 @@ fn constructed_value(s: &str, from: usize) -> Option<(String, bool)> {
let tail = &s[i.min(s.len())..];
let ok = match tail.chars().next() {
None | Some('\n') | Some(';') | Some('{') => true,
_ => re!(r#"^[ \t]+(?:$|\n|;|\{|[\w:@$"'\[])"#).is_match(&tail[..tail.len().min(200)]),
_ => re!(r#"^[ \t]+(?:$|\n|;|\{|[\w:@$"'\[])"#).is_match(tail.get(..200).unwrap_or(tail)),
};
// A chain may go on at the start of the next line: `Foo.new\n .tap {…}`.
let continued = re!(r"^[ \t]*\n\s*&?\.").is_match(&tail[..tail.len().min(200)]);
let continued = re!(r"^[ \t]*\n\s*&?\.").is_match(tail.get(..200).unwrap_or(tail));
(ok && !continued).then(|| (m[2].to_string(), m.get(1).is_some()))
}

Expand Down
Loading