diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 076830b47f851..9b40b0dae7092 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -65,7 +65,6 @@ namespace ts { const compilerOptions = host.getCompilerOptions(); const languageVersion = getEmitScriptTarget(compilerOptions); const modulekind = getEmitModuleKind(compilerOptions); - const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters; const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions); const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes"); @@ -313,7 +312,22 @@ namespace ts { return node && getTypeArgumentConstraint(node); }, - getSuggestionDiagnostics: file => suggestionDiagnostics.get(file.fileName) || emptyArray, + getSuggestionDiagnostics: file => { + return (suggestionDiagnostics.get(file.fileName) || emptyArray).concat(getUnusedDiagnostics()); + function getUnusedDiagnostics(): ReadonlyArray { + if (file.isDeclarationFile) return emptyArray; + + checkSourceFile(file); + const diagnostics: Diagnostic[] = []; + Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked)); + checkUnusedIdentifiers(allPotentiallyUnusedIdentifiers.get(file.fileName)!, (kind, diag) => { + if (!unusedIsError(kind)) { + diagnostics.push({ ...diag, category: DiagnosticCategory.Suggestion }); + } + }); + return diagnostics; + } + }, }; const tupleTypes: GenericType[] = []; @@ -422,8 +436,9 @@ namespace ts { let deferredGlobalTemplateStringsArrayType: ObjectType; let deferredNodes: Node[]; - let deferredUnusedIdentifierNodes: Node[]; - const seenDeferredUnusedIdentifiers = createMap(); // For assertion that we don't defer the same identifier twice + const allPotentiallyUnusedIdentifiers = createMap>(); // key is file name + let potentiallyUnusedIdentifiers: PotentiallyUnusedIdentifier[]; // Potentially unused identifiers in the source file currently being checked. + const seenPotentiallyUnusedIdentifiers = createMap(); // For assertion that we don't defer the same identifier twice let flowLoopStart = 0; let flowLoopCount = 0; @@ -455,17 +470,6 @@ namespace ts { const diagnostics = createDiagnosticCollection(); // Suggestion diagnostics must have a file. Keyed by source file name. const suggestionDiagnostics = createMultiMap(); - function addSuggestionDiagnostic(diag: Diagnostic): void { - suggestionDiagnostics.add(diag.file.fileName, { ...diag, category: DiagnosticCategory.Suggestion }); - } - function addErrorOrSuggestionDiagnostic(isError: boolean, diag: Diagnostic): void { - if (isError) { - diagnostics.add(diag); - } - else { - addSuggestionDiagnostic(diag); - } - } const enum TypeFacts { None = 0, @@ -624,6 +628,12 @@ namespace ts { resolvedMembers = "resolvedMembers" } + const enum UnusedKind { + Local, + Parameter, + } + type AddUnusedDiagnostic = (type: UnusedKind, diagnostic: Diagnostic) => void; + const builtinGlobals = createSymbolTable(); builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol); @@ -818,6 +828,18 @@ namespace ts { diagnostics.add(diagnostic); } + function addErrorOrSuggestion(isError: boolean, diagnostic: Diagnostic) { + if (isError) { + diagnostics.add(diagnostic); + } + else { + suggestionDiagnostics.add(diagnostic.file.fileName, { ...diagnostic, category: DiagnosticCategory.Suggestion }); + } + } + function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); + } + function createSymbol(flags: SymbolFlags, name: __String, checkFlags?: CheckFlags) { symbolCount++; const symbol = (new Symbol(flags | SymbolFlags.Transient, name)); @@ -1433,7 +1455,7 @@ namespace ts { // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. // If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself. // That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used. - if (isUse && result && noUnusedIdentifiers && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) { + if (isUse && result && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) { result.isReferenced |= meaning; } @@ -2124,7 +2146,7 @@ namespace ts { if (sourceFile) { if (sourceFile.symbol) { if (resolvedModule.isExternalLibraryImport && !extensionIsTypeScript(resolvedModule.extension)) { - addSuggestionDiagnostic(createModuleImplicitlyAnyDiagnostic(errorNode, resolvedModule, moduleReference)); + errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference); } // merged symbol is module declaration symbol combined with all augmentations return getMergedSymbol(sourceFile.symbol); @@ -2150,7 +2172,7 @@ namespace ts { error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName); } else { - addErrorOrSuggestionDiagnostic(noImplicitAny && !!moduleNotFoundError, createModuleImplicitlyAnyDiagnostic(errorNode, resolvedModule, moduleReference)); + errorOnImplicitAnyModule(/*isError*/ noImplicitAny && !!moduleNotFoundError, errorNode, resolvedModule, moduleReference); } // Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first. return undefined; @@ -2175,12 +2197,12 @@ namespace ts { return undefined; } - function createModuleImplicitlyAnyDiagnostic(errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): Diagnostic { + function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { const errorInfo = packageId && chainDiagnosticMessages( /*details*/ undefined, Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0, getMangledNameForScopedPackage(packageId.name)); - return createDiagnosticForNodeFromMessageChain(errorNode, chainDiagnosticMessages( + errorOrSuggestion(isError, errorNode, chainDiagnosticMessages( errorInfo, Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type, moduleReference, @@ -10521,8 +10543,7 @@ namespace ts { // related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice // that S and T are contra-variant whereas X and Y are co-variant. function mappedTypeRelatedTo(source: MappedType, target: MappedType, reportErrors: boolean): Ternary { - const modifiersRelated = relation === comparableRelation || ( - relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : + const modifiersRelated = relation === comparableRelation || (relation === identityRelation ? getMappedTypeModifiers(source) === getMappedTypeModifiers(target) : getCombinedMappedTypeOptionality(source) <= getCombinedMappedTypeOptionality(target)); if (modifiersRelated) { let result: Ternary; @@ -16725,7 +16746,7 @@ namespace ts { } function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) { - if (!prop || !noUnusedIdentifiers || !(prop.flags & SymbolFlags.ClassMember) || !prop.valueDeclaration || !hasModifier(prop.valueDeclaration, ModifierFlags.Private)) { + if (!prop || !(prop.flags & SymbolFlags.ClassMember) || !prop.valueDeclaration || !hasModifier(prop.valueDeclaration, ModifierFlags.Private)) { return; } if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor))) { @@ -19088,7 +19109,6 @@ namespace ts { } } } - registerForUnusedIdentifiersCheck(node); } } @@ -20438,8 +20458,8 @@ namespace ts { checkAsyncFunctionReturnType(node); } } - if (noUnusedIdentifiers && !(node).body) { - checkUnusedTypeParameters(node); + if (node.kind !== SyntaxKind.IndexSignature && node.kind !== SyntaxKind.JSDocFunctionType) { + registerForUnusedIdentifiersCheck(node); } } } @@ -20640,7 +20660,6 @@ namespace ts { if (!checkGrammarConstructorTypeParameters(node)) checkGrammarConstructorTypeAnnotation(node); checkSourceElement(node.body); - registerForUnusedIdentifiersCheck(node); const symbol = getSymbolOfNode(node); const firstDeclaration = getDeclarationOfKind(symbol, node.kind); @@ -20760,7 +20779,6 @@ namespace ts { } } checkSourceElement(node.body); - registerForUnusedIdentifiersCheck(node); } function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) { @@ -21911,70 +21929,72 @@ namespace ts { getReturnTypeOfSignature(getSignatureFromDeclaration(node)); } } - - registerForUnusedIdentifiersCheck(node); } - function registerForUnusedIdentifiersCheck(node: Node) { - if (deferredUnusedIdentifierNodes) { + function registerForUnusedIdentifiersCheck(node: PotentiallyUnusedIdentifier): void { + // May be in a call such as getTypeOfNode that happened to call this. But potentiallyUnusedIdentifiers is only defined in the scope of `checkSourceFile`. + if (potentiallyUnusedIdentifiers) { // TODO: GH#22580 - // Debug.assert(addToSeen(seenDeferredUnusedIdentifiers, getNodeId(node)), "Deferring unused identifier check twice"); - deferredUnusedIdentifierNodes.push(node); + // Debug.assert(addToSeen(seenPotentiallyUnusedIdentifiers, getNodeId(node)), "Adding potentially-unused identifier twice"); + potentiallyUnusedIdentifiers.push(node); } } - function checkUnusedIdentifiers() { - if (deferredUnusedIdentifierNodes) { - for (const node of deferredUnusedIdentifierNodes) { - switch (node.kind) { - case SyntaxKind.SourceFile: - case SyntaxKind.ModuleDeclaration: - checkUnusedModuleMembers(node); - break; - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - checkUnusedClassMembers(node); - checkUnusedTypeParameters(node); - break; - case SyntaxKind.InterfaceDeclaration: - checkUnusedTypeParameters(node); - break; - case SyntaxKind.Block: - case SyntaxKind.CaseBlock: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - checkUnusedLocalsAndParameters(node); - break; - case SyntaxKind.Constructor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ArrowFunction: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - if ((node).body) { - checkUnusedLocalsAndParameters(node); - } - checkUnusedTypeParameters(node); - break; - case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructorType: - case SyntaxKind.TypeAliasDeclaration: - checkUnusedTypeParameters(node); - break; - default: - Debug.fail("Node should not have been registered for unused identifiers check"); - } + type PotentiallyUnusedIdentifier = + | SourceFile | ModuleDeclaration | ClassLikeDeclaration | InterfaceDeclaration + | Block | CaseBlock | ForStatement | ForInStatement | ForOfStatement + | Exclude | TypeAliasDeclaration; + + function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: ReadonlyArray, addDiagnostic: AddUnusedDiagnostic) { + for (const node of potentiallyUnusedIdentifiers) { + switch (node.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: + checkUnusedModuleMembers(node, addDiagnostic); + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + checkUnusedClassMembers(node, addDiagnostic); + checkUnusedTypeParameters(node, addDiagnostic); + break; + case SyntaxKind.InterfaceDeclaration: + checkUnusedTypeParameters(node, addDiagnostic); + break; + case SyntaxKind.Block: + case SyntaxKind.CaseBlock: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + checkUnusedLocalsAndParameters(node, addDiagnostic); + break; + case SyntaxKind.Constructor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + if (node.body) { + checkUnusedLocalsAndParameters(node, addDiagnostic); + } + checkUnusedTypeParameters(node, addDiagnostic); + break; + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + case SyntaxKind.TypeAliasDeclaration: + checkUnusedTypeParameters(node, addDiagnostic); + break; + default: + Debug.assertNever(node, "Node should not have been registered for unused identifiers check"); } } } - function checkUnusedLocalsAndParameters(node: Node): void { - if (noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) { + function checkUnusedLocalsAndParameters(node: Node, addDiagnostic: AddUnusedDiagnostic): void { + if (!(node.flags & NodeFlags.Ambient)) { node.locals.forEach(local => { // If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`. // If it's a type parameter merged with a parameter, check if the parameter-side is used. @@ -21982,15 +22002,12 @@ namespace ts { if (local.valueDeclaration && getRootDeclaration(local.valueDeclaration).kind === SyntaxKind.Parameter) { const parameter = getRootDeclaration(local.valueDeclaration); const name = getNameOfDeclaration(local.valueDeclaration); - if (compilerOptions.noUnusedParameters && - !isParameterPropertyDeclaration(parameter) && - !parameterIsThisKeyword(parameter) && - !parameterNameStartsWithUnderscore(name)) { - error(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local)); + if (!isParameterPropertyDeclaration(parameter) && !parameterIsThisKeyword(parameter) && !parameterNameStartsWithUnderscore(name)) { + addDiagnostic(UnusedKind.Parameter, createDiagnosticForNode(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local))); } } - else if (compilerOptions.noUnusedLocals) { - forEach(local.declarations, d => errorUnusedLocal(d, symbolName(local))); + else { + forEach(local.declarations, d => errorUnusedLocal(d, symbolName(local), addDiagnostic)); } } }); @@ -22005,7 +22022,7 @@ namespace ts { return false; } - function errorUnusedLocal(declaration: Declaration, name: string) { + function errorUnusedLocal(declaration: Declaration, name: string, addDiagnostic: AddUnusedDiagnostic) { const node = getNameOfDeclaration(declaration) || declaration; if (isIdentifierThatStartsWithUnderScore(node)) { const declaration = getRootDeclaration(node.parent); @@ -22016,7 +22033,7 @@ namespace ts { } if (!isRemovedPropertyFromObjectSpread(node.kind === SyntaxKind.Identifier ? node.parent : node)) { - diagnostics.add(createDiagnosticForNodeSpan(getSourceFileOfNode(declaration), declaration, node, Diagnostics._0_is_declared_but_its_value_is_never_read, name)); + addDiagnostic(UnusedKind.Local, createDiagnosticForNodeSpan(getSourceFileOfNode(declaration), declaration, node, Diagnostics._0_is_declared_but_its_value_is_never_read, name)); } } @@ -22028,8 +22045,8 @@ namespace ts { return isIdentifier(node) && idText(node).charCodeAt(0) === CharacterCodes._; } - function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression): void { - if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { + function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression, addDiagnostic: AddUnusedDiagnostic): void { + if (!(node.flags & NodeFlags.Ambient)) { for (const member of node.members) { switch (member.kind) { case SyntaxKind.MethodDeclaration: @@ -22042,13 +22059,13 @@ namespace ts { } const symbol = getSymbolOfNode(member); if (!symbol.isReferenced && hasModifier(member, ModifierFlags.Private)) { - error(member.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolToString(symbol)); + addDiagnostic(UnusedKind.Local, createDiagnosticForNode(member.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolToString(symbol))); } break; case SyntaxKind.Constructor: for (const parameter of (member).parameters) { if (!parameter.symbol.isReferenced && hasModifier(parameter, ModifierFlags.Private)) { - error(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol)); + addDiagnostic(UnusedKind.Local, createDiagnosticForNode(parameter.name, Diagnostics.Property_0_is_declared_but_its_value_is_never_read, symbolName(parameter.symbol))); } } break; @@ -22063,27 +22080,23 @@ namespace ts { } } - function checkUnusedTypeParameters(node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration) { - if (compilerOptions.noUnusedParameters && !(node.flags & NodeFlags.Ambient)) { - if (node.typeParameters) { - // Only report errors on the last declaration for the type parameter container; - // this ensures that all uses have been accounted for. - const symbol = getSymbolOfNode(node); - const lastDeclaration = symbol && symbol.declarations && lastOrUndefined(symbol.declarations); - if (lastDeclaration !== node) { - return; - } - for (const typeParameter of node.typeParameters) { - if (!(getMergedSymbol(typeParameter.symbol).isReferenced & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) { - error(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol)); - } + function checkUnusedTypeParameters( + node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration, + addDiagnostic: AddUnusedDiagnostic, + ): void { + // Only report errors on the last declaration for the type parameter container; + // this ensures that all uses have been accounted for. + if (!(node.flags & NodeFlags.Ambient) && node.typeParameters && last(getSymbolOfNode(node)!.declarations) === node) { + for (const typeParameter of node.typeParameters) { + if (!(getMergedSymbol(typeParameter.symbol).isReferenced & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) { + addDiagnostic(UnusedKind.Parameter, createDiagnosticForNode(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol))); } } } } - function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void { - if (compilerOptions.noUnusedLocals && !(node.flags & NodeFlags.Ambient)) { + function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile, addDiagnostic: AddUnusedDiagnostic): void { + if (!(node.flags & NodeFlags.Ambient)) { // Ideally we could use the ImportClause directly as a key, but must wait until we have full ES6 maps. So must store key along with value. const unusedImports = createMap<[ImportClause, ImportedDeclaration[]]>(); node.locals.forEach(local => { @@ -22102,7 +22115,7 @@ namespace ts { } } else { - errorUnusedLocal(declaration, symbolName(local)); + errorUnusedLocal(declaration, symbolName(local), addDiagnostic); } } }); @@ -22110,13 +22123,13 @@ namespace ts { unusedImports.forEach(([importClause, unuseds]) => { const importDecl = importClause.parent; if (forEachImportedDeclaration(importClause, d => !contains(unuseds, d))) { - for (const unused of unuseds) errorUnusedLocal(unused, idText(unused.name)); + for (const unused of unuseds) errorUnusedLocal(unused, idText(unused.name), addDiagnostic); } else if (unuseds.length === 1) { - error(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name)); + addDiagnostic(UnusedKind.Local, createDiagnosticForNode(importDecl, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(first(unuseds).name))); } else { - error(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused, showModuleSpecifier(importDecl)); + addDiagnostic(UnusedKind.Local, createDiagnosticForNode(importDecl, Diagnostics.All_imports_in_import_declaration_are_unused, showModuleSpecifier(importDecl))); } }); } @@ -24874,6 +24887,17 @@ namespace ts { performance.measure("Check", "beforeCheck", "afterCheck"); } + function unusedIsError(kind: UnusedKind): boolean { + switch (kind) { + case UnusedKind.Local: + return compilerOptions.noUnusedLocals; + case UnusedKind.Parameter: + return compilerOptions.noUnusedParameters; + default: + return Debug.assertNever(kind); + } + } + // Fully type check a source file and collect the relevant diagnostics. function checkSourceFileWorker(node: SourceFile) { const links = getNodeLinks(node); @@ -24892,8 +24916,10 @@ namespace ts { clear(potentialNewTargetCollisions); deferredNodes = []; - deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined; - flowAnalysisDisabled = false; + if (produceDiagnostics) { + Debug.assert(!allPotentiallyUnusedIdentifiers.has(node.fileName)); + allPotentiallyUnusedIdentifiers.set(node.fileName, potentiallyUnusedIdentifiers = []); + } forEach(node.statements, checkSourceElement); @@ -24903,13 +24929,17 @@ namespace ts { registerForUnusedIdentifiersCheck(node); } - if (!node.isDeclarationFile) { - checkUnusedIdentifiers(); + if (!node.isDeclarationFile && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters)) { + checkUnusedIdentifiers(potentiallyUnusedIdentifiers, (kind, diag) => { + if (unusedIsError(kind)) { + diagnostics.add(diag); + } + }); } deferredNodes = undefined; - seenDeferredUnusedIdentifiers.clear(); - deferredUnusedIdentifierNodes = undefined; + seenPotentiallyUnusedIdentifiers.clear(); + potentiallyUnusedIdentifiers = undefined; if (isExternalOrCommonJsModule(node)) { checkExternalModuleExports(node); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index ae7e8de2ae12c..a75cc8cba0e89 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1606,6 +1606,7 @@ namespace ts { messageText: text, category: message.category, code: message.code, + reportsUnnecessary: message.unused, }; } @@ -1635,7 +1636,8 @@ namespace ts { messageText: text, category: message.category, - code: message.code + code: message.code, + reportsUnnecessary: message.unused, }; } @@ -1647,7 +1649,7 @@ namespace ts { code: chain.code, category: chain.category, - messageText: chain.next ? chain : chain.messageText + messageText: chain.next ? chain : chain.messageText, }; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ffb4fd958123e..e9bf71dd6eb49 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3282,7 +3282,8 @@ }, "'{0}' is declared but its value is never read.": { "category": "Error", - "code": 6133 + "code": 6133, + "unused": true }, "Report errors on unused locals.": { "category": "Message", @@ -3302,7 +3303,8 @@ }, "Property '{0}' is declared but its value is never read.": { "category": "Error", - "code": 6138 + "code": 6138, + "unused": true }, "Import emit helpers from 'tslib'.": { "category": "Message", @@ -3514,7 +3516,8 @@ }, "All imports in import declaration are unused.": { "category": "Error", - "code": 6192 + "code": 6192, + "unused": true }, "Found 1 error.": { "category": "Message", @@ -3602,7 +3605,8 @@ }, "Unused label.": { "category": "Error", - "code": 7028 + "code": 7028, + "unused": true }, "Fallthrough case in switch.": { "category": "Error", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a526ecc5dff98..f820201063c7e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4069,6 +4069,7 @@ namespace ts { category: DiagnosticCategory; code: number; message: string; + unused?: {}; } /** @@ -4090,6 +4091,8 @@ namespace ts { length: number | undefined; messageText: string | DiagnosticMessageChain; category: DiagnosticCategory; + /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ + reportsUnnecessary?: {}; code: number; source?: string; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 270b3d15d2d23..8c71a385d581b 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2577,7 +2577,7 @@ Actual: ${stringify(fullActual)}`); } const range = ts.first(ranges); - const codeFixes = this.getCodeFixes(fileName, errorCode, preferences); + const codeFixes = this.getCodeFixes(fileName, errorCode, preferences).filter(f => f.fixId === undefined); // TODO: GH#20315 filter out those that use the import fix ID; if (codeFixes.length === 0) { if (expectedTextArray.length !== 0) { diff --git a/src/harness/unittests/matchFiles.ts b/src/harness/unittests/matchFiles.ts index b2f41ba4fa2fa..458dddb22526e 100644 --- a/src/harness/unittests/matchFiles.ts +++ b/src/harness/unittests/matchFiles.ts @@ -123,13 +123,14 @@ namespace ts { } { const actual = parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack); - expected.errors = expected.errors.map(error => ({ + expected.errors = expected.errors.map((error): Diagnostic => ({ category: error.category, code: error.code, file: undefined, length: undefined, messageText: error.messageText, start: undefined, + reportsUnnecessary: undefined, })); assertParsed(actual, expected); } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index d4ef32dab8478..8170c663b1f9d 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -4068,7 +4068,7 @@ namespace ts.projectSystem { const folderPath = "/a/b/projects/temp"; const file1: FileOrFolder = { path: `${folderPath}/a.ts`, - content: 'import f = require("pad")' + content: 'import f = require("pad"); f;' }; const files = [file1, libFile]; const host = createServerHost(files); diff --git a/src/server/client.ts b/src/server/client.ts index 98fb130dbb3c7..87bb2e93414da 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -353,11 +353,11 @@ namespace ts.server { return this.getDiagnostics(file, CommandNames.SuggestionDiagnosticsSync); } - private getDiagnostics(file: string, command: CommandNames) { + private getDiagnostics(file: string, command: CommandNames): Diagnostic[] { const request = this.processRequest(command, { file, includeLinePosition: true }); const response = this.processResponse(request); - return (response.body).map(entry => { + return (response.body).map((entry): Diagnostic => { const category = firstDefined(Object.keys(DiagnosticCategory), id => isString(id) && entry.category === id.toLowerCase() ? (DiagnosticCategory)[id] : undefined); return { @@ -366,7 +366,8 @@ namespace ts.server { length: entry.length, messageText: entry.message, category: Debug.assertDefined(category, "convertDiagnostic: category should not be undefined"), - code: entry.code + code: entry.code, + reportsUnnecessary: entry.reportsUnnecessary, }; }); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 3f0ce3b6d4080..74b6865a3c315 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -455,6 +455,8 @@ namespace ts.server.protocol { endLocation: Location; category: string; code: number; + /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ + reportsUnnecessary?: {}; } /** diff --git a/src/services/shims.ts b/src/services/shims.ts index a96db02f1e679..4ed1afb8813a2 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -588,6 +588,7 @@ namespace ts { length: number; category: string; code: number; + unused?: {}; } export function realizeDiagnostics(diagnostics: ReadonlyArray, newLine: string): RealizedDiagnostic[] { return diagnostics.map(d => realizeDiagnostic(d, newLine)); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index f897b3bf84ea4..f44f46b9a369e 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2271,6 +2271,7 @@ declare namespace ts { category: DiagnosticCategory; code: number; message: string; + unused?: {}; } /** * A linked list of formatted diagnostic messages to be used as part of a multiline message. @@ -2290,6 +2291,8 @@ declare namespace ts { length: number | undefined; messageText: string | DiagnosticMessageChain; category: DiagnosticCategory; + /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ + reportsUnnecessary?: {}; code: number; source?: string; } @@ -5398,6 +5401,8 @@ declare namespace ts.server.protocol { endLocation: Location; category: string; code: number; + /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ + reportsUnnecessary?: {}; } /** * Response message for "projectInfo" request diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 1148b5ba9eab6..dbb4d6cc7bf46 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2271,6 +2271,7 @@ declare namespace ts { category: DiagnosticCategory; code: number; message: string; + unused?: {}; } /** * A linked list of formatted diagnostic messages to be used as part of a multiline message. @@ -2290,6 +2291,8 @@ declare namespace ts { length: number | undefined; messageText: string | DiagnosticMessageChain; category: DiagnosticCategory; + /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ + reportsUnnecessary?: {}; code: number; source?: string; } diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc12.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc12.ts index e7893fd99046a..2152355df8b9e 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc12.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc12.ts @@ -5,6 +5,7 @@ //// * @return {...*} //// */ //// m(x) { +//// return [x]; //// } ////} @@ -16,6 +17,7 @@ verify.codeFix({ * @return {...*} */ m(x): any[] { + return [x]; } }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc15.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc15.ts index 8072f0547de67..9d26eaa8cdeb0 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc15.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc15.ts @@ -12,6 +12,7 @@ //// * @param {promise} zeta //// */ ////function f(x, y, z, alpha, beta, gamma, delta, epsilon, zeta) { +//// x; y; z; alpha; beta; gamma; delta; epsilon; zeta; ////} verify.codeFix({ @@ -29,5 +30,6 @@ verify.codeFix({ * @param {promise} zeta */ function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma: Promise, delta: Array, epsilon: Array, zeta: Promise) { + x; y; z; alpha; beta; gamma; delta; epsilon; zeta; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts index 49d7133d9c460..6eb079f969291 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts @@ -1,12 +1,12 @@ /// // @strict: true /////** @type {function(*, ...number, ...boolean): void} */ -////var x = (x, ys, ...zs) => { }; +////var x = (x, ys, ...zs) => { x; ys; zs; }; verify.codeFix({ description: "Annotate with type from JSDoc", index: 0, newFileContent: `/** @type {function(*, ...number, ...boolean): void} */ -var x: (arg0: any, arg1: number[], ...rest: boolean[]) => void = (x, ys, ...zs) => { };`, +var x: (arg0: any, arg1: number[], ...rest: boolean[]) => void = (x, ys, ...zs) => { x; ys; zs; };`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc17.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc17.ts index 2382cc18a272f..a4453da882551 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc17.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc17.ts @@ -3,7 +3,7 @@ //// /** //// * @param {number} x - the first parameter //// */ -//// constructor(x) { +//// constructor(readonly x) { //// } ////} @@ -14,7 +14,7 @@ verify.codeFix({ /** * @param {number} x - the first parameter */ - constructor(x: number) { + constructor(readonly x: number) { } }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc18.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc18.ts index b1faa22b1f60d..685287f209283 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc18.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc18.ts @@ -1,7 +1,7 @@ /// ////class C { //// /** @param {number} value */ -//// set c(value) { return 12 } +//// set c(value) { return value } ////} verify.codeFix({ @@ -9,6 +9,6 @@ verify.codeFix({ newFileContent: `class C { /** @param {number} value */ - set c(value: number) { return 12 } + set c(value: number) { return value } }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc19.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc19.ts index 96e351ed2baa6..754d29d0e46c9 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc19.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc19.ts @@ -6,6 +6,7 @@ //// * @param {T} b //// */ ////function f(a, b) { +//// return a || b; ////} verify.codeFix({ @@ -17,5 +18,6 @@ verify.codeFix({ * @param {T} b */ function f(a: number, b: T) { + return a || b; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc20.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc20.ts index a54936b1ea610..0505c1511b2ee 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc20.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc20.ts @@ -4,11 +4,12 @@ //// * @param {number} a //// * @param {T} b //// */ -////function /*1*/f(a, b) { +////function f(a, b) { ////} verify.codeFix({ description: "Annotate with type from JSDoc", + errorCode: 80004, // ignore 'unused T' newFileContent: `/** * @param {number} a diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc21.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc21.ts index 67d7e09994994..9f91e69065876 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc21.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc21.ts @@ -4,19 +4,20 @@ //// * @return {number} //// */ ////function [|f|](x, y) { +//// return x + y; ////} //// /////** //// * @return {number} //// */ ////function g(x, y): number { -//// return 0; +//// return x + y; ////} /////** //// * @param {number} x //// */ ////function h(x: number, y): number { -//// return 0; +//// return x + y; ////} //// /////** @@ -24,13 +25,14 @@ //// * @param {string} y //// */ ////function i(x: number, y: string) { +//// return x + y; ////} /////** //// * @param {number} x //// * @return {boolean} //// */ ////function j(x: number, y): boolean { -//// return true; +//// return x < y; ////} // Only first location triggers a suggestion @@ -41,24 +43,26 @@ verify.getSuggestionDiagnostics([{ verify.codeFix({ description: "Annotate with type from JSDoc", - newFileContent: + errorCode: 80004, + newFileContent: `/** * @return {number} */ function f(x, y): number { + return x + y; } /** * @return {number} */ function g(x, y): number { - return 0; + return x + y; } /** * @param {number} x */ function h(x: number, y): number { - return 0; + return x + y; } /** @@ -66,12 +70,13 @@ function h(x: number, y): number { * @param {string} y */ function i(x: number, y: string) { + return x + y; } /** * @param {number} x * @return {boolean} */ function j(x: number, y): boolean { - return true; + return x < y; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc22.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc22.ts index 9da43e5099a6f..9163805bfcfdd 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc22.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc22.ts @@ -4,6 +4,7 @@ /////** @param {Object} sb //// * @param {Object} ns */ ////function f(sb, ns) { +//// sb; ns; ////} verify.codeFix({ @@ -13,5 +14,6 @@ verify.codeFix({ /** @param {Object} sb * @param {Object} ns */ function f(sb: { [s: string]: boolean; }, ns: { [n: number]: string; }) { + sb; ns; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc3.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc3.ts index 0eedc937198b4..c5013b80cf17b 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc3.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc3.ts @@ -7,6 +7,7 @@ //// * @param {*} beta - I have no idea how this got here //// */ ////function [|f|](x, y, z: string, alpha, beta) { +//// x; y; z; alpha; beta; ////} verify.getSuggestionDiagnostics([{ @@ -17,6 +18,7 @@ verify.getSuggestionDiagnostics([{ verify.codeFix({ description: "Annotate with type from JSDoc", newFileContent: +// TODO: GH#22358 `/** * @param {number} x - the first parameter * @param {{ a: string, b: Date }} y - the most complex parameter @@ -25,5 +27,6 @@ verify.codeFix({ * @param {*} beta - I have no idea how this got here */ function f(x: number, y: { a: string; b: Date; }, z: string, alpha, beta: any) { + x; y; z; alpha; beta; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc4.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc4.ts index 31825eea3f97f..c6010bf6cd002 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc4.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc4.ts @@ -10,6 +10,7 @@ //// * @param {number!} delta //// */ ////function [|f|](x, y, z, alpha, beta, gamma, delta) { +//// x; y; z; alpha; beta; gamma; delta; ////} verify.codeFix({ @@ -25,5 +26,6 @@ verify.codeFix({ * @param {number!} delta */ function f(x: any, y: any, z: number | undefined, alpha: number[], beta: (this: { a: string; }, arg1: string, arg2: number) => boolean, gamma: number | null, delta: number) { + x; y; z; alpha; beta; gamma; delta; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc7.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc7.ts index e242b53228d4b..ba3bd7d47a0b4 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc7.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc7.ts @@ -5,6 +5,7 @@ //// * @returns {number} //// */ ////function f(x) { +//// return x; ////} verify.codeFix({ @@ -15,5 +16,6 @@ verify.codeFix({ * @returns {number} */ function f(x: number): number { + return x; }`, }); diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc8.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc8.ts index 8e02259fd21a1..40ddf4fad0e8a 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc8.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc8.ts @@ -5,6 +5,7 @@ //// * @returns {number} //// */ ////var f = function (x) { +//// return x ////} verify.codeFix({ @@ -15,5 +16,6 @@ verify.codeFix({ * @returns {number} */ var f = function (x: number): number { + return x }`, }); diff --git a/tests/cases/fourslash/codeFixCannotFindModule.ts b/tests/cases/fourslash/codeFixCannotFindModule.ts index 10d4270892e87..d30e43819b307 100644 --- a/tests/cases/fourslash/codeFixCannotFindModule.ts +++ b/tests/cases/fourslash/codeFixCannotFindModule.ts @@ -7,13 +7,14 @@ ////not read // @Filename: /a.ts -/////**/import * as abs from "abs"; +////import * as abs from "abs"; +////abs; test.setTypesRegistry({ "abs": undefined, }); -goTo.marker(); +goTo.file("/a.ts"); verify.codeFixAvailable([{ description: "Install '@types/abs'", diff --git a/tests/cases/fourslash/codeFixCannotFindModule_notIfMissing.ts b/tests/cases/fourslash/codeFixCannotFindModule_notIfMissing.ts index f446c643542fb..f004ebac90298 100644 --- a/tests/cases/fourslash/codeFixCannotFindModule_notIfMissing.ts +++ b/tests/cases/fourslash/codeFixCannotFindModule_notIfMissing.ts @@ -1,7 +1,7 @@ /// // @Filename: /a.ts -////import * as abs from "abs"; +////import {} from "abs"; test.setTypesRegistry({ "abs": undefined, diff --git a/tests/cases/fourslash/codeFixCannotFindModule_suggestion.ts b/tests/cases/fourslash/codeFixCannotFindModule_suggestion.ts index 778ac040c1897..c35737514934a 100644 --- a/tests/cases/fourslash/codeFixCannotFindModule_suggestion.ts +++ b/tests/cases/fourslash/codeFixCannotFindModule_suggestion.ts @@ -7,6 +7,7 @@ // @Filename: /a.ts ////import * as abs from [|"abs/subModule"|]; +////abs; test.setTypesRegistry({ "abs": undefined, diff --git a/tests/cases/fourslash/codeFixCannotFindModule_suggestion_js.ts b/tests/cases/fourslash/codeFixCannotFindModule_suggestion_js.ts index a8ca9156cf158..8349be98fc35c 100644 --- a/tests/cases/fourslash/codeFixCannotFindModule_suggestion_js.ts +++ b/tests/cases/fourslash/codeFixCannotFindModule_suggestion_js.ts @@ -8,6 +8,7 @@ // @Filename: /a.js ////import abs from [|"abs"|]; +////abs; test.setTypesRegistry({ "abs": undefined }); diff --git a/tests/cases/fourslash/codeFixChangeExtendsToImplementsTypeParams.ts b/tests/cases/fourslash/codeFixChangeExtendsToImplementsTypeParams.ts index d71b7b560d90d..b5bf6cc3ffdf3 100644 --- a/tests/cases/fourslash/codeFixChangeExtendsToImplementsTypeParams.ts +++ b/tests/cases/fourslash/codeFixChangeExtendsToImplementsTypeParams.ts @@ -1,9 +1,9 @@ /// -////interface I { x: X} -////[|class C extends I|]{} +////interface I { x: X; y: Y; } +////[|class C extends I|]{} verify.codeFix({ description: "Change 'extends' to 'implements'", - newRangeContent: "class C implements I", + newRangeContent: "class C implements I", }); diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts index ca8bd92d12e59..d5ab73b16a041 100644 --- a/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax21.ts @@ -1,5 +1,5 @@ /// -//// var index = { set p(x: [|*|]) { } }; +//// var index = { set p(x: [|*|]) { x; } }; verify.codeFix({ description: "Change '*' to 'any'", diff --git a/tests/cases/fourslash/codeFixClassExprExtendsAbstractExpressionWithTypeArgs.ts b/tests/cases/fourslash/codeFixClassExprExtendsAbstractExpressionWithTypeArgs.ts index ef85b2c6cdfc4..24a97c70e6577 100644 --- a/tests/cases/fourslash/codeFixClassExprExtendsAbstractExpressionWithTypeArgs.ts +++ b/tests/cases/fourslash/codeFixClassExprExtendsAbstractExpressionWithTypeArgs.ts @@ -1,6 +1,7 @@ /// ////function foo(a: T) { +//// a; //// abstract class C { //// abstract a: T | U; //// } @@ -14,6 +15,7 @@ verify.codeFix({ // TODO: GH#18795 newFileContent: `function foo(a: T) { + a; abstract class C { abstract a: T | U; } diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractExpressionWithTypeArgs.ts b/tests/cases/fourslash/codeFixClassExtendAbstractExpressionWithTypeArgs.ts index e21b7a21e2608..f78cf2a3d6f25 100644 --- a/tests/cases/fourslash/codeFixClassExtendAbstractExpressionWithTypeArgs.ts +++ b/tests/cases/fourslash/codeFixClassExtendAbstractExpressionWithTypeArgs.ts @@ -1,6 +1,7 @@ /// ////function foo(a: T) { +//// a; //// abstract class C { //// abstract a: T | U; //// } @@ -14,6 +15,7 @@ verify.codeFix({ // TODO: GH#18795 newFileContent: `function foo(a: T) { + a; abstract class C { abstract a: T | U; } diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractGetterSetter.ts b/tests/cases/fourslash/codeFixClassExtendAbstractGetterSetter.ts index 8dd0e508ce972..75ccc9565218c 100644 --- a/tests/cases/fourslash/codeFixClassExtendAbstractGetterSetter.ts +++ b/tests/cases/fourslash/codeFixClassExtendAbstractGetterSetter.ts @@ -1,8 +1,6 @@ /// ////abstract class A { -//// private _a: string; -//// //// abstract get a(): number | string; //// abstract get b(): this; //// abstract get c(): A; @@ -25,8 +23,6 @@ verify.codeFix({ // TODO: GH#18795 newFileContent: `abstract class A { - private _a: string; - abstract get a(): number | string; abstract get b(): this; abstract get c(): A; diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractPrivateProperty.ts b/tests/cases/fourslash/codeFixClassExtendAbstractPrivateProperty.ts index b8f6b3d81eb69..b4bd301a41553 100644 --- a/tests/cases/fourslash/codeFixClassExtendAbstractPrivateProperty.ts +++ b/tests/cases/fourslash/codeFixClassExtendAbstractPrivateProperty.ts @@ -2,6 +2,7 @@ //// abstract class A { //// private abstract x: number; +//// m() { this.x; } // Avoid unused private //// } //// //// class C extends A {[| |]} diff --git a/tests/cases/fourslash/codeFixClassImplementClassAbstractGettersAndSetters.ts b/tests/cases/fourslash/codeFixClassImplementClassAbstractGettersAndSetters.ts index adea74627b8d5..71e0aba73b334 100644 --- a/tests/cases/fourslash/codeFixClassImplementClassAbstractGettersAndSetters.ts +++ b/tests/cases/fourslash/codeFixClassImplementClassAbstractGettersAndSetters.ts @@ -1,8 +1,6 @@ /// ////abstract class A { -//// private _a: string; -//// //// abstract get a(): string; //// abstract set a(newName: string); //// @@ -17,8 +15,6 @@ verify.codeFix({ description: "Implement interface 'A'", newFileContent: `abstract class A { - private _a: string; - abstract get a(): string; abstract set a(newName: string); diff --git a/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures1.ts b/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures1.ts index a0b59c6372ca0..1168b9d4c3e59 100644 --- a/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures1.ts +++ b/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures1.ts @@ -2,7 +2,7 @@ ////class A { //// method(a: number, b: string): boolean; -//// method(a: string | number, b?: string | number): boolean | Function { return true; } +//// method(a: string | number, b?: string | number): boolean | Function { return a + b as any; } ////} ////class C implements A {} @@ -11,7 +11,7 @@ verify.codeFix({ newFileContent: `class A { method(a: number, b: string): boolean; - method(a: string | number, b?: string | number): boolean | Function { return true; } + method(a: string | number, b?: string | number): boolean | Function { return a + b as any; } } class C implements A { method(a: number, b: string): boolean; diff --git a/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures2.ts b/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures2.ts index dcd5636428dbc..4b5be82f87070 100644 --- a/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures2.ts +++ b/tests/cases/fourslash/codeFixClassImplementClassMultipleSignatures2.ts @@ -4,7 +4,7 @@ //// method(a: any, b: string): boolean; //// method(a: string, b: number): Function; //// method(a: string): Function; -//// method(a: string | number, b?: string | number): boolean | Function { return true; } +//// method(a: string | number, b?: string | number): boolean | Function { return a + b as any; } ////} ////class C implements A {[| |]} @@ -15,7 +15,7 @@ verify.codeFix({ method(a: any, b: string): boolean; method(a: string, b: number): Function; method(a: string): Function; - method(a: string | number, b?: string | number): boolean | Function { return true; } + method(a: string | number, b?: string | number): boolean | Function { return a + b as any; } } class C implements A { method(a: any, b: string): boolean; diff --git a/tests/cases/fourslash/codeFixClassImplementClassPropertyModifiers.ts b/tests/cases/fourslash/codeFixClassImplementClassPropertyModifiers.ts index 7e7a712b60e2f..9614213798fb8 100644 --- a/tests/cases/fourslash/codeFixClassImplementClassPropertyModifiers.ts +++ b/tests/cases/fourslash/codeFixClassImplementClassPropertyModifiers.ts @@ -5,6 +5,7 @@ //// private y: number; //// protected z: number; //// public w: number; +//// public useY() { this.y; } ////} //// ////class C implements A {[| |]} @@ -17,11 +18,15 @@ verify.codeFix({ private y: number; protected z: number; public w: number; + public useY() { this.y; } } class C implements A { x: number; protected z: number; public w: number; + public useY(): void { + throw new Error("Method not implemented."); + } }`, }); diff --git a/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts b/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts index 516919b13df0d..c55a4e35961cc 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterfaceInheritsAbstractMethod.ts @@ -2,7 +2,7 @@ ////abstract class C1 { } ////abstract class C2 { -//// abstract fA(); +//// abstract fA(): T; ////} ////interface I1 extends C1, C2 { } ////class C3 implements I1 {[| |]} @@ -12,11 +12,11 @@ verify.codeFix({ newFileContent: `abstract class C1 { } abstract class C2 { - abstract fA(); + abstract fA(): T; } interface I1 extends C1, C2 { } class C3 implements I1 { - fA() { + fA(): T { throw new Error("Method not implemented."); } }`, diff --git a/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess.ts b/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess.ts index 5d1772ba8b800..4e6e303c2ae56 100644 --- a/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess.ts +++ b/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess.ts @@ -8,6 +8,7 @@ //// this.a = 12; //// super(); //// |]} +//// m() { this.a; } // avoid unused 'a' ////} verify.rangeAfterCodeFix(` super(); diff --git a/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_callWithThisInside.ts b/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_callWithThisInside.ts index 9b443b7df62f6..6660027ae0081 100644 --- a/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_callWithThisInside.ts +++ b/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_callWithThisInside.ts @@ -1,7 +1,7 @@ /// ////class Base{ -//// constructor(id: number) { } +//// constructor(id: number) { id; } ////} ////class C extends Base{ //// constructor(private a:number) { diff --git a/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType01.ts b/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType01.ts index ffcc9ffeacc61..0d5655482f56f 100644 --- a/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType01.ts +++ b/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType01.ts @@ -3,6 +3,6 @@ //// export interface Foo { //// bar: string; //// } -//// const x: [|Foo.bar|] = "" +//// export const x: [|Foo.bar|] = "" verify.rangeAfterCodeFix(`Foo["bar"]`); diff --git a/tests/cases/fourslash/codeFixInferFromUsageInaccessibleTypes.ts b/tests/cases/fourslash/codeFixInferFromUsageInaccessibleTypes.ts index e522d8fa62e39..91dfcffafc0d8 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageInaccessibleTypes.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageInaccessibleTypes.ts @@ -1,13 +1,13 @@ /// // @noImplicitAny: true -////function f1(a) { } +////function f1(a) { a; } ////function h1() { //// class C { p: number }; //// f1({ ofTypeC: new C() }); ////} //// -////function f2(a) { } +////function f2(a) { a; } ////function h2() { //// interface I { a: number } //// var i: I = {a : 1}; diff --git a/tests/cases/fourslash/codeFixInferFromUsageOptionalParam.ts b/tests/cases/fourslash/codeFixInferFromUsageOptionalParam.ts index f10de4bb03ae8..f9b7277e4cc73 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageOptionalParam.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageOptionalParam.ts @@ -2,6 +2,7 @@ // @noImplicitAny: true ////function f([|a? |]){ +//// a; ////} ////f(); ////f(1); diff --git a/tests/cases/fourslash/codeFixInferFromUsageRestParam.ts b/tests/cases/fourslash/codeFixInferFromUsageRestParam.ts index 963f84d651530..b4713181d9ad9 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageRestParam.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageRestParam.ts @@ -2,6 +2,7 @@ // @noImplicitAny: true ////function f(a: number, [|...rest |]){ +//// a; rest; ////} ////f(1); ////f(2, "s1"); diff --git a/tests/cases/fourslash/codeFixInferFromUsageRestParam2.ts b/tests/cases/fourslash/codeFixInferFromUsageRestParam2.ts index ae8262402281e..1e0c5f7a1956e 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageRestParam2.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageRestParam2.ts @@ -2,6 +2,7 @@ // @noImplicitAny: true ////function f(a: number, [|...rest |]){ +//// a; rest; ////} ////f(1); ////f(2, "s1"); diff --git a/tests/cases/fourslash/codeFixInferFromUsageRestParam3.ts b/tests/cases/fourslash/codeFixInferFromUsageRestParam3.ts index 4752176a324a2..8c98930bff1f3 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageRestParam3.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageRestParam3.ts @@ -2,6 +2,7 @@ // @noImplicitAny: true ////function f(a: number, [|...rest |]){ +//// a; //// rest.push(22); ////} diff --git a/tests/cases/fourslash/codeFixInferFromUsageSetter.ts b/tests/cases/fourslash/codeFixInferFromUsageSetter.ts index f515cd5a90687..596a535d01ee4 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageSetter.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageSetter.ts @@ -3,6 +3,7 @@ // @noImplicitAny: true ////class C { //// set [|x(v)|] { +//// v; //// } ////} ////(new C).x = 1; diff --git a/tests/cases/fourslash/codeFixInferFromUsageSetter2.ts b/tests/cases/fourslash/codeFixInferFromUsageSetter2.ts index a1169a03df16b..d058bc2787c7d 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageSetter2.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageSetter2.ts @@ -3,6 +3,7 @@ // @noImplicitAny: true ////class C { //// set [|x(v)|] { +//// v; //// } ////} ////(new C).x = 1; diff --git a/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts b/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts index 96c76a64837ab..7a0c079799b0a 100644 --- a/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts +++ b/tests/cases/fourslash/codeFixInferFromUsageSetterWithInaccessibleType.ts @@ -8,7 +8,7 @@ // @Filename: /b.ts ////export class C { -//// [|set x(val) {}|] +//// [|set x(val) { val; }|] //// method() { this.x = import("./a"); } ////} diff --git a/tests/cases/fourslash/codeFixSpelling5.ts b/tests/cases/fourslash/codeFixSpelling5.ts index 2ab34a44499f1..214af09fae68c 100644 --- a/tests/cases/fourslash/codeFixSpelling5.ts +++ b/tests/cases/fourslash/codeFixSpelling5.ts @@ -4,7 +4,7 @@ ////export const fooooooooo = 1; // @Filename: f2.ts -////import {[|fooooooooa|]} from "./f1"; +////import {[|fooooooooa|]} from "./f1"; fooooooooa; goTo.file("f2.ts") verify.rangeAfterCodeFix(`fooooooooo`); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixUnusedIdentifier_suggestion.ts b/tests/cases/fourslash/codeFixUnusedIdentifier_suggestion.ts new file mode 100644 index 0000000000000..de671de1e5db8 --- /dev/null +++ b/tests/cases/fourslash/codeFixUnusedIdentifier_suggestion.ts @@ -0,0 +1,25 @@ +/// + +////function f([|p|]) { +//// const [|x|] = 0; +////} + +const [r0, r1] = test.ranges(); +verify.getSuggestionDiagnostics([ + { + message: "'p' is declared but its value is never read.", + range: r0, + code: 6133, + unused: true, + }, + { + message: "'x' is declared but its value is never read.", + range: r1, + code: 6133, + unused: true, + } +]); + +verify.codeFixAvailable( + ["Remove declaration for: 'p'", "Prefix 'p' with an underscore", "Remove declaration for: 'x'"] + .map(description => ({ description }))); diff --git a/tests/cases/fourslash/codeFixUseDefaultImport.ts b/tests/cases/fourslash/codeFixUseDefaultImport.ts index 103c1e084650d..c86ea2ce93f9b 100644 --- a/tests/cases/fourslash/codeFixUseDefaultImport.ts +++ b/tests/cases/fourslash/codeFixUseDefaultImport.ts @@ -8,15 +8,18 @@ // @Filename: /b.ts /////*com ment*/import * as [|a|] from "./a";/*tnem moc*/ +////a; // @Filename: /c.ts /////*com ment*/import [|a|] = require("./a");/*tnem moc*/ +////a; // @Filename: /d.ts ////import "./a"; // @Filename: /e.ts ////import * as n from "./non-existant"; +////n; for (const file of ["/b.ts", "/c.ts"]) { goTo.file(file); @@ -29,7 +32,9 @@ for (const file of ["/b.ts", "/c.ts"]) { verify.codeFix({ description: "Convert to default import", - newFileContent: `/*com ment*/import a from "./a";/*tnem moc*/`, + newFileContent: +`/*com ment*/import a from "./a";/*tnem moc*/ +a;`, }); } diff --git a/tests/cases/fourslash/convertFunctionToEs6ClassJsDoc.ts b/tests/cases/fourslash/convertFunctionToEs6ClassJsDoc.ts index ef2249d2d43c7..5a2c6c6bc4912 100644 --- a/tests/cases/fourslash/convertFunctionToEs6ClassJsDoc.ts +++ b/tests/cases/fourslash/convertFunctionToEs6ClassJsDoc.ts @@ -17,7 +17,7 @@ /////** //// * This is a cool function! ////*/ -////fn.prototype.bar = function (x, y, z) { +////fn.prototype.bar = function (y) { //// this.x = y; ////}; @@ -38,7 +38,7 @@ verify.codeFix({ /** * This is a cool function! */ - bar(x, y, z) { + bar(y) { this.x = y; } } diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 6e813acaf57c6..e756bd22fae6f 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -518,6 +518,7 @@ declare namespace FourSlashInterface { /** @default `test.ranges()[0]` */ range?: Range; code: number; + unused?: true; } interface VerifyDocumentHighlightsOptions { filesToSearch?: ReadonlyArray; diff --git a/tests/cases/fourslash/incompleteFunctionCallCodefix.ts b/tests/cases/fourslash/incompleteFunctionCallCodefix.ts index 007eaa20f7ff9..a84c48e3da5d8 100644 --- a/tests/cases/fourslash/incompleteFunctionCallCodefix.ts +++ b/tests/cases/fourslash/incompleteFunctionCallCodefix.ts @@ -1,9 +1,10 @@ /// // @noImplicitAny: true -//// function f(/*1*/x) { -//// } -//// f( +////function f(/*1*/x) { +//// x; +////} +////f( verify.not.codeFixAvailable([]); diff --git a/tests/cases/fourslash/incompleteFunctionCallCodefix2.ts b/tests/cases/fourslash/incompleteFunctionCallCodefix2.ts index c1bc731541f62..0fd177585005b 100644 --- a/tests/cases/fourslash/incompleteFunctionCallCodefix2.ts +++ b/tests/cases/fourslash/incompleteFunctionCallCodefix2.ts @@ -1,7 +1,9 @@ /// // @noImplicitAny: true -//// function f(new C(100, 3, undefined) - -verify.not.codeFixAvailable([]); +////function f(new C(100, 3, undefined) +verify.codeFix({ + description: "Prefix 'C' with an underscore", + newFileContent: "function f(new _C(100, 3, undefined)", +}); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts index ff87d3c6948c2..e4b4c34f86a4e 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts @@ -11,10 +11,12 @@ ////exports.y; //// ////exports.z = 2; -////function f(z) { -//// exports.z; +////exports.f = function(z) { +//// z; ////} +// TODO: GH#22492 Should be a able access `exports.z` inside `exports.f` + verify.codeFix({ description: "Convert to ES6 module", newFileContent: @@ -26,9 +28,8 @@ const _y = y; export { _y as y }; _y; -const _z = 2; -export { _z as z }; -function f(z) { - _z; +export const z = 2; +export function f(z) { + z; }`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts b/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts index 746524e849c85..0525a2b881cca 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts @@ -3,13 +3,13 @@ // @allowJs: true // @Filename: /a.js -////exports.f = async function* f(p) {} +////exports.f = async function* f(p) { p; } ////exports.C = class C extends D { m() {} } verify.codeFix({ description: "Convert to ES6 module", newFileContent: -`export async function* f(p) { } +`export async function* f(p) { p; } export class C extends D { m() { } }`, diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts index d7e857b5d5e41..2c53f48a6ebdb 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts @@ -4,9 +4,11 @@ // @Filename: /a.js ////const [x, y] = /*a*/require/*b*/("x"); +////x; y; verify.codeFix({ description: "Convert to ES6 module", newFileContent: `import _x from "x"; -const [x, y] = _x;`, +const [x, y] = _x; +x; y;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts index a42f1fe5321d7..44750b76e6ee9 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts @@ -6,6 +6,7 @@ ////const x = require("x"); ////const [a, b] = require("x"); ////const {c, ...d} = require("x"); +////x; a; b; c; d; verify.codeFix({ description: "Convert to ES6 module", @@ -14,5 +15,6 @@ verify.codeFix({ import _x from "x"; const [a, b] = _x; import __x from "x"; -const { c, ...d } = __x;`, +const { c, ...d } = __x; +x; a; b; c; d;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts index 3c45950c90d93..ae387c060c748 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts @@ -6,11 +6,13 @@ // @Filename: /a.js ////const x = require("x"), y = 0, { z } = require("z"); +////x; y; z; verify.codeFix({ description: "Convert to ES6 module", newFileContent: `import x from "x"; const y = 0; -import { z } from "z";`, +import { z } from "z"; +x; y; z;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts index 32df990696490..f1397e462076d 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts @@ -4,10 +4,12 @@ // @Filename: /a.js ////const { x: { a, b } } = require("x"); +////a; b; verify.codeFix({ description: "Convert to ES6 module", newFileContent: `import x from "x"; -const { x: { a, b } } = x;`, +const { x: { a, b } } = x; +a; b;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts index 4bff560e530c1..52cb72783b1e0 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts @@ -4,8 +4,11 @@ // @Filename: /a.js ////const { x, y: z } = require("x"); +////x; z; verify.codeFix({ description: "Convert to ES6 module", - newFileContent: 'import { x, y as z } from "x";', + newFileContent: +`import { x, y as z } from "x"; +x; z;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts index 34c6ee6aa57f1..8d299d4f0ecb0 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts @@ -8,6 +8,7 @@ ////const a = require("a").a; ////const [a, b] = require("c").d; ////const [a, b] = require("c").a; // Test that we avoid shadowing the earlier local variable 'a' from 'const [a,b] = d;'. +////x; a; b; verify.codeFix({ description: "Convert to ES6 module", @@ -18,5 +19,6 @@ import { a } from "a"; import { d } from "c"; const [a, b] = d; import { a as _a } from "c"; -const [a, b] = _a; // Test that we avoid shadowing the earlier local variable 'a' from 'const [a,b] = d;'.`, +const [a, b] = _a; // Test that we avoid shadowing the earlier local variable 'a' from 'const [a,b] = d;'. +x; a; b;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_preserveQuotes.ts b/tests/cases/fourslash/refactorConvertToEs6Module_preserveQuotes.ts index 5260dc14fbc89..8aa8153888764 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_preserveQuotes.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_preserveQuotes.ts @@ -2,9 +2,9 @@ // @allowJs: true // @Filename: /a.js -////const a = require('a'); +////const a = require('a'); a; verify.codeFix({ description: "Convert to ES6 module", - newFileContent: "import a from 'a';", + newFileContent: "import a from 'a'; a;", });