Skip to content

Commit ae8b70f

Browse files
committed
Cover prototype property assignments
Amp-Thread-ID: https://ampcode.com/threads/T-01a029e2-5095-710a-9cce-0c6d8645c173
1 parent c4cab96 commit ae8b70f

5 files changed

Lines changed: 56 additions & 19 deletions

File tree

snapshots/input/prototype-members/src/connection.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@ Connection.prototype = {
44
getSchemaVersion() {
55
return 0
66
},
7+
getVersion: function () {
8+
return 1
9+
},
10+
version: 1,
711
}

snapshots/input/prototype-members/src/use.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,9 @@
22

33
/** @param {Connection} connection */
44
export function schemaVersion(connection) {
5-
return connection.getSchemaVersion()
5+
return [
6+
connection.getSchemaVersion(),
7+
connection.getVersion(),
8+
connection.version,
9+
]
610
}

snapshots/output/prototype-members/src/connection.mjs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ export function Connection() {}
66

77
Connection.prototype = {
88
//^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().
9-
//^^^^^^^^^ reference local 3
10-
// ^^^^^^^^^ reference local 2
9+
// ^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().
1110
getSchemaVersion() {
1211
//^^^^^^^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
1312
return 0
1413
},
14+
getVersion: function () {
15+
//^^^^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().getVersion.
16+
return 1
17+
},
18+
version: 1,
19+
//^^^^^^^ definition prototype-members 1.0.0 src/`connection.mjs`/Connection().version.
1520
}
1621

snapshots/output/prototype-members/src/use.mjs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@
77
export function schemaVersion(connection) {
88
// ^^^^^^^^^^^^^ definition prototype-members 1.0.0 src/`use.mjs`/schemaVersion().
99
// ^^^^^^^^^^ definition prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
10-
return connection.getSchemaVersion()
11-
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
12-
// ^^^^^^^^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
10+
return [
11+
connection.getSchemaVersion(),
12+
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
13+
// ^^^^^^^^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().getSchemaVersion().
14+
connection.getVersion(),
15+
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
16+
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().getVersion.
17+
connection.version,
18+
// ^^^^^^^^^^ reference prototype-members 1.0.0 src/`use.mjs`/schemaVersion().(connection)
19+
// ^^^^^^^ reference prototype-members 1.0.0 src/`connection.mjs`/Connection().version.
20+
]
1321
}
1422

src/FileIndexer.ts

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -426,14 +426,24 @@ export class FileIndexer {
426426
}
427427

428428
private prototypeAssignmentOwner(node: ts.Node): ts.Declaration | undefined {
429-
if (!ts.isObjectLiteralExpression(node)) {
430-
return
431-
}
432-
const assignment = node.parent
429+
const assignment = ts.isBinaryExpression(node)
430+
? node
431+
: ts.isObjectLiteralExpression(node)
432+
? node.parent
433+
: ts.isPropertyAccessExpression(node)
434+
? node.parent
435+
: ts.isIdentifier(node) && ts.isPropertyAccessExpression(node.parent)
436+
? node.parent.parent
437+
: (ts.isPropertyAssignment(node) ||
438+
ts.isShorthandPropertyAssignment(node)) &&
439+
ts.isObjectLiteralExpression(node.parent)
440+
? node.parent.parent
441+
: undefined
433442
if (
443+
!assignment ||
434444
!ts.isBinaryExpression(assignment) ||
435445
assignment.operatorToken.kind !== ts.SyntaxKind.EqualsToken ||
436-
assignment.right !== node ||
446+
!ts.isObjectLiteralExpression(assignment.right) ||
437447
!ts.isPropertyAccessExpression(assignment.left) ||
438448
assignment.left.name.text !== 'prototype'
439449
) {
@@ -462,6 +472,20 @@ export class FileIndexer {
462472
}
463473
return this.cached(node, package_)
464474
}
475+
476+
const prototypeOwner = this.prototypeAssignmentOwner(node)
477+
if (prototypeOwner) {
478+
// Declarations attached to the assignment and its object literal belong
479+
// to the constructor. Property assignments need their own stable member
480+
// descriptor instead of the counter-based object-property fallback.
481+
const owner = this.scipSymbol(prototypeOwner)
482+
const symbol =
483+
ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)
484+
? ScipSymbol.global(owner, termDescriptor(node.name.getText()))
485+
: owner
486+
return this.cached(node, symbol)
487+
}
488+
465489
if (
466490
ts.isPropertyAssignment(node) ||
467491
ts.isShorthandPropertyAssignment(node)
@@ -512,14 +536,6 @@ export class FileIndexer {
512536
}
513537
}
514538

515-
const prototypeOwner = this.prototypeAssignmentOwner(node)
516-
if (prototypeOwner) {
517-
// Methods in `Constructor.prototype = { ... }` belong to the constructor,
518-
// not to an anonymous object local to this file. Giving that object the
519-
// constructor's identity makes its members stable across files.
520-
return this.cached(node, this.scipSymbol(prototypeOwner))
521-
}
522-
523539
const owner = this.scipSymbol(node.parent)
524540
if (owner.isEmpty() || owner.isLocal()) {
525541
return this.newLocalSymbol(node)

0 commit comments

Comments
 (0)