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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Fixes

- TypeScript generic calls and typed tags using `typeof abstract` now retain their callers, while runtime `typeof` comparisons and optional chains keep their runtime meaning; re-index TypeScript projects after upgrading.
- TypeScript classes with members named `abstract` or `accessor`, and auto-accessors with `static`, `override` or `abstract` modifiers, now index correctly; re-index TypeScript projects after upgrading.
- A TSX file with a broken JSX attribute such as `<a {{b:>c:d(e f)` no longer stalls indexing for about 90 seconds and then drops out of the index; it is indexed like any other file with a syntax error.
- In TypeScript, a template string with a `\u` or `\x` that has no hex digits after it, like LaTeX in ``String.raw`\usepackage{x}` ``, now parses. Before, the file had a parse error there and the template's tag, such as `String.raw`, was not recorded as a call. Re-index TypeScript projects after upgrading.
- TypeScript variance annotations like `interface Stream<out A, in E>` or `<in out T>` now parse. Before, each one was a parse error, and in a large file enough of them could make the whole file fail to parse and show up with almost no symbols. Re-index TypeScript projects after upgrading.
Expand Down
34 changes: 34 additions & 0 deletions __tests__/fixtures/ts-syntax/abstract-member-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// A member named `abstract` (upstream #377), next to `abstract` as a modifier.
export interface I {
abstract?: boolean;
abstract2: number;
abstract(): void;
}

export type T = { abstract: boolean; a: 1 };

export class C {
abstract = 1;
static abstract = 2;
abstract!: number;
abstract<T>(x: T) { return x; }
}

export class D {
abstract
x: number = 0;
}

export abstract class A {
abstract x: number;
abstract m?(): void;
protected abstract override n(): void;
abstract readonly r: number;
readonly abstract s: number;
abstract abstract: number;
abstract
y = 1;
}

export const abstract = { abstract: 1 };
export function f(abstract: number) { return abstract + 1; }
37 changes: 37 additions & 0 deletions __tests__/fixtures/ts-syntax/abstract-member-name.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// tsx twin of abstract-member-name.ts.
// A member named `abstract` (upstream #377), next to `abstract` as a modifier.
export interface I {
abstract?: boolean;
abstract2: number;
abstract(): void;
}

export type T = { abstract: boolean; a: 1 };

export class C {
abstract = 1;
static abstract = 2;
abstract!: number;
abstract<T>(x: T) { return x; }
}

export class D {
abstract
x: number = 0;
}

export abstract class A {
abstract x: number;
abstract m?(): void;
protected abstract override n(): void;
abstract readonly r: number;
readonly abstract s: number;
abstract abstract: number;
abstract
y = 1;
}

export const abstract = { abstract: 1 };
export function f(abstract: number) { return abstract + 1; }

export const el = <a abstract={abstract.abstract}>{f(1)}</a>;
23 changes: 23 additions & 0 deletions __tests__/fixtures/ts-syntax/accessor-member-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// `accessor` is a contextual keyword, so it remains a member name (upstream #369).
class AccessorMethods {
accessor() { return 1; }
static accessor() { return 2; }
get accessor() { return 3; }
}
class AccessorFields {
accessor;
accessor = 1;
accessor: number = 1;
accessor?: number;
accessor!: number;
readonly accessor = 1;
accessor accessor = 1;
}
interface AccessorInterface { accessor?: boolean; accessor(): void; }
type AccessorType = { accessor: number; accessor(): void; };
class AccessorLineBreak {
accessor
value = 1;
accessor
method() {}
}
23 changes: 23 additions & 0 deletions __tests__/fixtures/ts-syntax/accessor-member-name.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// `accessor` is a contextual keyword, so it remains a member name (upstream #369).
class AccessorMethods {
accessor() { return 1; }
static accessor() { return 2; }
get accessor() { return 3; }
}
class AccessorFields {
accessor;
accessor = 1;
accessor: number = 1;
accessor?: number;
accessor!: number;
readonly accessor = 1;
accessor accessor = 1;
}
interface AccessorInterface { accessor?: boolean; accessor(): void; }
type AccessorType = { accessor: number; accessor(): void; };
class AccessorLineBreak {
accessor
value = 1;
accessor
method() {}
}
15 changes: 15 additions & 0 deletions __tests__/fixtures/ts-syntax/accessor-modifiers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Auto-accessors can follow other field modifiers (upstream #369).
class AccessorBase { accessor value = 1; }
class AccessorDerived extends AccessorBase {
static accessor shared = 1;
public static accessor publicShared: number = 2;
private static accessor privateShared = 3;
protected static accessor protectedShared = 4;
static accessor #hidden = 5;
override accessor value = 6;
public override accessor accessor = 7;
}
abstract class AbstractAccessors extends AccessorBase {
abstract accessor item: number;
protected abstract accessor protectedItem: number;
}
15 changes: 15 additions & 0 deletions __tests__/fixtures/ts-syntax/accessor-modifiers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Auto-accessors can follow other field modifiers (upstream #369).
class AccessorBase { accessor value = 1; }
class AccessorDerived extends AccessorBase {
static accessor shared = 1;
public static accessor publicShared: number = 2;
private static accessor privateShared = 3;
protected static accessor protectedShared = 4;
static accessor #hidden = 5;
override accessor value = 6;
public override accessor accessor = 7;
}
abstract class AbstractAccessors extends AccessorBase {
abstract accessor item: number;
protected abstract accessor protectedItem: number;
}
14 changes: 14 additions & 0 deletions __tests__/fixtures/ts-syntax/accessor-type-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// A contextual accessor keyword must retain its type-identifier interpretation.
type accessor = number;
type Parenthesized = (accessor);
let value: (accessor);
f<accessor>();
f<accessor>(0);
f<accessor>``;
class Derived extends Base<accessor> {}
type Qualified = accessor.Value;
f<accessor.Value>(0);
f<typeof accessor>();
f<typeof accessor>``;
const shorthand = { accessor };
const { accessor: renamed } = shorthand;
14 changes: 14 additions & 0 deletions __tests__/fixtures/ts-syntax/accessor-type-name.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// A contextual accessor keyword must retain its type-identifier interpretation.
type accessor = number;
type Parenthesized = (accessor);
let value: (accessor);
f<accessor>();
f<accessor>(0);
f<accessor>``;
class Derived extends Base<accessor> {}
type Qualified = accessor.Value;
f<accessor.Value>(0);
f<typeof accessor>();
f<typeof accessor>``;
const shorthand = { accessor };
const { accessor: renamed } = shorthand;
2 changes: 0 additions & 2 deletions __tests__/fixtures/ts-syntax/gap-static-accessor.ts

This file was deleted.

2 changes: 2 additions & 0 deletions __tests__/fixtures/ts-syntax/static-accessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Static auto-accessors (TS 4.9, upstream #369).
export class Config { static accessor shared = 1; }
28 changes: 28 additions & 0 deletions __tests__/fixtures/ts-syntax/typeof-abstract-comparison.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Invalid type-query operands must keep the valid runtime comparison reading.
namespace RuntimeCalls {
declare function abstract(x: unknown): number;
declare const f: string, x: any;
f < typeof abstract(x) > (x);
const holder = { abstract: abstract };
f < typeof holder.abstract(x) > (x);
}
namespace RuntimeProperties {
declare const abstract: { abstract: { abstract: number } };
declare const f: any, x: any;
f < typeof abstract["abstract"].abstract > (x);
}

namespace RuntimeOptional {
declare const abstract: { abstract: { value: number } } | undefined;
declare const f: string, x: any;
f < typeof abstract?.abstract > (x);
f < typeof abstract?.abstract.value > (x);
f < typeof abstract?.["abstract"] > (x);
f < typeof abstract?.abstract["value"] > (x);
}
namespace RuntimeOptionalNested {
declare const abstract: { abstract: { value: number } | undefined };
declare const f: string, x: any;
f < typeof abstract.abstract?.value > (x);
f < typeof abstract.abstract?.["value"] > (x);
}
28 changes: 28 additions & 0 deletions __tests__/fixtures/ts-syntax/typeof-abstract-comparison.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Invalid type-query operands must keep the valid runtime comparison reading.
namespace RuntimeCalls {
declare function abstract(x: unknown): number;
declare const f: string, x: any;
f < typeof abstract(x) > (x);
const holder = { abstract: abstract };
f < typeof holder.abstract(x) > (x);
}
namespace RuntimeProperties {
declare const abstract: { abstract: { abstract: number } };
declare const f: any, x: any;
f < typeof abstract["abstract"].abstract > (x);
}

namespace RuntimeOptional {
declare const abstract: { abstract: { value: number } } | undefined;
declare const f: string, x: any;
f < typeof abstract?.abstract > (x);
f < typeof abstract?.abstract.value > (x);
f < typeof abstract?.["abstract"] > (x);
f < typeof abstract?.abstract["value"] > (x);
}
namespace RuntimeOptionalNested {
declare const abstract: { abstract: { value: number } | undefined };
declare const f: string, x: any;
f < typeof abstract.abstract?.value > (x);
f < typeof abstract.abstract?.["value"] > (x);
}
21 changes: 21 additions & 0 deletions __tests__/fixtures/ts-syntax/typeof-abstract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// A value named abstract must remain available to type queries in generic calls.
function abstract<T>(value: T): T { return value; }
namespace abstract { export const value = 0; }
function f<T>(value: T): T { return value; }
function tag<T>(parts: readonly string[]): string { return parts[0]; }
const holder = { abstract: abstract };

export function caller() {
f<typeof abstract>(abstract);
f<typeof abstract.value>(0);
f<typeof holder.abstract>(abstract);
tag<typeof abstract>`hello`;
return abstract(1);
}

type Parenthesized = (typeof abstract);
type Qualified = (typeof abstract.value);
type Property = typeof holder.abstract;
type Instantiated = typeof abstract<number>;
type ParenthesizedInstantiation = (typeof abstract<number>);
type Lookup = typeof abstract["value"];
21 changes: 21 additions & 0 deletions __tests__/fixtures/ts-syntax/typeof-abstract.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// A value named abstract must remain available to type queries in generic calls.
function abstract<T>(value: T): T { return value; }
namespace abstract { export const value = 0; }
function f<T>(value: T): T { return value; }
function tag<T>(parts: readonly string[]): string { return parts[0]; }
const holder = { abstract: abstract };

export function caller() {
f<typeof abstract>(abstract);
f<typeof abstract.value>(0);
f<typeof holder.abstract>(abstract);
tag<typeof abstract>`hello`;
return abstract(1);
}

type Parenthesized = (typeof abstract);
type Qualified = (typeof abstract.value);
type Property = typeof holder.abstract;
type Instantiated = typeof abstract<number>;
type ParenthesizedInstantiation = (typeof abstract<number>);
type Lookup = typeof abstract["value"];
Loading
Loading