diff --git a/gitnexus/test/helpers/r-rename-verdict.ts b/gitnexus/test/helpers/r-rename-verdict.ts index 2a39debc9..4d6d52507 100644 --- a/gitnexus/test/helpers/r-rename-verdict.ts +++ b/gitnexus/test/helpers/r-rename-verdict.ts @@ -1,7 +1,8 @@ /** * Run the R rename provider's safety check on real parsed sources and a real knowledge graph. * `localDefs` are read off the sources the way the indexer would list plain top-level functions - * (`name <- function`), so a function defined in another file is visible to the checks. + * (`name <- function`, `name <<- function` and `name = function`), so a function defined in + * another file is visible to the checks. */ import Parser from 'tree-sitter'; import R from '@eagleoutice/tree-sitter-r'; @@ -21,7 +22,7 @@ export interface RVerdictInput { readonly targetFile?: string; } -const FUNCTION_DEF = /^(`[^`\n]+`|[A-Za-z.][A-Za-z0-9._]*)\s*<-\s*function/gm; +const FUNCTION_DEF = /^(`[^`\n]+`|[A-Za-z.][A-Za-z0-9._]*)\s*(?:<-|<<-|=(?!=))\s*function/gm; /** The issue the provider reports (`code`, `message`), or null when it accepts the rename. */ export function rIssue(input: RVerdictInput): { code: string; message: string } | null { diff --git a/gitnexus/test/unit/r-rename-collisions.test.ts b/gitnexus/test/unit/r-rename-collisions.test.ts index 068deeb2c..85ca81109 100644 --- a/gitnexus/test/unit/r-rename-collisions.test.ts +++ b/gitnexus/test/unit/r-rename-collisions.test.ts @@ -48,6 +48,28 @@ describe('R rename: a new name that already exists', () => { ).toBe('name_collision'); }); + it.each(['<-', '<<-', '='])( + 'lists a function defined with %s, so another file defining the new name is refused', + (op) => { + expect( + rIssue({ + files: { 'a.R': HELPER, 'b.R': `assist ${op} function(v) v * 2\n` }, + newName: 'assist', + })?.code, + ).toBe('name_collision'); + }, + ); + + it('sees a generic defined with = when it guards against a new S3 method name', () => { + // `to_json = function(x) x` makes `to_json.foo` an S3 method of an indexed function. + expect( + rIssue({ + files: { 'a.R': HELPER, 'b.R': 'to_json = function(x) x\n' }, + newName: 'to_json.foo', + })?.code, + ).toBe('unsupported_occurrence'); + }); + it('refuses a <<- to the new name from inside a function', () => { expect(verdict('install <- function() { assist <<- 3 }\n')).toBe('name_collision'); expect(verdict('install <- function() { 3 ->> assist }\n')).toBe('name_collision');