diff --git a/fixtures/jsii-calc/lib/decorators.ts b/fixtures/jsii-calc/lib/decorators.ts new file mode 100644 index 00000000..a3e89780 --- /dev/null +++ b/fixtures/jsii-calc/lib/decorators.ts @@ -0,0 +1,50 @@ +type Constructor = { new (...args: any[]): {} }; + +export function functionReturnsClasstype(ctr: T) { + return class extends ctr { + }; +} + +/** + * A class decorator that changes inherited state and adds a readonly field to the class. + * + * This wasn't the thing that was exploding, see `function-returning-anonymous-class.ts` for that. + * Nevertheless, this makes for a good class decorator demo. + */ +export function classDecorator(x: typeof SomeDecoratedClass): typeof SomeDecoratedClass { + const ret = class extends x { + constructor() { + super(); + this.state = this.state + this.state; + } + }; + + // This adds a field to the class, but we can't reflect that in the type because of the limitations + // of decorators. That's we advertise it through interface merging below. + (ret.prototype as any)['field'] = 'some_added_field'; + + return ret; +} + +@classDecorator +export class SomeDecoratedClass { + protected state = 'state'; + + public accessState() { + return this.state; + } +} + +export interface SomeDecoratedClass { + readonly field: string; +} + +/** + * Exercise the above code + */ +function tryDecoratedClass() { + const instance = new SomeDecoratedClass(); + return instance.field; +} +// Suppress unused locals warnings +void tryDecoratedClass; \ No newline at end of file diff --git a/fixtures/jsii-calc/lib/function-returning-anonymous-class.ts b/fixtures/jsii-calc/lib/function-returning-anonymous-class.ts new file mode 100644 index 00000000..4e0efe37 --- /dev/null +++ b/fixtures/jsii-calc/lib/function-returning-anonymous-class.ts @@ -0,0 +1,17 @@ +type Constructor = { new (...args: any[]): {} }; + +/** + * Just the mere presence of this function is enough to break jsii, even if it's not exported from + * the jsii root module. + * + * The reason is that when we add deprecation warnings we visit all functions in all files. + */ +export function propertyInjectionDecorator(ctr: T) { + // Important for the bug: the anonymous class extends something, *and* + // declares a method. + return class extends ctr { + public someMethod(): string { + return 'abc'; + } + }; +} \ No newline at end of file diff --git a/fixtures/jsii-calc/lib/index.ts b/fixtures/jsii-calc/lib/index.ts index 49fec18b..b0b2f91a 100644 --- a/fixtures/jsii-calc/lib/index.ts +++ b/fixtures/jsii-calc/lib/index.ts @@ -9,6 +9,7 @@ export * from './stability'; export * from './submodules'; export * from './container-types'; export * from './indirect-implementation'; +export * from './decorators'; export * as submodule from './submodule'; export * as onlystatic from './only-static'; diff --git a/src/common/symbol-id.ts b/src/common/symbol-id.ts index 90209739..33333e44 100644 --- a/src/common/symbol-id.ts +++ b/src/common/symbol-id.ts @@ -49,9 +49,13 @@ interface SymbolIdOptions { */ export function symbolIdentifier( typeChecker: ts.TypeChecker, - sym: ts.Symbol, + sym: ts.Symbol | undefined, options: SymbolIdOptions = {}, ): string | undefined { + if (!sym) { + return undefined; + } + // If this symbol happens to be an alias, resolve it first // eslint-disable-next-line no-bitwise while ((sym.flags & ts.SymbolFlags.Alias) !== 0) { diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index 87be9bde..ab2a5783 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -1693,14 +1693,14 @@ const foo = 'bar'; "jsii-calc.anonymous": { "locationInModule": { "filename": "lib/index.ts", - "line": 28, + "line": 29, }, "symbolId": "lib/anonymous/index:", }, "jsii-calc.cdk16625": { "locationInModule": { "filename": "lib/index.ts", - "line": 24, + "line": 25, }, "symbolId": "lib/cdk16625/index:", }, @@ -1714,7 +1714,7 @@ const foo = 'bar'; "jsii-calc.cdk22369": { "locationInModule": { "filename": "lib/index.ts", - "line": 25, + "line": 26, }, "symbolId": "lib/cdk22369/index:", }, @@ -1728,7 +1728,7 @@ const foo = 'bar'; "jsii-calc.homonymousForwardReferences": { "locationInModule": { "filename": "lib/index.ts", - "line": 30, + "line": 31, }, "readme": { "markdown": "Verifies homonymous forward references don't trip the Python type checker @@ -1756,35 +1756,35 @@ information, which was reported in https://github.com/aws/jsii/issues/3818. "jsii-calc.jsii3656": { "locationInModule": { "filename": "lib/index.ts", - "line": 26, + "line": 27, }, "symbolId": "lib/jsii3656/index:", }, "jsii-calc.module2530": { "locationInModule": { "filename": "lib/index.ts", - "line": 21, + "line": 22, }, "symbolId": "lib/module2530/index:", }, "jsii-calc.module2617": { "locationInModule": { "filename": "lib/index.ts", - "line": 17, + "line": 18, }, "symbolId": "lib/module2617/index:", }, "jsii-calc.module2647": { "locationInModule": { "filename": "lib/index.ts", - "line": 16, + "line": 17, }, "symbolId": "lib/module2647/index:", }, "jsii-calc.module2689": { "locationInModule": { "filename": "lib/index.ts", - "line": 18, + "line": 19, }, "symbolId": "lib/module2689/index:", }, @@ -1819,7 +1819,7 @@ information, which was reported in https://github.com/aws/jsii/issues/3818. "jsii-calc.module2692": { "locationInModule": { "filename": "lib/index.ts", - "line": 20, + "line": 21, }, "symbolId": "lib/module2692/index:", }, @@ -1840,21 +1840,21 @@ information, which was reported in https://github.com/aws/jsii/issues/3818. "jsii-calc.module2700": { "locationInModule": { "filename": "lib/index.ts", - "line": 22, + "line": 23, }, "symbolId": "lib/module2700/index:", }, "jsii-calc.module2702": { "locationInModule": { "filename": "lib/index.ts", - "line": 19, + "line": 20, }, "symbolId": "lib/module2702/index:", }, "jsii-calc.nodirect": { "locationInModule": { "filename": "lib/index.ts", - "line": 15, + "line": 16, }, "symbolId": "lib/no-direct-types/index:", }, @@ -1875,14 +1875,14 @@ information, which was reported in https://github.com/aws/jsii/issues/3818. "jsii-calc.onlystatic": { "locationInModule": { "filename": "lib/index.ts", - "line": 14, + "line": 15, }, "symbolId": "lib/only-static/index:", }, "jsii-calc.submodule": { "locationInModule": { "filename": "lib/index.ts", - "line": 13, + "line": 14, }, "readme": { "markdown": "Read you, read me @@ -1952,7 +1952,7 @@ This is the readme of the \`jsii-calc.submodule.isolated\` module. "jsii-calc.union": { "locationInModule": { "filename": "lib/index.ts", - "line": 29, + "line": 30, }, "symbolId": "lib/union:", }, @@ -14613,6 +14613,72 @@ this it would break runtime type checks in the JVM or CLR.", ], "symbolId": "lib/calculator:SmellyStruct", }, + "jsii-calc.SomeDecoratedClass": { + "assembly": "jsii-calc", + "docs": { + "stability": "stable", + }, + "fqn": "jsii-calc.SomeDecoratedClass", + "initializer": { + "docs": { + "stability": "stable", + }, + }, + "kind": "class", + "locationInModule": { + "filename": "lib/decorators.ts", + "line": 29, + }, + "methods": [ + { + "docs": { + "stability": "stable", + }, + "locationInModule": { + "filename": "lib/decorators.ts", + "line": 33, + }, + "name": "accessState", + "returns": { + "type": { + "primitive": "string", + }, + }, + }, + ], + "name": "SomeDecoratedClass", + "properties": [ + { + "docs": { + "stability": "stable", + }, + "immutable": true, + "locationInModule": { + "filename": "lib/decorators.ts", + "line": 39, + }, + "name": "field", + "type": { + "primitive": "string", + }, + }, + { + "docs": { + "stability": "stable", + }, + "locationInModule": { + "filename": "lib/decorators.ts", + "line": 31, + }, + "name": "state", + "protected": true, + "type": { + "primitive": "string", + }, + }, + ], + "symbolId": "lib/decorators:SomeDecoratedClass", + }, "jsii-calc.SomeTypeJsii976": { "assembly": "jsii-calc", "docs": {