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<Diagnostic> {
+                    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<true>(); // For assertion that we don't defer the same identifier twice
+        const allPotentiallyUnusedIdentifiers = createMap<ReadonlyArray<PotentiallyUnusedIdentifier>>(); // key is file name
+        let potentiallyUnusedIdentifiers: PotentiallyUnusedIdentifier[]; // Potentially unused identifiers in the source file currently being checked.
+        const seenPotentiallyUnusedIdentifiers = createMap<true>(); // 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<Diagnostic>();
-        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 = <TransientSymbol>(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(<FunctionLikeDeclaration>node);
                     }
                 }
-                if (noUnusedIdentifiers && !(<FunctionDeclaration>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(<ModuleDeclaration | SourceFile>node);
-                            break;
-                        case SyntaxKind.ClassDeclaration:
-                        case SyntaxKind.ClassExpression:
-                            checkUnusedClassMembers(<ClassDeclaration | ClassExpression>node);
-                            checkUnusedTypeParameters(<ClassDeclaration | ClassExpression>node);
-                            break;
-                        case SyntaxKind.InterfaceDeclaration:
-                            checkUnusedTypeParameters(<InterfaceDeclaration>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 ((<FunctionLikeDeclaration>node).body) {
-                                checkUnusedLocalsAndParameters(<FunctionLikeDeclaration>node);
-                            }
-                            checkUnusedTypeParameters(<FunctionLikeDeclaration>node);
-                            break;
-                        case SyntaxKind.MethodSignature:
-                        case SyntaxKind.CallSignature:
-                        case SyntaxKind.ConstructSignature:
-                        case SyntaxKind.FunctionType:
-                        case SyntaxKind.ConstructorType:
-                        case SyntaxKind.TypeAliasDeclaration:
-                            checkUnusedTypeParameters(<MethodSignature | CallSignatureDeclaration | ConstructSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | TypeAliasDeclaration>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<SignatureDeclaration, IndexSignatureDeclaration | JSDocFunctionType> | TypeAliasDeclaration;
+
+        function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: ReadonlyArray<PotentiallyUnusedIdentifier>, 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 = <ParameterDeclaration>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 (<ConstructorDeclaration>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<Diagnostic>(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<protocol.SyntacticDiagnosticsSyncRequest | protocol.SemanticDiagnosticsSyncRequest | protocol.SuggestionDiagnosticsSyncRequest>(command, { file, includeLinePosition: true });
             const response = this.processResponse<protocol.SyntacticDiagnosticsSyncResponse | protocol.SemanticDiagnosticsSyncResponse | protocol.SuggestionDiagnosticsSyncResponse>(request);
 
-            return (<protocol.DiagnosticWithLinePosition[]>response.body).map(entry => {
+            return (<protocol.DiagnosticWithLinePosition[]>response.body).map((entry): Diagnostic => {
                 const category = firstDefined(Object.keys(DiagnosticCategory), id =>
                     isString(id) && entry.category === id.toLowerCase() ? (<any>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<Diagnostic>, 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<String>} 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<String>} zeta
  */
 function f(x: boolean, y: string, z: number, alpha: object, beta: Date, gamma: Promise<any>, delta: Array<any>, epsilon: Array<number>, zeta: Promise<string>) {
+    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 @@
 /// <reference path='fourslash.ts' />
 // @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 @@
 /// <reference path='fourslash.ts' />
 ////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<T>(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<T>(a, b) {
+////function f<T>(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<string, boolean>} sb
 ////  * @param {Object<number, string>} ns */
 ////function f(sb, ns) {
+////    sb; ns;
 ////}
 
 verify.codeFix({
@@ -13,5 +14,6 @@ verify.codeFix({
 /** @param {Object<string, boolean>} sb
   * @param {Object<number, string>} 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 @@
 /// <reference path='fourslash.ts' />
 
 // @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 @@
 /// <reference path='fourslash.ts' />
 
-////interface I<X> { x: X}
-////[|class C<T extends string , U> extends I<T>|]{}
+////interface I<X, Y> { x: X; y: Y; }
+////[|class C<T extends string , U> extends I<T , U>|]{}
 
 verify.codeFix({
     description: "Change 'extends' to 'implements'",
-    newRangeContent: "class C<T extends string , U> implements I<T>",
+    newRangeContent: "class C<T extends string , U> implements I<T , U>",
 });
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 @@
 /// <reference path='fourslash.ts' />
-//// 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 @@
 /// <reference path='fourslash.ts' />
 
 ////function foo<T>(a: T) {
+////    a;
 ////    abstract class C<U> {
 ////        abstract a: T | U;
 ////    }
@@ -14,6 +15,7 @@ verify.codeFix({
     // TODO: GH#18795
     newFileContent:
 `function foo<T>(a: T) {
+    a;
     abstract class C<U> {
         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 @@
 /// <reference path='fourslash.ts' />
 
 ////function foo<T>(a: T) {
+////    a;
 ////    abstract class C<U> {
 ////        abstract a: T | U;
 ////    }
@@ -14,6 +15,7 @@ verify.codeFix({
     // TODO: GH#18795
     newFileContent:
 `function foo<T>(a: T) {
+    a;
     abstract class C<U> {
         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 @@
 /// <reference path='fourslash.ts' />
 
 ////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 @@
 /// <reference path='fourslash.ts' />
 
 ////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<T extends number>();
+////    abstract fA<T extends number>(): 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<T extends number>();
+    abstract fA<T extends number>(): T;
 }
 interface I1 extends C1, C2 { }
 class C3 implements I1 {
-    fA<T extends number>() {
+    fA<T extends number>(): 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 @@
 /// <reference path='fourslash.ts' />
 
 ////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 @@
 /// <reference path='fourslash.ts' />
 
 // @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 @@
+/// <reference path='fourslash.ts' />
+
+////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<string>;
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 @@
 /// <reference path='fourslash.ts' />
 
 // @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 @@
 /// <reference path='fourslash.ts' />
 
 // @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;",
 });