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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
41 changes: 31 additions & 10 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29602,7 +29602,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
node.kind === SyntaxKind.PropertyDeclaration)!;
}

// Check if a parameter or catch variable is assigned anywhere
// Check if a parameter, catch variable, or mutable local variable is assigned anywhere definitely
function isSymbolAssignedDefinitely(symbol: Symbol) {
if (symbol.lastAssignmentPos !== undefined) {
return symbol.lastAssignmentPos < 0;
}
return isSymbolAssigned(symbol) && symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0;
}

// Check if a parameter, catch variable, or mutable local variable is assigned anywhere
function isSymbolAssigned(symbol: Symbol) {
return !isPastLastAssignment(symbol, /*location*/ undefined);
}
Expand All @@ -29621,7 +29629,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
markNodeAssignments(parent);
}
}
return !symbol.lastAssignmentPos || location && symbol.lastAssignmentPos < location.pos;
return !symbol.lastAssignmentPos || location && Math.abs(symbol.lastAssignmentPos) < location.pos;
}

// Check if a parameter or catch variable (or their bindings elements) is assigned anywhere
Expand Down Expand Up @@ -29655,12 +29663,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function markNodeAssignments(node: Node) {
switch (node.kind) {
case SyntaxKind.Identifier:
if (isAssignmentTarget(node)) {
const assigmentTarget = getAssignmentTargetKind(node);
if (assigmentTarget !== AssignmentKind.None) {
const symbol = getResolvedSymbol(node as Identifier);
if (isParameterOrMutableLocalVariable(symbol) && symbol.lastAssignmentPos !== Number.MAX_VALUE) {
const referencingFunction = findAncestor(node, isFunctionOrSourceFile);
const declaringFunction = findAncestor(symbol.valueDeclaration, isFunctionOrSourceFile);
symbol.lastAssignmentPos = referencingFunction === declaringFunction ? extendAssignmentPosition(node, symbol.valueDeclaration!) : Number.MAX_VALUE;
const hasDefiniteAssignment = assigmentTarget === AssignmentKind.Definite || (symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0);
if (isParameterOrMutableLocalVariable(symbol)) {
if (symbol.lastAssignmentPos === undefined || Math.abs(symbol.lastAssignmentPos) !== Number.MAX_VALUE) {
const referencingFunction = findAncestor(node, isFunctionOrSourceFile);
const declaringFunction = findAncestor(symbol.valueDeclaration, isFunctionOrSourceFile);
symbol.lastAssignmentPos = referencingFunction === declaringFunction ? extendAssignmentPosition(node, symbol.valueDeclaration!) : Number.MAX_VALUE;
}
if (hasDefiniteAssignment && symbol.lastAssignmentPos > 0) {
symbol.lastAssignmentPos *= -1;
}
}
}
return;
Expand All @@ -29670,7 +29685,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!(node as ExportSpecifier).isTypeOnly && !exportDeclaration.isTypeOnly && !exportDeclaration.moduleSpecifier && name.kind !== SyntaxKind.StringLiteral) {
const symbol = resolveEntityName(name, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true);
if (symbol && isParameterOrMutableLocalVariable(symbol)) {
symbol.lastAssignmentPos = Number.MAX_VALUE;
const sign = symbol.lastAssignmentPos !== undefined && symbol.lastAssignmentPos < 0 ? -1 : 1;
symbol.lastAssignmentPos = sign * Number.MAX_VALUE;
}
}
return;
Expand Down Expand Up @@ -30414,6 +30430,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
let declaration = localOrExportSymbol.valueDeclaration;
const immediateDeclaration = declaration;

// If the identifier is declared in a binding pattern for which we're currently computing the implied type and the
// reference occurs with the same binding pattern, return the non-inferrable any type. This for example occurs in
Expand Down Expand Up @@ -30503,7 +30520,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
// declaration container are the same).
const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) ||
const isNeverInitialized = immediateDeclaration && isVariableDeclaration(immediateDeclaration) && !immediateDeclaration.initializer && !immediateDeclaration.exclamationToken && isMutableLocalVariableDeclaration(immediateDeclaration) && !isSymbolAssignedDefinitely(symbol);
const assumeInitialized = isParameter || isAlias ||
(isOuterVariable && !isNeverInitialized) ||
isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) ||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 ||
isInTypeQuery(node) || isInAmbientOrTypeNode(node) || node.parent.kind === SyntaxKind.ExportSpecifier) ||
node.parent.kind === SyntaxKind.NonNullExpression ||
Expand Down Expand Up @@ -43495,7 +43515,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
if (node.body) { // Don't report unused parameters in overloads
// Only report unused parameters on the implementation, not overloads.
if (node.body) {
checkUnusedLocalsAndParameters(node, addDiagnostic);
}
checkUnusedTypeParameters(node, addDiagnostic);
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/transformers/classFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ import {
} from "../_namespaces/ts.js";

const enum ClassPropertySubstitutionFlags {
None = 0,
/**
* Enables substitutions for class expressions with static fields
* which have initializers that reference the class name.
Expand Down Expand Up @@ -401,7 +402,7 @@ export function transformClassFields(context: TransformationContext): (x: Source
context.onEmitNode = onEmitNode;

let shouldTransformPrivateStaticElementsInFile = false;
let enabledSubstitutions: ClassPropertySubstitutionFlags;
let enabledSubstitutions = ClassPropertySubstitutionFlags.None;

let classAliases: Identifier[];

Expand Down
3 changes: 2 additions & 1 deletion src/compiler/transformers/es2015.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ import {
} from "../_namespaces/ts.js";

const enum ES2015SubstitutionFlags {
None = 0,
/** Enables substitutions for captured `this` */
CapturedThis = 1 << 0,
/** Enables substitutions for block-scoped bindings. */
Expand Down Expand Up @@ -523,7 +524,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile
* They are persisted between each SourceFile transformation and should not
* be reset.
*/
let enabledSubstitutions: ES2015SubstitutionFlags;
let enabledSubstitutions = ES2015SubstitutionFlags.None;

return chainBundle(context, transformSourceFile);

Expand Down
3 changes: 2 additions & 1 deletion src/compiler/transformers/es2017.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ import {
type SuperContainer = ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration;

const enum ES2017SubstitutionFlags {
None = 0,
/** Enables substitutions for async methods with `super` calls. */
AsyncMethodsWithSuper = 1 << 0,
}
Expand Down Expand Up @@ -132,7 +133,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile
* Keeps track of whether expression substitution has been enabled for specific edge cases.
* They are persisted between each SourceFile transformation and should not be reset.
*/
let enabledSubstitutions: ES2017SubstitutionFlags;
let enabledSubstitutions = ES2017SubstitutionFlags.None;

/**
* This keeps track of containers where `super` is valid, for use with
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/transformers/es2018.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ import {
} from "../_namespaces/ts.js";

const enum ESNextSubstitutionFlags {
None = 0,
/** Enables substitutions for async methods with `super` calls. */
AsyncMethodsWithSuper = 1 << 0,
}
Expand Down Expand Up @@ -170,7 +171,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile
context.onSubstituteNode = onSubstituteNode;

let exportedVariableStatement = false;
let enabledSubstitutions: ESNextSubstitutionFlags;
let enabledSubstitutions = ESNextSubstitutionFlags.None;
let enclosingFunctionFlags: FunctionFlags;
let parametersWithPrecedingObjectRestOrSpread: Set<ParameterDeclaration> | undefined;
let enclosingSuperContainerFlags: NodeCheckFlags = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ import {
const USE_NEW_TYPE_METADATA_FORMAT = false;

const enum TypeScriptSubstitutionFlags {
None = 0,
/** Enables substitutions for namespace exports. */
NamespaceExports = 1 << 1,
/* Enables substitutions for unqualified enum members */
Expand Down Expand Up @@ -270,7 +271,7 @@ export function transformTypeScript(context: TransformationContext) {
* Keeps track of whether expression substitution has been enabled for specific edge cases.
* They are persisted between each SourceFile transformation and should not be reset.
*/
let enabledSubstitutions: TypeScriptSubstitutionFlags;
let enabledSubstitutions = TypeScriptSubstitutionFlags.None;

/**
* Keeps track of whether we are within any containing namespaces when performing
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5970,7 +5970,7 @@ export interface Symbol {
/** @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/** @internal */ constEnumOnlyModule: boolean | undefined; // True if module contains only const enums or other modules with only const enums
/** @internal */ isReferenced?: SymbolFlags; // True if the symbol is referenced elsewhere. Keeps track of the meaning of a reference in case a symbol is both a type parameter and parameter.
/** @internal */ lastAssignmentPos?: number; // Source position of last node that assigns value to symbol
/** @internal */ lastAssignmentPos?: number; // Source position of last node that assigns value to symbol. Negative if it is assigned anywhere definitely
/** @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol?
/** @internal */ assignmentDeclarationMembers?: Map<number, Declaration>; // detected late-bound assignment declarations associated with the symbol
}
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ import {
forEachChild,
forEachChildRecursively,
ForInOrOfStatement,
ForInStatement,
ForOfStatement,
ForStatement,
FunctionBody,
FunctionDeclaration,
Expand Down Expand Up @@ -7906,6 +7908,9 @@ function accessKind(node: Node): AccessKind {
return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent);
case SyntaxKind.ArrayLiteralExpression:
return accessKind(parent);
case SyntaxKind.ForInStatement:
case SyntaxKind.ForOfStatement:
return node === (parent as ForInStatement | ForOfStatement).initializer ? AccessKind.Write : AccessKind.Read;
default:
return AccessKind.Read;
}
Expand Down
17 changes: 14 additions & 3 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4456,7 +4456,7 @@ export class ProjectService {
toRetainConfiguredProjects: Set<ConfiguredProject> | undefined,
openFilesWithRetainedConfiguredProject: Set<Path> | undefined,
externalProjectsRetainingConfiguredProjects: Set<string> | undefined,
) {
): Set<ConfiguredProject> {
const toRemoveConfiguredProjects = new Set(this.configuredProjects.values());
const markOriginalProjectsAsUsed = (project: Project) => {
if (project.originalConfiguredProjects && (isConfiguredProject(project) || !project.isOrphan())) {
Expand All @@ -4469,6 +4469,8 @@ export class ProjectService {
}
};
toRetainConfiguredProjects?.forEach(retainConfiguredProject);
// Everything needs to be retained, fast path to skip all the work
if (!toRemoveConfiguredProjects.size) return toRemoveConfiguredProjects;

// Do not remove configured projects that are used as original projects of other
this.inferredProjects.forEach(markOriginalProjectsAsUsed);
Expand All @@ -4479,7 +4481,10 @@ export class ProjectService {
projects.forEach(retainConfiguredProject);
}
});
this.openFiles.forEach((_projectRootPath, path) => {
// Everything needs to be retained, fast path to skip all the work
if (!toRemoveConfiguredProjects.size) return toRemoveConfiguredProjects;

forEachEntry(this.openFiles, (_projectRootPath, path) => {
if (openFilesWithRetainedConfiguredProject?.has(path)) return;
const info = this.getScriptInfoForPath(path)!;
// Part of external project
Expand All @@ -4491,15 +4496,21 @@ export class ProjectService {
);
if (result?.defaultProject) {
result?.seenProjects.forEach(retainConfiguredProject);
// Everything needs to be retained, fast path to skip all the work
if (!toRemoveConfiguredProjects.size) return toRemoveConfiguredProjects;
}
});

// Everything needs to be retained, fast path to skip all the work
if (!toRemoveConfiguredProjects.size) return toRemoveConfiguredProjects;

// Retain all the configured projects that have pending updates
// or the ones that is referencing retained project (or to be retained)
this.configuredProjects.forEach(project => {
forEachEntry(this.configuredProjects, project => {
if (toRemoveConfiguredProjects.has(project)) {
if (isPendingUpdate(project) || forEachReferencedProject(project, isRetained)) {
retainConfiguredProject(project);
if (!toRemoveConfiguredProjects.size) return toRemoveConfiguredProjects;
}
}
});
Expand Down
15 changes: 4 additions & 11 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1365,20 +1365,13 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo

/** @internal */
onAutoImportProviderSettingsChanged() {
if (this.autoImportProviderHost === false) {
this.autoImportProviderHost = undefined;
}
else {
this.autoImportProviderHost?.markAsDirty();
}
this.markAutoImportProviderAsDirty();
}

/** @internal */
onPackageJsonChange() {
this.moduleSpecifierCache.clear();
if (this.autoImportProviderHost) {
this.autoImportProviderHost.markAsDirty();
}
this.markAutoImportProviderAsDirty();
}

/** @internal */
Expand Down Expand Up @@ -2275,7 +2268,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
if (dependencySelection) {
tracing?.push(tracing.Phase.Session, "getPackageJsonAutoImportProvider");
const start = timestamp();
this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.getHostForAutoImportProvider(), this.documentRegistry);
this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.getHostForAutoImportProvider(), this.documentRegistry) ?? false;
if (this.autoImportProviderHost) {
updateProjectIfDirty(this.autoImportProviderHost);
this.sendPerformanceEvent("CreatePackageJsonAutoImportProvider", timestamp() - start);
Expand Down Expand Up @@ -2552,7 +2545,7 @@ export class AutoImportProviderProject extends Project {
const symlinkCache = hostProject.getSymlinkCache();
for (const name of arrayFrom(dependencyNames.keys())) {
// Avoid creating a large project that would significantly slow down time to editor interactivity
if (dependencySelection === PackageJsonAutoImportPreference.Auto && dependenciesAdded > this.maxDependencies) {
if (dependencySelection === PackageJsonAutoImportPreference.Auto && dependenciesAdded >= this.maxDependencies) {
hostProject.log(`AutoImportProviderProject: attempted to add more than ${this.maxDependencies} dependencies. Aborting.`);
return ts.emptyArray;
}
Expand Down
3 changes: 2 additions & 1 deletion src/testRunner/unittests/tsserver/autoImportProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {

host.writeFile(packageJson.path, packageJson.content);
session.host.baselineHost("Before getAutoImportProvider");
host.runQueuedTimeoutCallbacks();
assert.ok(session.getProjectService().configuredProjects.get(tsconfig.path)!.getLanguageService().getAutoImportProvider());
session.host.baselineHost("After getAutoImportProvider");
baselineTsserverLogs("autoImportProvider", "Responds to package_json changes", session);
Expand Down Expand Up @@ -272,7 +273,7 @@ describe("unittests:: tsserver:: autoImportProvider", () => {
];

const packages = [];
for (let i = 0; i < 11; i++) {
for (let i = 0; i < 10; i++) {
packages.push(createPackage(i));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// for (<|var { [|property1|]: p1 } of elems|>) {
// }
// var p2;
// for (<|{ [|{| isWriteAccess: true |}property1|] : p2 } of elems|>) {
// for (<|{ [|property1|] : p2 } of elems|>) {
// }

// === Definitions ===
Expand Down Expand Up @@ -94,7 +94,7 @@
// for (<|var { [|property1|]: p1 } of elems|>) {
// }
// var p2;
// for (<|{ [|{| isWriteAccess: true |}property1|] : p2 } of elems|>) {
// for (<|{ [|property1|] : p2 } of elems|>) {
// }

// === Definitions ===
Expand Down Expand Up @@ -180,7 +180,7 @@
// for (<|var { /*FIND ALL REFS*/[|property1|]: p1 } of elems|>) {
// }
// var p2;
// for (<|{ [|{| isWriteAccess: true |}property1|] : p2 } of elems|>) {
// for (<|{ [|property1|] : p2 } of elems|>) {
// }

// === Definitions ===
Expand Down Expand Up @@ -270,7 +270,7 @@
// for (<|var { [|property1|]: p1 } of elems|>) {
// }
// var p2;
// for (<|{ /*FIND ALL REFS*/[|{| isWriteAccess: true, isDefinition: true |}property1|] : p2 } of elems|>) {
// for (<|{ /*FIND ALL REFS*/[|{| isDefinition: true |}property1|] : p2 } of elems|>) {
// }

// === Definitions ===
Expand Down Expand Up @@ -358,7 +358,7 @@
// for (<|var { [|{| defId: 0 |}property1|]: p1 } of elems|>) {
// }
// var p2;
// for (<|{ [|{| defId: 0, isWriteAccess: true |}property1|] : p2 } of elems|>) {
// for (<|{ [|{| defId: 0 |}property1|] : p2 } of elems|>) {
// }

// === Definitions ===
Expand Down
Loading