Skip to content

Emit enclosing ranges for declarations #308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 9, 2024
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
19 changes: 19 additions & 0 deletions snapshots/input/enclosing-ranges-ts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// format-options: showRanges

interface Foo {
bar: string
test: () => void
}

interface Single<T> {
t: T
}

enum SimpleEnum {
Case1,
Case2,
}

type SimpleTypeAlias = SimpleEnum

type ComplexTypeAlias<T> = Single<Single<T>>
4 changes: 4 additions & 0 deletions snapshots/input/enclosing-ranges-ts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "enclosing-ranges-ts",
"version": "1.0.0"
}
1 change: 1 addition & 0 deletions snapshots/input/enclosing-ranges-ts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
4 changes: 4 additions & 0 deletions snapshots/input/enclosing-ranges/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "enclosing-ranges",
"version": "0.0.1"
}
38 changes: 38 additions & 0 deletions snapshots/input/enclosing-ranges/range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// format-options: showRanges

const test = () => {
const a = 'a'
const b = 'b'

return a + b
}

function test2() {
const a = 'a'
const b = 'b'

return a + b
}

class Test {
constructor() {
const a = 'a'
const b = 'b'

return a + b
}

test() {
const a = 'a'
const b = 'b'

return a + b
}

static test() {
const a = 'a'
const b = 'b'

return a + b
}
}
1 change: 1 addition & 0 deletions snapshots/input/enclosing-ranges/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "compilerOptions": { "allowJs": true } }
51 changes: 51 additions & 0 deletions snapshots/output/enclosing-ranges-ts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// < definition enclosing-ranges-ts 1.0.0 `index.ts`/

// format-options: showRanges

// < start enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/Foo#
// < start enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/
interface Foo {
// ^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/Foo#
bar: string
//^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/Foo#bar.
test: () => void
//^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/Foo#test.
}
// < end enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/Foo#

// < start enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/Single#
interface Single<T> {
// ^^^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/Single#
// ^ definition enclosing-ranges-ts 1.0.0 `index.ts`/Single#[T]
t: T
//^ definition enclosing-ranges-ts 1.0.0 `index.ts`/Single#t.
// ^ reference enclosing-ranges-ts 1.0.0 `index.ts`/Single#[T]
}
// < end enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/Single#

// < start enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/SimpleEnum#
enum SimpleEnum {
// ^^^^^^^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/SimpleEnum#
Case1,
//^^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/SimpleEnum#Case1.
Case2,
//^^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/SimpleEnum#Case2.
}
// < end enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/SimpleEnum#

// < start enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/SimpleTypeAlias#
type SimpleTypeAlias = SimpleEnum
// ^^^^^^^^^^^^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/SimpleTypeAlias#
// ^^^^^^^^^^ reference enclosing-ranges-ts 1.0.0 `index.ts`/SimpleEnum#
// < end enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/SimpleTypeAlias#

// < start enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/ComplexTypeAlias#
type ComplexTypeAlias<T> = Single<Single<T>>
// ^^^^^^^^^^^^^^^^ definition enclosing-ranges-ts 1.0.0 `index.ts`/ComplexTypeAlias#
// ^ definition enclosing-ranges-ts 1.0.0 `index.ts`/ComplexTypeAlias#[T]
// ^^^^^^ reference enclosing-ranges-ts 1.0.0 `index.ts`/Single#
// ^^^^^^ reference enclosing-ranges-ts 1.0.0 `index.ts`/Single#
// ^ reference enclosing-ranges-ts 1.0.0 `index.ts`/ComplexTypeAlias#[T]
// < end enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/ComplexTypeAlias#

// < end enclosing_range enclosing-ranges-ts 1.0.0 `index.ts`/
79 changes: 79 additions & 0 deletions snapshots/output/enclosing-ranges/range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// < definition enclosing-ranges 0.0.1 `range.js`/

// format-options: showRanges

// < start enclosing_range enclosing-ranges 0.0.1 `range.js`/
// ⌄ start enclosing_range enclosing-ranges 0.0.1 `range.js`/test.
const test = () => {
// ^^^^ definition enclosing-ranges 0.0.1 `range.js`/test.
const a = 'a'
// ^ definition local 2
const b = 'b'
// ^ definition local 5

return a + b
// ^ reference local 2
// ^ reference local 5
}
// ^ end enclosing_range enclosing-ranges 0.0.1 `range.js`/test.

// < start enclosing_range enclosing-ranges 0.0.1 `range.js`/test2().
function test2() {
// ^^^^^ definition enclosing-ranges 0.0.1 `range.js`/test2().
const a = 'a'
// ^ definition local 8
const b = 'b'
// ^ definition local 11

return a + b
// ^ reference local 8
// ^ reference local 11
}
// < end enclosing_range enclosing-ranges 0.0.1 `range.js`/test2().

// < start enclosing_range enclosing-ranges 0.0.1 `range.js`/Test#
class Test {
// ^^^^ definition enclosing-ranges 0.0.1 `range.js`/Test#
constructor() {
//^^^^^^^^^^^ definition enclosing-ranges 0.0.1 `range.js`/Test#`<constructor>`().
const a = 'a'
// ^ definition local 14
const b = 'b'
// ^ definition local 17

return a + b
// ^ reference local 14
// ^ reference local 17
}

// ⌄ start enclosing_range enclosing-ranges 0.0.1 `range.js`/Test#test().
test() {
//^^^^ definition enclosing-ranges 0.0.1 `range.js`/Test#test().
const a = 'a'
// ^ definition local 20
const b = 'b'
// ^ definition local 23

return a + b
// ^ reference local 20
// ^ reference local 23
}
// ^ end enclosing_range enclosing-ranges 0.0.1 `range.js`/Test#test().

// ⌄ start enclosing_range enclosing-ranges 0.0.1 `range.js`/Test#test().
static test() {
// ^^^^ definition enclosing-ranges 0.0.1 `range.js`/Test#test().
const a = 'a'
// ^ definition local 26
const b = 'b'
// ^ definition local 29

return a + b
// ^ reference local 26
// ^ reference local 29
}
// ^ end enclosing_range enclosing-ranges 0.0.1 `range.js`/Test#test().
}
// < end enclosing_range enclosing-ranges 0.0.1 `range.js`/Test#

// < end enclosing_range enclosing-ranges 0.0.1 `range.js`/
4 changes: 2 additions & 2 deletions src/Descriptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type Suffix = scip.scip.Descriptor.Suffix
const Suffix = scip.scip.Descriptor.Suffix

export function packageDescriptor(name: string): Descriptor {
return new Descriptor({ name, suffix: Suffix.Package })
return new Descriptor({ name, suffix: Suffix.Namespace })
}

export function typeDescriptor(name: string): Descriptor {
Expand Down Expand Up @@ -35,7 +35,7 @@ export function typeParameterDescriptor(name: string): Descriptor {

export function descriptorString(desc: Descriptor): string {
switch (desc.suffix) {
case Suffix.Package: {
case Suffix.Namespace: {
return escapedName(desc) + '/'
}
case Suffix.Type: {
Expand Down
23 changes: 23 additions & 0 deletions src/FileIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export class FileIndexer {
this.pushOccurrence(
new scip.scip.Occurrence({
range: [0, 0, 0],
enclosing_range: Range.fromNode(this.sourceFile).toLsif(),
symbol: symbol.value,
symbol_roles: scip.scip.SymbolRole.Definition,
})
Expand Down Expand Up @@ -168,6 +169,27 @@ export class FileIndexer {
for (const declaration of declarations) {
let scipSymbol = this.scipSymbol(declaration)

let enclosingRange: number[] | undefined

if (!isDefinitionNode || scipSymbol.isEmpty() || scipSymbol.isLocal()) {
// Skip enclosing ranges for these cases
} else if (
ts.isVariableDeclaration(declaration) &&
declaration.initializer &&
ts.isFunctionLike(declaration.initializer)
) {
enclosingRange = Range.fromNode(declaration.initializer).toLsif()
} else if (
ts.isFunctionDeclaration(declaration) ||
ts.isEnumDeclaration(declaration) ||
ts.isTypeAliasDeclaration(declaration) ||
ts.isClassDeclaration(declaration) ||
ts.isMethodDeclaration(declaration) ||
ts.isInterfaceDeclaration(declaration)
) {
enclosingRange = Range.fromNode(declaration).toLsif()
}

if (
((ts.isIdentifier(node) && ts.isNewExpression(node.parent)) ||
(ts.isPropertyAccessExpression(node.parent) &&
Expand All @@ -187,6 +209,7 @@ export class FileIndexer {
}
this.pushOccurrence(
new scip.scip.Occurrence({
enclosing_range: enclosingRange,
range,
symbol: scipSymbol.value,
symbol_roles: role,
Expand Down
80 changes: 80 additions & 0 deletions src/SnapshotTesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export function formatSnapshot(
externalSymbolTable.set(externalSymbol.symbol, externalSymbol)
}

const enclosingRanges: { range: Range; symbol: string }[] = []
const symbolsWithDefinitions: Set<string> = new Set()

const formatOptions = parseOptions(input.lines)
Expand All @@ -77,6 +78,29 @@ export function formatSnapshot(
if (isDefinition) {
symbolsWithDefinitions.add(occurrence.symbol)
}

if (formatOptions.showRanges && occurrence.enclosing_range.length > 0) {
enclosingRanges.push({
range: Range.fromLsif(occurrence.enclosing_range),
symbol: occurrence.symbol,
})
}
}

enclosingRanges.sort(enclosingRangesByLine)

const enclosingRangeStarts: (typeof enclosingRanges)[number][][] = Array.from(
new Array(input.lines.length),
() => []
)
const enclosingRangeEnds: (typeof enclosingRanges)[number][][] = Array.from(
new Array(input.lines.length),
() => []
)

for (const enclosingRange of enclosingRanges) {
enclosingRangeStarts[enclosingRange.range.start.line].push(enclosingRange)
enclosingRangeEnds[enclosingRange.range.end.line].unshift(enclosingRange)
}

const emittedDocstrings: Set<string> = new Set()
Expand Down Expand Up @@ -162,6 +186,38 @@ export function formatSnapshot(
out.push('\n')
}

const pushEnclosingRange = (
enclosingRange: {
range: Range
symbol: string
},
end: boolean = false
): void => {
if (!formatOptions.showRanges) {
return
}

out.push(commentSyntax)
out.push(' '.repeat(Math.max(1, enclosingRange.range.start.character - 2)))

if (enclosingRange.range.start.character < 2) {
out.push('<')
} else if (end) {
out.push('^')
} else {
out.push('⌄')
}

if (end) {
out.push(' end ')
} else {
out.push(' start ')
}
out.push('enclosing_range ')
out.push(symbolNameForSnapshot(enclosingRange.symbol))
out.push('\n')
}

doc.occurrences.sort(occurrencesByLine)
let occurrenceIndex = 0

Expand Down Expand Up @@ -189,6 +245,11 @@ export function formatSnapshot(
}
}

// Check if any enclosing ranges start on this line
for (const enclosingRange of enclosingRangeStarts[lineNumber]) {
pushEnclosingRange(enclosingRange)
}

out.push('')
out.push(line)
out.push('\n')
Expand Down Expand Up @@ -235,10 +296,29 @@ export function formatSnapshot(

pushDoc(range, occurrence.symbol, isDefinition, isStartOfLine)
}

// Check if any enclosing ranges end on this line
for (const enclosingRange of enclosingRangeEnds[lineNumber]) {
pushEnclosingRange(enclosingRange, true)
}
}
return out.join('')
}

function occurrencesByLine(a: scip.Occurrence, b: scip.Occurrence): number {
return Range.fromLsif(a.range).compare(Range.fromLsif(b.range))
}

function enclosingRangesByLine(
a: { range: Range; symbol: string },
b: { range: Range; symbol: string }
): number {
// Return the range that starts first, and if they start at the same line, the one that ends last (enclosing).
const rangeCompare = a.range.compare(b.range)

if (rangeCompare !== 0) {
return rangeCompare
}

return b.range.end.line - a.range.end.line
}
Loading