Skip to content

Infer symbol relationship for object literals property in return statement #248

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 2 commits into from
Apr 20, 2023
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
60 changes: 60 additions & 0 deletions snapshots/input/syntax/src/infer-relationship.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
interface Configuration {
property: number
}

function random(): number {
return Math.random()
}
export function returnStatement(): Configuration {
if (random() > 0) {
return {
property: 41,
}
}
for (let i = 0; i < 9; i++) {
if (random() > i) {
return {
property: 41,
}
}
}
for (const i of [1, 2, 3]) {
if (random() > i) {
return {
property: 41,
}
}
}
for (const i in { '1': 2 }) {
if (random() > Number.parseInt(i)) {
return {
property: 41,
}
}
}
while (random() < 0) {
return {
property: 41,
}
}
do {
if (random() > 0) {
return {
property: 41,
}
}
} while (random() < 0)

return {
property: 42,
}
}

export function returnStatementInsideArgumentExpression(): Configuration[] {
return [1].map<Configuration>(number => {
const incremented = number + 1
return {
property: incremented,
}
})
}
136 changes: 136 additions & 0 deletions snapshots/output/syntax/src/infer-relationship.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
interface Configuration {
// definition syntax 1.0.0 src/`infer-relationship.ts`/
//documentation ```ts\nmodule "infer-relationship.ts"\n```
// ^^^^^^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/Configuration#
// documentation ```ts\ninterface Configuration\n```
property: number
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
// documentation ```ts\n(property) property: number\n```
}

function random(): number {
// ^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/random().
// documentation ```ts\nfunction random(): number\n```
return Math.random()
// ^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Math#
// ^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Math.
// ^^^^ reference typescript 4.8.4 lib/`lib.es2015.core.d.ts`/Math#
// ^^^^ reference typescript 4.8.4 lib/`lib.es2015.symbol.wellknown.d.ts`/Math#
// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Math#random().
}
export function returnStatement(): Configuration {
// ^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/returnStatement().
// documentation ```ts\nfunction returnStatement(): Configuration\n```
// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/Configuration#
if (random() > 0) {
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().
return {
property: 41,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property0:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}
for (let i = 0; i < 9; i++) {
// ^ definition local 2
// documentation ```ts\nvar i: number\n```
// ^ reference local 2
// ^ reference local 2
if (random() > i) {
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().
// ^ reference local 2
return {
property: 41,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property1:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}
}
for (const i of [1, 2, 3]) {
// ^ definition local 5
// documentation ```ts\nvar i: number\n```
if (random() > i) {
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().
// ^ reference local 5
return {
property: 41,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property2:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}
}
for (const i in { '1': 2 }) {
// ^ definition local 8
// documentation ```ts\nvar i: string\n```
// ^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/`'1'0`:
// documentation ```ts\n(property) '1': number\n```
if (random() > Number.parseInt(i)) {
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().
// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number#
// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number.
// ^^^^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Number#
// ^^^^^^ reference typescript 4.8.4 lib/`lib.es2020.number.d.ts`/Number#
// ^^^^^^^^ reference typescript 4.8.4 lib/`lib.es2015.core.d.ts`/NumberConstructor#parseInt().
// ^ reference local 8
return {
property: 41,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property3:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}
}
while (random() < 0) {
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().
return {
property: 41,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property4:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}
do {
if (random() > 0) {
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().
return {
property: 41,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property5:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}
} while (random() < 0)
// ^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/random().

return {
property: 42,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property6:
// documentation ```ts\n(property) property: number\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`infer-relationship.ts`/Configuration#property.
}
}

export function returnStatementInsideArgumentExpression(): Configuration[] {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/returnStatementInsideArgumentExpression().
// documentation ```ts\nfunction returnStatementInsideArgumentExpression(): Configuration[]\n```
// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/Configuration#
return [1].map<Configuration>(number => {
// ^^^ reference typescript 4.8.4 lib/`lib.es5.d.ts`/Array#map().
// ^^^^^^^^^^^^^ reference syntax 1.0.0 src/`infer-relationship.ts`/Configuration#
// ^^^^^^ definition local 12
// documentation ```ts\n(parameter) number: number\n```
const incremented = number + 1
// ^^^^^^^^^^^ definition local 15
// documentation ```ts\nvar incremented: number\n```
// ^^^^^^ reference local 12
return {
property: incremented,
// ^^^^^^^^ definition syntax 1.0.0 src/`infer-relationship.ts`/property7:
// documentation ```ts\n(property) property: number\n```
// ^^^^^^^^^^^ reference local 15
}
})
}

3 changes: 3 additions & 0 deletions snapshots/output/syntax/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
property: 'a',
// ^^^^^^^^ definition syntax 1.0.0 src/`interface.ts`/property0:
// documentation ```ts\n(property) property: string\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`interface.ts`/Interface#property.
methodSignature(param: string): string {
// ^^^^^^^^^^^^^^^ definition local 4
// documentation ```ts\n(method) methodSignature(param: string): string\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`interface.ts`/Interface#methodSignature().
// ^^^^^ definition local 5
// documentation ```ts\n(parameter) param: string\n```
return param
Expand All @@ -37,6 +39,7 @@
methodSignature2: (param: string): string => {
// ^^^^^^^^^^^^^^^^ definition syntax 1.0.0 src/`interface.ts`/methodSignature20:
// documentation ```ts\n(property) methodSignature2: (param: string) => string\n```
// relationship implementation reference scip-typescript npm syntax 1.0.0 src/`interface.ts`/Interface#methodSignature2.
// ^^^^^ definition local 7
// documentation ```ts\n(parameter) param: string\n```
return param
Expand Down
45 changes: 35 additions & 10 deletions src/FileIndexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class FileIndexer {
}
public index(): void {
// Uncomment below if you want to skip certain files for local development.
// if (!this.sourceFile.fileName.includes('ClassWithPrivate')) {
// if (!this.sourceFile.fileName.includes('infer-relationship')) {
// return
// }
this.emitSourceFileOccurrence()
Expand Down Expand Up @@ -561,7 +561,10 @@ export class FileIndexer {
onAncestor(declaration)
}
if (ts.isObjectLiteralExpression(declaration)) {
const tpe = this.inferredTypeOfObjectLiteral(declaration)
const tpe = this.inferredTypeOfObjectLiteral(
declaration.parent,
declaration
)
for (const symbolDeclaration of tpe.symbol?.declarations || []) {
loop(symbolDeclaration)
}
Expand Down Expand Up @@ -592,19 +595,41 @@ export class FileIndexer {
// `SomeInterface`. The object literal could satisfy many types, but in this
// particular location must only satisfy `SomeInterface`.
private inferredTypeOfObjectLiteral(
node: ts.ObjectLiteralExpression
node: ts.Node,
literal: ts.ObjectLiteralExpression
): ts.Type {
if (ts.isVariableDeclaration(node.parent)) {
if (
ts.isIfStatement(node) ||
ts.isForStatement(node) ||
ts.isForInStatement(node) ||
ts.isForOfStatement(node) ||
ts.isWhileStatement(node) ||
ts.isDoStatement(node) ||
ts.isReturnStatement(node) ||
ts.isBlock(node)
) {
return this.inferredTypeOfObjectLiteral(node.parent, literal)
}

if (ts.isVariableDeclaration(node)) {
// Example, return `SomeInterface` from `const x: SomeInterface = {y: 42}`.
return this.checker.getTypeAtLocation(node.parent.name)
return this.checker.getTypeAtLocation(node.name)
}

if (ts.isFunctionLike(node)) {
const functionType = this.checker.getTypeAtLocation(node)
const callSignatures = functionType.getCallSignatures()
if (callSignatures.length > 0) {
return callSignatures[0].getReturnType()
}
}

if (ts.isCallOrNewExpression(node.parent)) {
if (ts.isCallOrNewExpression(node)) {
// Example: return the type of the second parameter of `someMethod` from
// the expression `someMethod(someParameter, {y: 42})`.
const signature = this.checker.getResolvedSignature(node.parent)
for (const [index, argument] of (node.parent.arguments || []).entries()) {
if (argument === node) {
const signature = this.checker.getResolvedSignature(node)
for (const [index, argument] of (node.arguments || []).entries()) {
if (argument === literal) {
const parameterSymbol = signature?.getParameters()[index]
if (parameterSymbol) {
return this.checker.getTypeOfSymbolAtLocation(parameterSymbol, node)
Expand All @@ -613,7 +638,7 @@ export class FileIndexer {
}
}

return this.checker.getTypeAtLocation(node)
return this.checker.getTypeAtLocation(literal)
}
}

Expand Down