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
74 changes: 46 additions & 28 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1905,46 +1905,64 @@ func (c *Checker) isBlockScopedNameDeclaredBeforeUse(declaration *ast.Node, usag
}

func (c *Checker) isUsedInFunctionOrInstanceProperty(usage *ast.Node, declaration *ast.Node, declContainer *ast.Node) bool {
for current := usage; current != nil && current != declContainer; current = current.Parent {
return ast.FindAncestorOrQuit(usage, func(current *ast.Node) ast.FindAncestorResult {
if current == declContainer {
return ast.FindAncestorQuit
}
if ast.IsFunctionLike(current) {
return ast.GetImmediatelyInvokedFunctionExpression(current) == nil
return ast.ToFindAncestorResult(ast.GetImmediatelyInvokedFunctionExpression(current) == nil)
}
if ast.IsClassStaticBlockDeclaration(current) {
return declaration.Pos() < usage.Pos()
return ast.ToFindAncestorResult(declaration.Pos() < usage.Pos())
}
if current.Parent != nil && ast.IsPropertyDeclaration(current.Parent) && current.Parent.Initializer() == current {
if ast.IsStatic(current.Parent) {
if ast.IsMethodDeclaration(declaration) {
return true
}
if ast.IsPropertyDeclaration(declaration) && ast.GetContainingClass(usage) == ast.GetContainingClass(declaration) {
propName := declaration.Name()
if ast.IsIdentifier(propName) || ast.IsPrivateIdentifier(propName) {
t := c.getTypeOfSymbol(c.getSymbolOfDeclaration(declaration))
staticBlocks := core.Filter(declaration.Parent.Members(), ast.IsClassStaticBlockDeclaration)
if c.isPropertyInitializedInStaticBlocks(propName, t, staticBlocks, declaration.Parent.Pos(), current.Pos()) {
return true

if current.Parent != nil && ast.IsPropertyDeclaration(current.Parent) {
propertyDeclaration := current.Parent
initializerOfProperty := propertyDeclaration.Initializer() == current
if initializerOfProperty {
Comment on lines +1921 to +1922
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit on naming and comparison order to make it more readable

Suggested change
initializerOfProperty := propertyDeclaration.Initializer() == current
if initializerOfProperty {
currentIsInitializer := current == propertyDeclaration.Initializer()
if currentIsInitializer {

or if you flip the order, I'd argue you don't need a variable anyway

Suggested change
initializerOfProperty := propertyDeclaration.Initializer() == current
if initializerOfProperty {
if current == propertyDeclaration.Initializer() {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is 1:1 ported so I don't really want to futz with it.

if ast.IsStatic(current.Parent) {
if ast.IsMethodDeclaration(declaration) {
return ast.FindAncestorTrue
}
if ast.IsPropertyDeclaration(declaration) && ast.GetContainingClass(usage) == ast.GetContainingClass(declaration) {
propName := declaration.Name()
if ast.IsIdentifier(propName) || ast.IsPrivateIdentifier(propName) {
t := c.getTypeOfSymbol(c.getSymbolOfDeclaration(declaration))
staticBlocks := core.Filter(declaration.Parent.Members(), ast.IsClassStaticBlockDeclaration)
if c.isPropertyInitializedInStaticBlocks(propName, t, staticBlocks, declaration.Parent.Pos(), current.Pos()) {
return ast.FindAncestorTrue
}
}
}
}
} else {
isDeclarationInstanceProperty := ast.IsPropertyDeclaration(declaration) && !ast.IsStatic(declaration)
if !isDeclarationInstanceProperty || ast.GetContainingClass(usage) != ast.GetContainingClass(declaration) {
return true
} else {
isDeclarationInstanceProperty := ast.IsPropertyDeclaration(declaration) && !ast.IsStatic(declaration)
if !isDeclarationInstanceProperty || ast.GetContainingClass(usage) != ast.GetContainingClass(declaration) {
return ast.FindAncestorTrue
}
}
}
}
if current.Parent != nil && ast.IsDecorator(current.Parent) && current.Parent.AsDecorator().Expression == current {

if current.Parent != nil && ast.IsDecorator(current.Parent) {
decorator := current.Parent.AsDecorator()
if ast.IsParameter(decorator.Parent) {
return c.isUsedInFunctionOrInstanceProperty(decorator.Parent.Parent.Parent, declaration, declContainer)
}
if ast.IsMethodDeclaration(decorator.Parent) {
return c.isUsedInFunctionOrInstanceProperty(decorator.Parent.Parent, declaration, declContainer)
if decorator.Expression == current {
if ast.IsParameter(decorator.Parent) {
if c.isUsedInFunctionOrInstanceProperty(decorator.Parent.Parent.Parent, declaration, declContainer) {
return ast.FindAncestorTrue
}
return ast.FindAncestorQuit
}
if ast.IsMethodDeclaration(decorator.Parent) {
if c.isUsedInFunctionOrInstanceProperty(decorator.Parent.Parent, declaration, declContainer) {
return ast.FindAncestorTrue
}
return ast.FindAncestorQuit
}
}
}
}
return false

return ast.FindAncestorFalse
}) != nil
}

func isImmediatelyUsedInInitializerOfBlockScopedVariable(declaration *ast.Node, usage *ast.Node, declContainer *ast.Node) bool {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//// [tests/cases/compiler/blockedScopeVariableNotUnused1.ts] ////

//// [blockedScopeVariableNotUnused1.ts]
export function foo() {
const _fn = () => {
;(() => numFilesSelected)()
}

const numFilesSelected = 1
}


//// [blockedScopeVariableNotUnused1.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.foo = foo;
function foo() {
const _fn = () => {
;
(() => numFilesSelected)();
};
const numFilesSelected = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//// [tests/cases/compiler/blockedScopeVariableNotUnused1.ts] ////

=== blockedScopeVariableNotUnused1.ts ===
export function foo() {
>foo : Symbol(foo, Decl(blockedScopeVariableNotUnused1.ts, 0, 0))

const _fn = () => {
>_fn : Symbol(_fn, Decl(blockedScopeVariableNotUnused1.ts, 1, 7))

;(() => numFilesSelected)()
>numFilesSelected : Symbol(numFilesSelected, Decl(blockedScopeVariableNotUnused1.ts, 5, 7))
}

const numFilesSelected = 1
>numFilesSelected : Symbol(numFilesSelected, Decl(blockedScopeVariableNotUnused1.ts, 5, 7))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [tests/cases/compiler/blockedScopeVariableNotUnused1.ts] ////

=== blockedScopeVariableNotUnused1.ts ===
export function foo() {
>foo : () => void

const _fn = () => {
>_fn : () => void
>() => { ;(() => numFilesSelected)() } : () => void

;(() => numFilesSelected)()
>(() => numFilesSelected)() : number
>(() => numFilesSelected) : () => number
>() => numFilesSelected : () => number
>numFilesSelected : 1
}

const numFilesSelected = 1
>numFilesSelected : 1
>1 : 1
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @strict: true

export function foo() {
const _fn = () => {
;(() => numFilesSelected)()
}

const numFilesSelected = 1
}