From 17a428c21f6820b05519a381c0448b5c0cb14ce4 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 28 Jun 2016 16:04:52 -0700 Subject: [PATCH 01/18] Fix #9402: Do not report unused identifier errors for catch variables --- src/compiler/checker.ts | 1 - .../reference/unusedParameterInCatchClause.errors.txt | 10 ---------- .../reference/unusedParameterInCatchClause.symbols | 8 ++++++++ .../reference/unusedParameterInCatchClause.types | 8 ++++++++ 4 files changed, 16 insertions(+), 11 deletions(-) delete mode 100644 tests/baselines/reference/unusedParameterInCatchClause.errors.txt create mode 100644 tests/baselines/reference/unusedParameterInCatchClause.symbols create mode 100644 tests/baselines/reference/unusedParameterInCatchClause.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06591a7ab3d44..a7b69c96e1cdb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15563,7 +15563,6 @@ namespace ts { } checkBlock(catchClause.block); - checkUnusedIdentifiers(catchClause); } if (node.finallyBlock) { diff --git a/tests/baselines/reference/unusedParameterInCatchClause.errors.txt b/tests/baselines/reference/unusedParameterInCatchClause.errors.txt deleted file mode 100644 index e996763e2c6f4..0000000000000 --- a/tests/baselines/reference/unusedParameterInCatchClause.errors.txt +++ /dev/null @@ -1,10 +0,0 @@ -tests/cases/compiler/unusedParameterInCatchClause.ts(3,18): error TS6133: 'ex' is declared but never used. - - -==== tests/cases/compiler/unusedParameterInCatchClause.ts (1 errors) ==== - - function f1() { - try {} catch(ex){} - ~~ -!!! error TS6133: 'ex' is declared but never used. - } \ No newline at end of file diff --git a/tests/baselines/reference/unusedParameterInCatchClause.symbols b/tests/baselines/reference/unusedParameterInCatchClause.symbols new file mode 100644 index 0000000000000..9406d3ea53eb5 --- /dev/null +++ b/tests/baselines/reference/unusedParameterInCatchClause.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/unusedParameterInCatchClause.ts === + +function f1() { +>f1 : Symbol(f1, Decl(unusedParameterInCatchClause.ts, 0, 0)) + + try {} catch(ex){} +>ex : Symbol(ex, Decl(unusedParameterInCatchClause.ts, 2, 17)) +} diff --git a/tests/baselines/reference/unusedParameterInCatchClause.types b/tests/baselines/reference/unusedParameterInCatchClause.types new file mode 100644 index 0000000000000..ad23b5d753b74 --- /dev/null +++ b/tests/baselines/reference/unusedParameterInCatchClause.types @@ -0,0 +1,8 @@ +=== tests/cases/compiler/unusedParameterInCatchClause.ts === + +function f1() { +>f1 : () => void + + try {} catch(ex){} +>ex : any +} From aeadbe4376acae542b4c8344b50e0d98fafbc879 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 28 Jun 2016 23:37:26 -0700 Subject: [PATCH 02/18] Defere checking unsed identifier checks --- src/compiler/checker.ts | 152 +++++++++++++++++++++++++++------------- 1 file changed, 103 insertions(+), 49 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7b69c96e1cdb..05cb7df24fba2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -51,6 +51,7 @@ namespace ts { const compilerOptions = host.getCompilerOptions(); const languageVersion = compilerOptions.target || ScriptTarget.ES3; const modulekind = getEmitModuleKind(compilerOptions); + const noUnusedIdentifiers = compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters; const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System; const strictNullChecks = compilerOptions.strictNullChecks; @@ -8323,7 +8324,7 @@ namespace ts { const extendedTypeNode = getClassExtendsHeritageClauseElement(node); if (extendedTypeNode) { const t = getTypeFromTypeNode(extendedTypeNode); - if (t !== unknownType && t.symbol && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) && !isInAmbientContext(node)) { + if (t !== unknownType && t.symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { t.symbol.hasReference = true; } } @@ -8331,7 +8332,7 @@ namespace ts { function checkIdentifier(node: Identifier): Type { const symbol = getResolvedSymbol(node); - if (symbol && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) && !isInAmbientContext(node)) { + if (symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { symbol.hasReference = true; } @@ -10248,7 +10249,7 @@ namespace ts { return unknownType; } - if ((compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) && !isInAmbientContext(node)) { + if (noUnusedIdentifiers && !isInAmbientContext(node)) { prop.hasReference = true; } @@ -12155,47 +12156,54 @@ namespace ts { } function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + if (node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)) { - const isAsync = isAsyncFunctionLike(node); - const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type)); - if (!node.asteriskToken) { - // return is not necessary in the body of generators - checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType); - } - - if (node.body) { - if (!node.type) { - // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors - // we need. An example is the noImplicitAny errors resulting from widening the return expression - // of a function. Because checking of function expression bodies is deferred, there was never an - // appropriate time to do this during the main walk of the file (see the comment at the top of - // checkFunctionExpressionBodies). So it must be done now. - getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + const isAsync = isAsyncFunctionLike(node); + const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type)); + if (!node.asteriskToken) { + // return is not necessary in the body of generators + checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType); } - if (node.body.kind === SyntaxKind.Block) { - checkSourceElement(node.body); - } - else { - // From within an async function you can return either a non-promise value or a promise. Any - // Promise/A+ compatible implementation will always assimilate any foreign promise, so we - // should not be checking assignability of a promise to the return type. Instead, we need to - // check assignability of the awaited type of the expression body against the promised type of - // its return type annotation. - const exprType = checkExpression(node.body); - if (returnOrPromisedType) { - if (isAsync) { - const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member); - checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body); + if (node.body) { + if (!node.type) { + // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors + // we need. An example is the noImplicitAny errors resulting from widening the return expression + // of a function. Because checking of function expression bodies is deferred, there was never an + // appropriate time to do this during the main walk of the file (see the comment at the top of + // checkFunctionExpressionBodies). So it must be done now. + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } + + if (node.body.kind === SyntaxKind.Block) { + checkSourceElement(node.body); + } + else { + // From within an async function you can return either a non-promise value or a promise. Any + // Promise/A+ compatible implementation will always assimilate any foreign promise, so we + // should not be checking assignability of a promise to the return type. Instead, we need to + // check assignability of the awaited type of the expression body against the promised type of + // its return type annotation. + const exprType = checkExpression(node.body); + if (returnOrPromisedType) { + if (isAsync) { + const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member); + checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body); + } + else { + checkTypeAssignableTo(exprType, returnOrPromisedType, node.body); + } } - else { - checkTypeAssignableTo(exprType, returnOrPromisedType, node.body); + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); } } } - checkUnusedIdentifiers(node); - checkUnusedTypeParameters(node); + } + else { + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } } } @@ -13423,8 +13431,10 @@ namespace ts { checkGrammarConstructorTypeParameters(node) || checkGrammarConstructorTypeAnnotation(node); checkSourceElement(node.body); - checkUnusedIdentifiers(node); - checkUnusedTypeParameters(node); + + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } const symbol = getSymbolOfNode(node); const firstDeclaration = getDeclarationOfKind(symbol, node.kind); @@ -13586,6 +13596,8 @@ namespace ts { function checkAccessorDeferred(node: AccessorDeclaration) { checkSourceElement(node.body); + checkUnusedIdentifiers(node); + checkUnusedTypeParameters(node); } function checkMissingDeclaration(node: Node) { @@ -13618,7 +13630,7 @@ namespace ts { checkGrammarTypeArguments(node, node.typeArguments); const type = getTypeFromTypeReference(node); if (type !== unknownType) { - if (type.symbol && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) && !isInAmbientContext(node)) { + if (type.symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { type.symbol.hasReference = true; } if (node.typeArguments) { @@ -14471,8 +14483,7 @@ namespace ts { } checkSourceElement(node.body); - checkUnusedIdentifiers(node); - checkUnusedTypeParameters(node); + if (!node.asteriskToken) { const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type)); checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType); @@ -14492,10 +14503,19 @@ namespace ts { getReturnTypeOfSignature(getSignatureFromDeclaration(node)); } } + + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } + } + + function checkFunctionOrConstructorDeclarationDeferred(node: FunctionDeclaration | ConstructorDeclaration) { + checkUnusedIdentifiers(node); + checkUnusedTypeParameters(node); } function checkUnusedIdentifiers(node: FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction | ForInStatement | Block | CatchClause): void { - if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) && !isInAmbientContext(node)) { + if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) { for (const key in node.locals) { if (hasProperty(node.locals, key)) { const local = node.locals[key]; @@ -14514,7 +14534,7 @@ namespace ts { } } - function checkUnusedClassLocals(node: ClassDeclaration): void { + function checkUnusedClassLocals(node: ClassDeclaration | ClassExpression): void { if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { if (node.members) { for (const member of node.members) { @@ -14535,7 +14555,7 @@ namespace ts { } } - function checkUnusedTypeParameters(node: ClassDeclaration | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration) { + function checkUnusedTypeParameters(node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration) { if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { if (node.typeParameters) { for (const typeParameter of node.typeParameters) { @@ -14570,6 +14590,12 @@ namespace ts { checkGrammarStatementInAmbientContext(node); } forEach(node.statements, checkSourceElement); + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } + } + + function checkBlockDeferred(node: Block | ForInStatement | ForOfStatement) { checkUnusedIdentifiers(node); } @@ -15075,7 +15101,9 @@ namespace ts { } checkSourceElement(node.statement); - checkUnusedIdentifiers(node); + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } } function checkForInStatement(node: ForInStatement) { @@ -15123,7 +15151,9 @@ namespace ts { } checkSourceElement(node.statement); - checkUnusedIdentifiers(node); + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } } function checkForInOrForOfVariableDeclaration(iterationStatement: ForInStatement | ForOfStatement): void { @@ -15716,6 +15746,8 @@ namespace ts { function checkClassExpressionDeferred(node: ClassExpression) { forEach(node.members, checkSourceElement); + checkUnusedClassLocals(node); + checkUnusedTypeParameters(node); } function checkClassDeclaration(node: ClassDeclaration) { @@ -15724,6 +15756,13 @@ namespace ts { } checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); + + if (produceDiagnostics && noUnusedIdentifiers) { + checkNodeDeferred(node); + } + } + + function checkClassDeclarationDefered(node: ClassDeclaration) { checkUnusedClassLocals(node); checkUnusedTypeParameters(node); } @@ -16614,7 +16653,7 @@ namespace ts { if (target.flags & SymbolFlags.Type) { checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0); } - if ((compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters) && !isInAmbientContext(node)) { + if (noUnusedIdentifiers && !isInAmbientContext(node)) { target.hasReference = true; } } @@ -16929,6 +16968,18 @@ namespace ts { case SyntaxKind.ClassExpression: checkClassExpressionDeferred(node); break; + case SyntaxKind.Constructor: + case SyntaxKind.FunctionDeclaration: + checkFunctionOrConstructorDeclarationDeferred(node); + break; + case SyntaxKind.Block: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + checkBlockDeferred(node); + break; + case SyntaxKind.ClassDeclaration: + checkClassDeclarationDefered(node); + break; } } } @@ -16959,10 +17010,13 @@ namespace ts { deferredNodes = []; forEach(node.statements, checkSourceElement); + + checkDeferredNodes(); + if (isExternalModule(node)) { checkUnusedModuleLocals(node); } - checkDeferredNodes(); + deferredNodes = undefined; if (isExternalOrCommonJsModule(node)) { From e7fcb661c3b2667522078c58d9b258226888b17a Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 12:06:47 -0700 Subject: [PATCH 03/18] Use a deferred list to check for unused identifiers --- src/compiler/checker.ts | 257 ++++++++++++++++++++++------------------ 1 file changed, 142 insertions(+), 115 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 05cb7df24fba2..938776c35e845 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -188,6 +188,7 @@ namespace ts { let jsxElementClassType: Type; let deferredNodes: Node[]; + let deferredUnusedIdentifierNodes: Node[]; let flowLoopStart = 0; let flowLoopCount = 0; @@ -395,7 +396,7 @@ namespace ts { target.flags |= source.flags; if (source.valueDeclaration && (!target.valueDeclaration || - (target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) { + (target.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && source.valueDeclaration.kind !== SyntaxKind.ModuleDeclaration))) { // other kinds of value declarations take precedence over modules target.valueDeclaration = source.valueDeclaration; } @@ -665,8 +666,8 @@ namespace ts { useResult = result.flags & SymbolFlags.TypeParameter // type parameters are visible in parameter list, return type and type parameter list ? lastLocation === (location).type || - lastLocation.kind === SyntaxKind.Parameter || - lastLocation.kind === SyntaxKind.TypeParameter + lastLocation.kind === SyntaxKind.Parameter || + lastLocation.kind === SyntaxKind.TypeParameter // local types not visible outside the function body : false; } @@ -855,7 +856,7 @@ namespace ts { if (!result) { if (nameNotFoundMessage) { if (!checkAndReportErrorForMissingPrefix(errorLocation, name, nameArg) && - !checkAndReportErrorForExtendingInterface(errorLocation)) { + !checkAndReportErrorForExtendingInterface(errorLocation)) { error(errorLocation, nameNotFoundMessage, typeof nameArg === "string" ? nameArg : declarationNameToString(nameArg)); } } @@ -962,7 +963,7 @@ namespace ts { return true; } return false; - } + } function checkResolvedBlockScopedVariable(result: Symbol, errorLocation: Node): void { Debug.assert((result.flags & SymbolFlags.BlockScopedVariable) !== 0); @@ -1023,8 +1024,8 @@ namespace ts { const exportDefaultSymbol = isShorthandAmbientModule(moduleSymbol.valueDeclaration) ? moduleSymbol : moduleSymbol.exports["export="] ? - getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") : - resolveSymbol(moduleSymbol.exports["default"]); + getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") : + resolveSymbol(moduleSymbol.exports["default"]); if (!exportDefaultSymbol && !allowSyntheticDefaultImports) { error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol)); @@ -4537,7 +4538,7 @@ namespace ts { : undefined; const typeParameters = classType ? classType.localTypeParameters : declaration.typeParameters ? getTypeParametersFromDeclaration(declaration.typeParameters) : - getTypeParametersFromJSDocTemplate(declaration); + getTypeParametersFromJSDocTemplate(declaration); const returnType = getSignatureReturnTypeFromDeclaration(declaration, minArgumentCount, isJSConstructSignature, classType); const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ? createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) : @@ -5166,7 +5167,7 @@ namespace ts { if (typeSet.length === 0) { return typeSet.containsNull ? typeSet.containsNonWideningType ? nullType : nullWideningType : typeSet.containsUndefined ? typeSet.containsNonWideningType ? undefinedType : undefinedWideningType : - neverType; + neverType; } else if (typeSet.length === 1) { return typeSet[0]; @@ -5402,8 +5403,8 @@ namespace ts { const count = sources.length; const mapper: TypeMapper = count == 1 ? createUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) : - count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) : - createArrayTypeMapper(sources, targets); + count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) : + createArrayTypeMapper(sources, targets); mapper.mappedTypes = sources; return mapper; } @@ -5726,8 +5727,8 @@ namespace ts { } function isSignatureAssignableTo(source: Signature, - target: Signature, - ignoreReturnTypes: boolean): boolean { + target: Signature, + ignoreReturnTypes: boolean): boolean { return compareSignaturesRelated(source, target, ignoreReturnTypes, /*reportErrors*/ false, /*errorReporter*/ undefined, compareTypesAssignable) !== Ternary.False; } @@ -5735,11 +5736,11 @@ namespace ts { * See signatureRelatedTo, compareSignaturesIdentical */ function compareSignaturesRelated(source: Signature, - target: Signature, - ignoreReturnTypes: boolean, - reportErrors: boolean, - errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void, - compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { + target: Signature, + ignoreReturnTypes: boolean, + reportErrors: boolean, + errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void, + compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -5821,10 +5822,10 @@ namespace ts { } function compareTypePredicateRelatedTo(source: TypePredicate, - target: TypePredicate, - reportErrors: boolean, - errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void, - compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { + target: TypePredicate, + reportErrors: boolean, + errorReporter: (d: DiagnosticMessage, arg0?: string, arg1?: string) => void, + compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary { if (source.kind !== target.kind) { if (reportErrors) { errorReporter(Diagnostics.A_this_based_type_guard_is_not_compatible_with_a_parameter_based_type_guard); @@ -6905,7 +6906,7 @@ namespace ts { function isStringLiteralUnionType(type: Type): boolean { return type.flags & TypeFlags.StringLiteral ? true : type.flags & TypeFlags.Union ? forEach((type).types, isStringLiteralUnionType) : - false; + false; } /** @@ -6987,11 +6988,11 @@ namespace ts { const resolved = type; const members = transformTypeOfMembers(type, getRegularTypeOfObjectLiteral); const regularNew = createAnonymousType(resolved.symbol, - members, - resolved.callSignatures, - resolved.constructSignatures, - resolved.stringIndexInfo, - resolved.numberIndexInfo); + members, + resolved.callSignatures, + resolved.constructSignatures, + resolved.stringIndexInfo, + resolved.numberIndexInfo); regularNew.flags = resolved.flags & ~TypeFlags.FreshObjectLiteral; (type).regularType = regularNew; return regularNew; @@ -7819,7 +7820,7 @@ namespace ts { // We cache results of flow type resolution for shared nodes that were previously visited in // the same getFlowTypeOfReference invocation. A node is considered shared when it is the // antecedent of more than one node. - for (let i = visitedFlowStart; i < visitedFlowCount; i++) { + for (let i = visitedFlowStart; i < visitedFlowCount; i++) { if (visitedFlowNodes[i] === flow) { return visitedFlowTypes[i]; } @@ -8206,7 +8207,7 @@ namespace ts { const targetType = type.flags & TypeFlags.TypeParameter ? getApparentType(type) : type; return isTypeAssignableTo(candidate, targetType) ? candidate : isTypeAssignableTo(type, candidate) ? type : - getIntersectionType([type, candidate]); + getIntersectionType([type, candidate]); } function narrowTypeByTypePredicate(type: Type, callExpression: CallExpression, assumeTrue: boolean): Type { @@ -8625,9 +8626,9 @@ namespace ts { getSpecialPropertyAssignmentKind(container.parent) === SpecialPropertyAssignmentKind.PrototypeProperty) { // Get the 'x' of 'x.prototype.y = f' (here, 'f' is 'container') const className = (((container.parent as BinaryExpression) // x.prototype.y = f - .left as PropertyAccessExpression) // x.prototype.y - .expression as PropertyAccessExpression) // x.prototype - .expression; // x + .left as PropertyAccessExpression) // x.prototype.y + .expression as PropertyAccessExpression) // x.prototype + .expression; // x const classSymbol = checkExpression(className).symbol; if (classSymbol && classSymbol.members && (classSymbol.flags & SymbolFlags.Function)) { return getInferredClassType(classSymbol); @@ -9872,7 +9873,7 @@ namespace ts { elemType = checkExpression(node.tagName); } if (elemType.flags & TypeFlags.Union) { - const types = ( elemType).types; + const types = (elemType).types; return getUnionType(types.map(type => { return getResolvedJsxType(node, type, elemClassType); })); @@ -11804,7 +11805,7 @@ namespace ts { // if inference didn't come up with anything but {}, fall back to the binding pattern if present. if (links.type === emptyObjectType && (parameter.valueDeclaration.name.kind === SyntaxKind.ObjectBindingPattern || - parameter.valueDeclaration.name.kind === SyntaxKind.ArrayBindingPattern)) { + parameter.valueDeclaration.name.kind === SyntaxKind.ArrayBindingPattern)) { links.type = getTypeFromBindingPattern(parameter.valueDeclaration.name); } assignBindingElementTypes(parameter.valueDeclaration); @@ -12156,53 +12157,47 @@ namespace ts { } function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { - if (node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)) { + Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); - const isAsync = isAsyncFunctionLike(node); - const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type)); - if (!node.asteriskToken) { - // return is not necessary in the body of generators - checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType); - } + const isAsync = isAsyncFunctionLike(node); + const returnOrPromisedType = node.type && (isAsync ? checkAsyncFunctionReturnType(node) : getTypeFromTypeNode(node.type)); + if (!node.asteriskToken) { + // return is not necessary in the body of generators + checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnOrPromisedType); + } - if (node.body) { - if (!node.type) { - // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors - // we need. An example is the noImplicitAny errors resulting from widening the return expression - // of a function. Because checking of function expression bodies is deferred, there was never an - // appropriate time to do this during the main walk of the file (see the comment at the top of - // checkFunctionExpressionBodies). So it must be done now. - getReturnTypeOfSignature(getSignatureFromDeclaration(node)); - } + if (node.body) { + if (!node.type) { + // There are some checks that are only performed in getReturnTypeFromBody, that may produce errors + // we need. An example is the noImplicitAny errors resulting from widening the return expression + // of a function. Because checking of function expression bodies is deferred, there was never an + // appropriate time to do this during the main walk of the file (see the comment at the top of + // checkFunctionExpressionBodies). So it must be done now. + getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + } - if (node.body.kind === SyntaxKind.Block) { - checkSourceElement(node.body); - } - else { - // From within an async function you can return either a non-promise value or a promise. Any - // Promise/A+ compatible implementation will always assimilate any foreign promise, so we - // should not be checking assignability of a promise to the return type. Instead, we need to - // check assignability of the awaited type of the expression body against the promised type of - // its return type annotation. - const exprType = checkExpression(node.body); - if (returnOrPromisedType) { - if (isAsync) { - const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member); - checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body); - } - else { - checkTypeAssignableTo(exprType, returnOrPromisedType, node.body); - } + if (node.body.kind === SyntaxKind.Block) { + checkSourceElement(node.body); + } + else { + // From within an async function you can return either a non-promise value or a promise. Any + // Promise/A+ compatible implementation will always assimilate any foreign promise, so we + // should not be checking assignability of a promise to the return type. Instead, we need to + // check assignability of the awaited type of the expression body against the promised type of + // its return type annotation. + const exprType = checkExpression(node.body); + if (returnOrPromisedType) { + if (isAsync) { + const awaitedType = checkAwaitedType(exprType, node.body, Diagnostics.Expression_body_for_async_arrow_function_does_not_have_a_valid_callable_then_member); + checkTypeAssignableTo(awaitedType, returnOrPromisedType, node.body); } - if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + else { + checkTypeAssignableTo(exprType, returnOrPromisedType, node.body); } } } - } - else { if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + checkUnusedIdentifiersDeferred(node) } } } @@ -13433,7 +13428,7 @@ namespace ts { checkSourceElement(node.body); if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + checkUnusedIdentifiersDeferred(node); } const symbol = getSymbolOfNode(node); @@ -13580,6 +13575,9 @@ namespace ts { } if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); + if (noUnusedIdentifiers) { + checkUnusedIdentifiersDeferred(node); + } } else { checkNodeDeferred(node); @@ -13596,8 +13594,9 @@ namespace ts { function checkAccessorDeferred(node: AccessorDeclaration) { checkSourceElement(node.body); - checkUnusedIdentifiers(node); - checkUnusedTypeParameters(node); + if (produceDiagnostics && noUnusedIdentifiers) { + checkUnusedIdentifiersDeferred(node); + } } function checkMissingDeclaration(node: Node) { @@ -14505,16 +14504,57 @@ namespace ts { } if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + checkUnusedIdentifiersDeferred(node) } } - function checkFunctionOrConstructorDeclarationDeferred(node: FunctionDeclaration | ConstructorDeclaration) { - checkUnusedIdentifiers(node); - checkUnusedTypeParameters(node); + function checkUnusedIdentifiersDeferred(node: Node) { + deferredUnusedIdentifierNodes.push(node); } - function checkUnusedIdentifiers(node: FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction | ForInStatement | Block | CatchClause): void { + function checkUnusedIdentifiersDeferredNodes() { + for (const node of deferredUnusedIdentifierNodes) { + switch (node.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: + checkUnusedModuleLocals(node); + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + checkUnusedClassLocals(node); + checkUnusedTypeParameters(node); + break; + case SyntaxKind.InterfaceDeclaration: + checkUnusedTypeParameters(node); + break; + case SyntaxKind.Block: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + checkUnusedIdentifiers(node); + break; + case SyntaxKind.Constructor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + checkUnusedIdentifiers(node); + + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + checkUnusedTypeParameters(node); + break; + }; + } + } + + function checkUnusedIdentifiers(node: FunctionLikeDeclaration | ForStatement | Block): void { if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) { for (const key in node.locals) { if (hasProperty(node.locals, key)) { @@ -14590,15 +14630,11 @@ namespace ts { checkGrammarStatementInAmbientContext(node); } forEach(node.statements, checkSourceElement); - if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + if (produceDiagnostics && noUnusedIdentifiers && node.locals) { + checkUnusedIdentifiersDeferred(node); } } - function checkBlockDeferred(node: Block | ForInStatement | ForOfStatement) { - checkUnusedIdentifiers(node); - } - function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact if (!hasDeclaredRestParameter(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { @@ -15101,8 +15137,8 @@ namespace ts { } checkSourceElement(node.statement); - if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + if (produceDiagnostics && noUnusedIdentifiers && node.locals) { + checkUnusedIdentifiersDeferred(node); } } @@ -15151,8 +15187,8 @@ namespace ts { } checkSourceElement(node.statement); - if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + if (produceDiagnostics && noUnusedIdentifiers && node.locals) { + checkUnusedIdentifiersDeferred(node) } } @@ -15746,8 +15782,9 @@ namespace ts { function checkClassExpressionDeferred(node: ClassExpression) { forEach(node.members, checkSourceElement); - checkUnusedClassLocals(node); - checkUnusedTypeParameters(node); + if (produceDiagnostics && noUnusedIdentifiers) { + checkUnusedIdentifiersDeferred(node) + } } function checkClassDeclaration(node: ClassDeclaration) { @@ -15758,15 +15795,10 @@ namespace ts { forEach(node.members, checkSourceElement); if (produceDiagnostics && noUnusedIdentifiers) { - checkNodeDeferred(node); + checkUnusedIdentifiersDeferred(node); } } - function checkClassDeclarationDefered(node: ClassDeclaration) { - checkUnusedClassLocals(node); - checkUnusedTypeParameters(node); - } - function checkClassLikeDeclaration(node: ClassLikeDeclaration) { checkGrammarClassDeclarationHeritageClauses(node); checkDecorators(node); @@ -16472,7 +16504,9 @@ namespace ts { if (node.body) { checkSourceElement(node.body); - checkUnusedModuleLocals(node); + if (produceDiagnostics && noUnusedIdentifiers) { + checkUnusedIdentifiersDeferred(node); + } } } @@ -16968,18 +17002,6 @@ namespace ts { case SyntaxKind.ClassExpression: checkClassExpressionDeferred(node); break; - case SyntaxKind.Constructor: - case SyntaxKind.FunctionDeclaration: - checkFunctionOrConstructorDeclarationDeferred(node); - break; - case SyntaxKind.Block: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - checkBlockDeferred(node); - break; - case SyntaxKind.ClassDeclaration: - checkClassDeclarationDefered(node); - break; } } } @@ -17009,15 +17031,20 @@ namespace ts { potentialThisCollisions.length = 0; deferredNodes = []; + deferredUnusedIdentifierNodes = []; + forEach(node.statements, checkSourceElement); checkDeferredNodes(); - if (isExternalModule(node)) { - checkUnusedModuleLocals(node); + if (isExternalModule(node) && produceDiagnostics && noUnusedIdentifiers) { + checkUnusedIdentifiersDeferred(node); } + checkUnusedIdentifiersDeferredNodes(); + deferredNodes = undefined; + deferredUnusedIdentifierNodes = undefined; if (isExternalOrCommonJsModule(node)) { checkExternalModuleExports(node); From 7836ba093e1f1dab8d79a58eae96918e5bb0cfe7 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 12:07:08 -0700 Subject: [PATCH 04/18] push checks to checkUnusedIdentifiersDeferred --- src/compiler/checker.ts | 125 ++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 69 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 938776c35e845..6a7cbce6083d9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12196,9 +12196,7 @@ namespace ts { } } } - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node) - } + checkUnusedIdentifiersDeferred(node); } } @@ -13426,10 +13424,7 @@ namespace ts { checkGrammarConstructorTypeParameters(node) || checkGrammarConstructorTypeAnnotation(node); checkSourceElement(node.body); - - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node); - } + checkUnusedIdentifiersDeferred(node); const symbol = getSymbolOfNode(node); const firstDeclaration = getDeclarationOfKind(symbol, node.kind); @@ -13575,9 +13570,7 @@ namespace ts { } if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); - if (noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node); - } + checkUnusedIdentifiersDeferred(node); } else { checkNodeDeferred(node); @@ -13594,9 +13587,7 @@ namespace ts { function checkAccessorDeferred(node: AccessorDeclaration) { checkSourceElement(node.body); - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node); - } + checkUnusedIdentifiersDeferred(node); } function checkMissingDeclaration(node: Node) { @@ -14503,54 +14494,56 @@ namespace ts { } } - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node) - } + checkUnusedIdentifiersDeferred(node); } function checkUnusedIdentifiersDeferred(node: Node) { - deferredUnusedIdentifierNodes.push(node); + if (deferredUnusedIdentifierNodes) { + deferredUnusedIdentifierNodes.push(node); + } } function checkUnusedIdentifiersDeferredNodes() { - for (const node of deferredUnusedIdentifierNodes) { - switch (node.kind) { - case SyntaxKind.SourceFile: - case SyntaxKind.ModuleDeclaration: - checkUnusedModuleLocals(node); - break; - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - checkUnusedClassLocals(node); - checkUnusedTypeParameters(node); - break; - case SyntaxKind.InterfaceDeclaration: - checkUnusedTypeParameters(node); - break; - case SyntaxKind.Block: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: - checkUnusedIdentifiers(node); - break; - case SyntaxKind.Constructor: - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ArrowFunction: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - checkUnusedIdentifiers(node); + if (deferredUnusedIdentifierNodes) { + for (const node of deferredUnusedIdentifierNodes) { + switch (node.kind) { + case SyntaxKind.SourceFile: + case SyntaxKind.ModuleDeclaration: + checkUnusedModuleLocals(node); + break; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + checkUnusedClassLocals(node); + checkUnusedTypeParameters(node); + break; + case SyntaxKind.InterfaceDeclaration: + checkUnusedTypeParameters(node); + break; + case SyntaxKind.Block: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + checkUnusedIdentifiers(node); + break; + case SyntaxKind.Constructor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + checkUnusedIdentifiers(node); - case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructorType: - checkUnusedTypeParameters(node); - break; - }; + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructorType: + checkUnusedTypeParameters(node); + break; + }; + } } } @@ -14630,7 +14623,7 @@ namespace ts { checkGrammarStatementInAmbientContext(node); } forEach(node.statements, checkSourceElement); - if (produceDiagnostics && noUnusedIdentifiers && node.locals) { + if (node.locals) { checkUnusedIdentifiersDeferred(node); } } @@ -15137,7 +15130,7 @@ namespace ts { } checkSourceElement(node.statement); - if (produceDiagnostics && noUnusedIdentifiers && node.locals) { + if (node.locals) { checkUnusedIdentifiersDeferred(node); } } @@ -15187,8 +15180,8 @@ namespace ts { } checkSourceElement(node.statement); - if (produceDiagnostics && noUnusedIdentifiers && node.locals) { - checkUnusedIdentifiersDeferred(node) + if (node.locals) { + checkUnusedIdentifiersDeferred(node); } } @@ -15782,9 +15775,7 @@ namespace ts { function checkClassExpressionDeferred(node: ClassExpression) { forEach(node.members, checkSourceElement); - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node) - } + checkUnusedIdentifiersDeferred(node); } function checkClassDeclaration(node: ClassDeclaration) { @@ -15794,9 +15785,7 @@ namespace ts { checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node); - } + checkUnusedIdentifiersDeferred(node); } function checkClassLikeDeclaration(node: ClassLikeDeclaration) { @@ -16504,9 +16493,7 @@ namespace ts { if (node.body) { checkSourceElement(node.body); - if (produceDiagnostics && noUnusedIdentifiers) { - checkUnusedIdentifiersDeferred(node); - } + checkUnusedIdentifiersDeferred(node); } } @@ -17031,13 +17018,13 @@ namespace ts { potentialThisCollisions.length = 0; deferredNodes = []; - deferredUnusedIdentifierNodes = []; + deferredUnusedIdentifierNodes = produceDiagnostics && noUnusedIdentifiers ? [] : undefined; forEach(node.statements, checkSourceElement); checkDeferredNodes(); - if (isExternalModule(node) && produceDiagnostics && noUnusedIdentifiers) { + if (isExternalModule(node)) { checkUnusedIdentifiersDeferred(node); } From b1b3ae07e0aaab8e7a897e47277d66994cd3ea2b Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 12:09:49 -0700 Subject: [PATCH 05/18] use isParameterPropertyDeclaration to test for paramter propoerties --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6a7cbce6083d9..65f0a8dd888ef 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14557,7 +14557,7 @@ namespace ts { error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name); } else if (local.valueDeclaration.kind === SyntaxKind.Parameter && compilerOptions.noUnusedParameters) { - if (local.valueDeclaration.flags === 0) { + if (!isParameterPropertyDeclaration(local.valueDeclaration)) { error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name); } } From c28487db92a5079767300df89ece6e28d52e7bf3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 13:18:06 -0700 Subject: [PATCH 06/18] Report unused identifiers in for statements --- src/compiler/checker.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65f0a8dd888ef..06813b82557a4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15090,6 +15090,7 @@ namespace ts { if (node.condition) checkExpression(node.condition); if (node.incrementor) checkExpression(node.incrementor); checkSourceElement(node.statement); + checkUnusedIdentifiersDeferred(node); } function checkForOfStatement(node: ForOfStatement): void { From 4789ff0316f7a19e53fda55f07a54ff3aedaa26d Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 13:34:41 -0700 Subject: [PATCH 07/18] Do not check ambients, and overloads --- src/compiler/checker.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06813b82557a4..d1c3a88c85ee4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14532,8 +14532,11 @@ namespace ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: - checkUnusedIdentifiers(node); - + if ((node).body) { + checkUnusedIdentifiers(node); + } + checkUnusedTypeParameters(node); + break; case SyntaxKind.MethodSignature: case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: @@ -17029,7 +17032,9 @@ namespace ts { checkUnusedIdentifiersDeferred(node); } - checkUnusedIdentifiersDeferredNodes(); + if (!node.isDeclarationFile) { + checkUnusedIdentifiersDeferredNodes(); + } deferredNodes = undefined; deferredUnusedIdentifierNodes = undefined; From 62f47fe995acec622aa88afa19e933b94ee94e3d Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 13:35:10 -0700 Subject: [PATCH 08/18] Add tests --- .../unusedLocalsAndParameters.errors.txt | 159 +++++++++ .../reference/unusedLocalsAndParameters.js | 168 +++++++++ ...usedLocalsAndParametersDeferred.errors.txt | 172 +++++++++ .../unusedLocalsAndParametersDeferred.js | 325 ++++++++++++++++++ ...edLocalsAndParametersOverloadSignatures.js | 45 +++ ...alsAndParametersOverloadSignatures.symbols | 70 ++++ ...ocalsAndParametersOverloadSignatures.types | 74 ++++ .../compiler/unusedLocalsAndParameters.ts | 86 +++++ .../unusedLocalsAndParametersDeferred.ts | 162 +++++++++ ...edLocalsAndParametersOverloadSignatures.ts | 25 ++ 10 files changed, 1286 insertions(+) create mode 100644 tests/baselines/reference/unusedLocalsAndParameters.errors.txt create mode 100644 tests/baselines/reference/unusedLocalsAndParameters.js create mode 100644 tests/baselines/reference/unusedLocalsAndParametersDeferred.errors.txt create mode 100644 tests/baselines/reference/unusedLocalsAndParametersDeferred.js create mode 100644 tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.js create mode 100644 tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.symbols create mode 100644 tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.types create mode 100644 tests/cases/compiler/unusedLocalsAndParameters.ts create mode 100644 tests/cases/compiler/unusedLocalsAndParametersDeferred.ts create mode 100644 tests/cases/compiler/unusedLocalsAndParametersOverloadSignatures.ts diff --git a/tests/baselines/reference/unusedLocalsAndParameters.errors.txt b/tests/baselines/reference/unusedLocalsAndParameters.errors.txt new file mode 100644 index 0000000000000..a7b1d1b37f485 --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParameters.errors.txt @@ -0,0 +1,159 @@ +tests/cases/compiler/unusedLocalsAndParameters.ts(5,12): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(10,22): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(16,5): error TS6133: 'farrow' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(16,15): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(19,7): error TS6133: 'C' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(21,12): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(24,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/compiler/unusedLocalsAndParameters.ts(24,11): error TS6133: 'v' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(28,5): error TS6133: 'E' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(30,12): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(33,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/compiler/unusedLocalsAndParameters.ts(33,11): error TS6133: 'v' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(39,12): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(42,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/compiler/unusedLocalsAndParameters.ts(42,11): error TS6133: 'v' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(49,10): error TS6133: 'i' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(53,10): error TS6133: 'i' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(57,17): error TS6133: 'n' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(64,11): error TS6133: 'c' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(69,11): error TS6133: 'a' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(72,11): error TS6133: 'c' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(75,11): error TS6133: 'c' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(80,11): error TS6133: 'N' is declared but never used. +tests/cases/compiler/unusedLocalsAndParameters.ts(81,9): error TS6133: 'x' is declared but never used. + + +==== tests/cases/compiler/unusedLocalsAndParameters.ts (24 errors) ==== + + export { }; + + // function declaration paramter + function f(a) { + ~ +!!! error TS6133: 'a' is declared but never used. + } + f(0); + + // function expression paramter + var fexp = function (a) { + ~ +!!! error TS6133: 'a' is declared but never used. + }; + + fexp(0); + + // arrow function paramter + var farrow = (a) => { + ~~~~~~ +!!! error TS6133: 'farrow' is declared but never used. + ~ +!!! error TS6133: 'a' is declared but never used. + }; + + class C { + ~ +!!! error TS6133: 'C' is declared but never used. + // Method declaration paramter + method(a) { + ~ +!!! error TS6133: 'a' is declared but never used. + } + // Accessor declaration paramter + set x(v: number) { + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + ~ +!!! error TS6133: 'v' is declared but never used. + } + } + + var E = class { + ~ +!!! error TS6133: 'E' is declared but never used. + // Method declaration paramter + method(a) { + ~ +!!! error TS6133: 'a' is declared but never used. + } + // Accessor declaration paramter + set x(v: number) { + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + ~ +!!! error TS6133: 'v' is declared but never used. + } + } + + var o = { + // Object literal method declaration paramter + method(a) { + ~ +!!! error TS6133: 'a' is declared but never used. + }, + // Accessor declaration paramter + set x(v: number) { + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + ~ +!!! error TS6133: 'v' is declared but never used. + } + }; + + o; + + // in a for..in statment + for (let i in o) { + ~ +!!! error TS6133: 'i' is declared but never used. + } + + // in a for..of statment + for (let i of [1, 2, 3]) { + ~ +!!! error TS6133: 'i' is declared but never used. + } + + // in a for. statment + for (let i = 0, n; i < 10; i++) { + ~ +!!! error TS6133: 'n' is declared but never used. + } + + // in a block + + const condition = false; + if (condition) { + const c = 0; + ~ +!!! error TS6133: 'c' is declared but never used. + } + + // in try/catch/finally + try { + const a = 0; + ~ +!!! error TS6133: 'a' is declared but never used. + } + catch (e) { + const c = 1; + ~ +!!! error TS6133: 'c' is declared but never used. + } + finally { + const c = 0; + ~ +!!! error TS6133: 'c' is declared but never used. + } + + + // in a namespace + namespace N { + ~ +!!! error TS6133: 'N' is declared but never used. + var x; + ~ +!!! error TS6133: 'x' is declared but never used. + } + + \ No newline at end of file diff --git a/tests/baselines/reference/unusedLocalsAndParameters.js b/tests/baselines/reference/unusedLocalsAndParameters.js new file mode 100644 index 0000000000000..64ff373db4a91 --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParameters.js @@ -0,0 +1,168 @@ +//// [unusedLocalsAndParameters.ts] + +export { }; + +// function declaration paramter +function f(a) { +} +f(0); + +// function expression paramter +var fexp = function (a) { +}; + +fexp(0); + +// arrow function paramter +var farrow = (a) => { +}; + +class C { + // Method declaration paramter + method(a) { + } + // Accessor declaration paramter + set x(v: number) { + } +} + +var E = class { + // Method declaration paramter + method(a) { + } + // Accessor declaration paramter + set x(v: number) { + } +} + +var o = { + // Object literal method declaration paramter + method(a) { + }, + // Accessor declaration paramter + set x(v: number) { + } +}; + +o; + +// in a for..in statment +for (let i in o) { +} + +// in a for..of statment +for (let i of [1, 2, 3]) { +} + +// in a for. statment +for (let i = 0, n; i < 10; i++) { +} + +// in a block + +const condition = false; +if (condition) { + const c = 0; +} + +// in try/catch/finally +try { + const a = 0; +} +catch (e) { + const c = 1; +} +finally { + const c = 0; +} + + +// in a namespace +namespace N { + var x; +} + + + +//// [unusedLocalsAndParameters.js] +"use strict"; +// function declaration paramter +function f(a) { +} +f(0); +// function expression paramter +var fexp = function (a) { +}; +fexp(0); +// arrow function paramter +var farrow = function (a) { +}; +var C = (function () { + function C() { + } + // Method declaration paramter + C.prototype.method = function (a) { + }; + Object.defineProperty(C.prototype, "x", { + // Accessor declaration paramter + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return C; +}()); +var E = (function () { + function class_1() { + } + // Method declaration paramter + class_1.prototype.method = function (a) { + }; + Object.defineProperty(class_1.prototype, "x", { + // Accessor declaration paramter + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return class_1; +}()); +var o = { + // Object literal method declaration paramter + method: function (a) { + }, + // Accessor declaration paramter + set x(v) { + } +}; +o; +// in a for..in statment +for (var i in o) { +} +// in a for..of statment +for (var _i = 0, _a = [1, 2, 3]; _i < _a.length; _i++) { + var i = _a[_i]; +} +// in a for. statment +for (var i = 0, n = void 0; i < 10; i++) { +} +// in a block +var condition = false; +if (condition) { + var c = 0; +} +// in try/catch/finally +try { + var a = 0; +} +catch (e) { + var c = 1; +} +finally { + var c = 0; +} +// in a namespace +var N; +(function (N) { + var x; +})(N || (N = {})); diff --git a/tests/baselines/reference/unusedLocalsAndParametersDeferred.errors.txt b/tests/baselines/reference/unusedLocalsAndParametersDeferred.errors.txt new file mode 100644 index 0000000000000..63afd213f1cc3 --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersDeferred.errors.txt @@ -0,0 +1,172 @@ +tests/cases/compiler/unusedLocalsAndParametersDeferred.ts(42,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/compiler/unusedLocalsAndParametersDeferred.ts(65,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. +tests/cases/compiler/unusedLocalsAndParametersDeferred.ts(87,9): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + + +==== tests/cases/compiler/unusedLocalsAndParametersDeferred.ts (3 errors) ==== + + export { }; + + function defered(a: () => T): T { + return a(); + } + + // function declaration paramter + function f(a) { + defered(() => { + a; + }); + } + f(0); + + // function expression paramter + var fexp = function (a) { + defered(() => { + a; + }); + }; + fexp(1); + + // arrow function paramter + var farrow = (a) => { + defered(() => { + a; + }); + }; + farrow(2); + + let prop1; + + class C { + // Method declaration paramter + method(a) { + defered(() => { + a; + }); + } + // Accessor declaration paramter + set x(v: number) { + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + defered(() => { + v; + }); + } + // in a property initalizer + p = defered(() => { + prop1; + }); + } + + new C(); + + let prop2; + + var E = class { + // Method declaration paramter + method(a) { + defered(() => { + a; + }); + } + // Accessor declaration paramter + set x(v: number) { + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + defered(() => { + v; + }); + } + // in a property initalizer + p = defered(() => { + prop2; + }); + } + + new E(); + + + var o = { + // Object literal method declaration paramter + method(a) { + defered(() => { + a; + }); + }, + // Accessor declaration paramter + set x(v: number) { + ~ +!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher. + defered(() => { + v; + }); + }, + // in a property initalizer + p: defered(() => { + prop1; + }) + }; + + o; + + // in a for..in statment + for (let i in o) { + defered(() => { + i; + }); + } + + // in a for..of statment + for (let i of [1,2,3]) { + defered(() => { + i; + }); + } + + // in a for. statment + for (let i = 0; i < 10; i++) { + defered(() => { + i; + }); + } + + // in a block + + const condition = false; + if (condition) { + const c = 0; + defered(() => { + c; + }); + } + + // in try/catch/finally + try { + const a = 0; + defered(() => { + a; + }); + } + catch (e) { + const c = 1; + defered(() => { + c; + }); + } + finally { + const c = 0; + defered(() => { + c; + }); + } + + + // in a namespace + namespace N { + var x; + defered(() => { + x; + }); + } + N; + \ No newline at end of file diff --git a/tests/baselines/reference/unusedLocalsAndParametersDeferred.js b/tests/baselines/reference/unusedLocalsAndParametersDeferred.js new file mode 100644 index 0000000000000..7fbfd15c5261a --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersDeferred.js @@ -0,0 +1,325 @@ +//// [unusedLocalsAndParametersDeferred.ts] + +export { }; + +function defered(a: () => T): T { + return a(); +} + +// function declaration paramter +function f(a) { + defered(() => { + a; + }); +} +f(0); + +// function expression paramter +var fexp = function (a) { + defered(() => { + a; + }); +}; +fexp(1); + +// arrow function paramter +var farrow = (a) => { + defered(() => { + a; + }); +}; +farrow(2); + +let prop1; + +class C { + // Method declaration paramter + method(a) { + defered(() => { + a; + }); + } + // Accessor declaration paramter + set x(v: number) { + defered(() => { + v; + }); + } + // in a property initalizer + p = defered(() => { + prop1; + }); +} + +new C(); + +let prop2; + +var E = class { + // Method declaration paramter + method(a) { + defered(() => { + a; + }); + } + // Accessor declaration paramter + set x(v: number) { + defered(() => { + v; + }); + } + // in a property initalizer + p = defered(() => { + prop2; + }); +} + +new E(); + + +var o = { + // Object literal method declaration paramter + method(a) { + defered(() => { + a; + }); + }, + // Accessor declaration paramter + set x(v: number) { + defered(() => { + v; + }); + }, + // in a property initalizer + p: defered(() => { + prop1; + }) +}; + +o; + +// in a for..in statment +for (let i in o) { + defered(() => { + i; + }); +} + +// in a for..of statment +for (let i of [1,2,3]) { + defered(() => { + i; + }); +} + +// in a for. statment +for (let i = 0; i < 10; i++) { + defered(() => { + i; + }); +} + +// in a block + +const condition = false; +if (condition) { + const c = 0; + defered(() => { + c; + }); +} + +// in try/catch/finally +try { + const a = 0; + defered(() => { + a; + }); +} +catch (e) { + const c = 1; + defered(() => { + c; + }); +} +finally { + const c = 0; + defered(() => { + c; + }); +} + + +// in a namespace +namespace N { + var x; + defered(() => { + x; + }); +} +N; + + +//// [unusedLocalsAndParametersDeferred.js] +"use strict"; +function defered(a) { + return a(); +} +// function declaration paramter +function f(a) { + defered(function () { + a; + }); +} +f(0); +// function expression paramter +var fexp = function (a) { + defered(function () { + a; + }); +}; +fexp(1); +// arrow function paramter +var farrow = function (a) { + defered(function () { + a; + }); +}; +farrow(2); +var prop1; +var C = (function () { + function C() { + // in a property initalizer + this.p = defered(function () { + prop1; + }); + } + // Method declaration paramter + C.prototype.method = function (a) { + defered(function () { + a; + }); + }; + Object.defineProperty(C.prototype, "x", { + // Accessor declaration paramter + set: function (v) { + defered(function () { + v; + }); + }, + enumerable: true, + configurable: true + }); + return C; +}()); +new C(); +var prop2; +var E = (function () { + function class_1() { + // in a property initalizer + this.p = defered(function () { + prop2; + }); + } + // Method declaration paramter + class_1.prototype.method = function (a) { + defered(function () { + a; + }); + }; + Object.defineProperty(class_1.prototype, "x", { + // Accessor declaration paramter + set: function (v) { + defered(function () { + v; + }); + }, + enumerable: true, + configurable: true + }); + return class_1; +}()); +new E(); +var o = { + // Object literal method declaration paramter + method: function (a) { + defered(function () { + a; + }); + }, + // Accessor declaration paramter + set x(v) { + defered(function () { + v; + }); + }, + // in a property initalizer + p: defered(function () { + prop1; + }) +}; +o; +// in a for..in statment +var _loop_1 = function(i) { + defered(function () { + i; + }); +}; +for (var i in o) { + _loop_1(i); +} +// in a for..of statment +var _loop_2 = function(i) { + defered(function () { + i; + }); +}; +for (var _i = 0, _a = [1, 2, 3]; _i < _a.length; _i++) { + var i = _a[_i]; + _loop_2(i); +} +// in a for. statment +var _loop_3 = function(i) { + defered(function () { + i; + }); +}; +for (var i = 0; i < 10; i++) { + _loop_3(i); +} +// in a block +var condition = false; +if (condition) { + var c_1 = 0; + defered(function () { + c_1; + }); +} +// in try/catch/finally +try { + var a_1 = 0; + defered(function () { + a_1; + }); +} +catch (e) { + var c_2 = 1; + defered(function () { + c_2; + }); +} +finally { + var c_3 = 0; + defered(function () { + c_3; + }); +} +// in a namespace +var N; +(function (N) { + var x; + defered(function () { + x; + }); +})(N || (N = {})); +N; diff --git a/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.js b/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.js new file mode 100644 index 0000000000000..221d49a0fdf2d --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.js @@ -0,0 +1,45 @@ +//// [unusedLocalsAndParametersOverloadSignatures.ts] + +export function func(details: number, message: string, ...args: any[]): void; +export function func(details: number, message: string): any { + return details + message; +} + +export class C { + constructor(details: number, message: string, ...args: any[]); + constructor(details: number, message: string) { + details + message; + } + + method(details: number, message: string, ...args: any[]): void; + method(details: number, message: string): any { + return details + message; + } +} + + +export function genericFunc(details: number, message: T, ...args: any[]): void; +export function genericFunc(details: number, message: any): any { + return details + message; +} + +//// [unusedLocalsAndParametersOverloadSignatures.js] +"use strict"; +function func(details, message) { + return details + message; +} +exports.func = func; +var C = (function () { + function C(details, message) { + details + message; + } + C.prototype.method = function (details, message) { + return details + message; + }; + return C; +}()); +exports.C = C; +function genericFunc(details, message) { + return details + message; +} +exports.genericFunc = genericFunc; diff --git a/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.symbols b/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.symbols new file mode 100644 index 0000000000000..da3c47f2e42dd --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.symbols @@ -0,0 +1,70 @@ +=== tests/cases/compiler/unusedLocalsAndParametersOverloadSignatures.ts === + +export function func(details: number, message: string, ...args: any[]): void; +>func : Symbol(func, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 0, 0), Decl(unusedLocalsAndParametersOverloadSignatures.ts, 1, 77)) +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 1, 21)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 1, 37)) +>args : Symbol(args, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 1, 54)) + +export function func(details: number, message: string): any { +>func : Symbol(func, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 0, 0), Decl(unusedLocalsAndParametersOverloadSignatures.ts, 1, 77)) +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 2, 21)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 2, 37)) + + return details + message; +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 2, 21)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 2, 37)) +} + +export class C { +>C : Symbol(C, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 4, 1)) + + constructor(details: number, message: string, ...args: any[]); +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 7, 16)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 7, 32)) +>args : Symbol(args, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 7, 49)) + + constructor(details: number, message: string) { +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 8, 16)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 8, 32)) + + details + message; +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 8, 16)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 8, 32)) + } + + method(details: number, message: string, ...args: any[]): void; +>method : Symbol(C.method, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 10, 5), Decl(unusedLocalsAndParametersOverloadSignatures.ts, 12, 67)) +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 12, 11)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 12, 27)) +>args : Symbol(args, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 12, 44)) + + method(details: number, message: string): any { +>method : Symbol(C.method, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 10, 5), Decl(unusedLocalsAndParametersOverloadSignatures.ts, 12, 67)) +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 13, 11)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 13, 27)) + + return details + message; +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 13, 11)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 13, 27)) + } +} + + +export function genericFunc(details: number, message: T, ...args: any[]): void; +>genericFunc : Symbol(genericFunc, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 16, 1), Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 82)) +>T : Symbol(T, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 28)) +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 31)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 47)) +>T : Symbol(T, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 28)) +>args : Symbol(args, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 59)) + +export function genericFunc(details: number, message: any): any { +>genericFunc : Symbol(genericFunc, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 16, 1), Decl(unusedLocalsAndParametersOverloadSignatures.ts, 19, 82)) +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 20, 28)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 20, 44)) + + return details + message; +>details : Symbol(details, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 20, 28)) +>message : Symbol(message, Decl(unusedLocalsAndParametersOverloadSignatures.ts, 20, 44)) +} diff --git a/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.types b/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.types new file mode 100644 index 0000000000000..2a216c8acd212 --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersOverloadSignatures.types @@ -0,0 +1,74 @@ +=== tests/cases/compiler/unusedLocalsAndParametersOverloadSignatures.ts === + +export function func(details: number, message: string, ...args: any[]): void; +>func : (details: number, message: string, ...args: any[]) => void +>details : number +>message : string +>args : any[] + +export function func(details: number, message: string): any { +>func : (details: number, message: string, ...args: any[]) => void +>details : number +>message : string + + return details + message; +>details + message : string +>details : number +>message : string +} + +export class C { +>C : C + + constructor(details: number, message: string, ...args: any[]); +>details : number +>message : string +>args : any[] + + constructor(details: number, message: string) { +>details : number +>message : string + + details + message; +>details + message : string +>details : number +>message : string + } + + method(details: number, message: string, ...args: any[]): void; +>method : (details: number, message: string, ...args: any[]) => void +>details : number +>message : string +>args : any[] + + method(details: number, message: string): any { +>method : (details: number, message: string, ...args: any[]) => void +>details : number +>message : string + + return details + message; +>details + message : string +>details : number +>message : string + } +} + + +export function genericFunc(details: number, message: T, ...args: any[]): void; +>genericFunc : (details: number, message: T, ...args: any[]) => void +>T : T +>details : number +>message : T +>T : T +>args : any[] + +export function genericFunc(details: number, message: any): any { +>genericFunc : (details: number, message: T, ...args: any[]) => void +>details : number +>message : any + + return details + message; +>details + message : any +>details : number +>message : any +} diff --git a/tests/cases/compiler/unusedLocalsAndParameters.ts b/tests/cases/compiler/unusedLocalsAndParameters.ts new file mode 100644 index 0000000000000..1f4fc944ff4f1 --- /dev/null +++ b/tests/cases/compiler/unusedLocalsAndParameters.ts @@ -0,0 +1,86 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +export { }; + +// function declaration paramter +function f(a) { +} +f(0); + +// function expression paramter +var fexp = function (a) { +}; + +fexp(0); + +// arrow function paramter +var farrow = (a) => { +}; + +class C { + // Method declaration paramter + method(a) { + } + // Accessor declaration paramter + set x(v: number) { + } +} + +var E = class { + // Method declaration paramter + method(a) { + } + // Accessor declaration paramter + set x(v: number) { + } +} + +var o = { + // Object literal method declaration paramter + method(a) { + }, + // Accessor declaration paramter + set x(v: number) { + } +}; + +o; + +// in a for..in statment +for (let i in o) { +} + +// in a for..of statment +for (let i of [1, 2, 3]) { +} + +// in a for. statment +for (let i = 0, n; i < 10; i++) { +} + +// in a block + +const condition = false; +if (condition) { + const c = 0; +} + +// in try/catch/finally +try { + const a = 0; +} +catch (e) { + const c = 1; +} +finally { + const c = 0; +} + + +// in a namespace +namespace N { + var x; +} + + \ No newline at end of file diff --git a/tests/cases/compiler/unusedLocalsAndParametersDeferred.ts b/tests/cases/compiler/unusedLocalsAndParametersDeferred.ts new file mode 100644 index 0000000000000..75b98308199d5 --- /dev/null +++ b/tests/cases/compiler/unusedLocalsAndParametersDeferred.ts @@ -0,0 +1,162 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +export { }; + +function defered(a: () => T): T { + return a(); +} + +// function declaration paramter +function f(a) { + defered(() => { + a; + }); +} +f(0); + +// function expression paramter +var fexp = function (a) { + defered(() => { + a; + }); +}; +fexp(1); + +// arrow function paramter +var farrow = (a) => { + defered(() => { + a; + }); +}; +farrow(2); + +let prop1; + +class C { + // Method declaration paramter + method(a) { + defered(() => { + a; + }); + } + // Accessor declaration paramter + set x(v: number) { + defered(() => { + v; + }); + } + // in a property initalizer + p = defered(() => { + prop1; + }); +} + +new C(); + +let prop2; + +var E = class { + // Method declaration paramter + method(a) { + defered(() => { + a; + }); + } + // Accessor declaration paramter + set x(v: number) { + defered(() => { + v; + }); + } + // in a property initalizer + p = defered(() => { + prop2; + }); +} + +new E(); + + +var o = { + // Object literal method declaration paramter + method(a) { + defered(() => { + a; + }); + }, + // Accessor declaration paramter + set x(v: number) { + defered(() => { + v; + }); + }, + // in a property initalizer + p: defered(() => { + prop1; + }) +}; + +o; + +// in a for..in statment +for (let i in o) { + defered(() => { + i; + }); +} + +// in a for..of statment +for (let i of [1,2,3]) { + defered(() => { + i; + }); +} + +// in a for. statment +for (let i = 0; i < 10; i++) { + defered(() => { + i; + }); +} + +// in a block + +const condition = false; +if (condition) { + const c = 0; + defered(() => { + c; + }); +} + +// in try/catch/finally +try { + const a = 0; + defered(() => { + a; + }); +} +catch (e) { + const c = 1; + defered(() => { + c; + }); +} +finally { + const c = 0; + defered(() => { + c; + }); +} + + +// in a namespace +namespace N { + var x; + defered(() => { + x; + }); +} +N; + \ No newline at end of file diff --git a/tests/cases/compiler/unusedLocalsAndParametersOverloadSignatures.ts b/tests/cases/compiler/unusedLocalsAndParametersOverloadSignatures.ts new file mode 100644 index 0000000000000..32affb28be3d1 --- /dev/null +++ b/tests/cases/compiler/unusedLocalsAndParametersOverloadSignatures.ts @@ -0,0 +1,25 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +export function func(details: number, message: string, ...args: any[]): void; +export function func(details: number, message: string): any { + return details + message; +} + +export class C { + constructor(details: number, message: string, ...args: any[]); + constructor(details: number, message: string) { + details + message; + } + + method(details: number, message: string, ...args: any[]): void; + method(details: number, message: string): any { + return details + message; + } +} + + +export function genericFunc(details: number, message: T, ...args: any[]): void; +export function genericFunc(details: number, message: any): any { + return details + message; +} \ No newline at end of file From d4513c8affcd1e127b72e6f03d03a9ef073da031 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 14:07:42 -0700 Subject: [PATCH 09/18] Consolidate type reference marking in getTypeFromTypeReference --- src/compiler/checker.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d1c3a88c85ee4..26b94358f3693 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4961,6 +4961,10 @@ namespace ts { // type reference in checkTypeReferenceOrExpressionWithTypeArguments. links.resolvedSymbol = symbol; links.resolvedType = type; + + if (noUnusedIdentifiers && symbol !== unknownSymbol && !isInAmbientContext(node)) { + symbol.hasReference = true; + } } return links.resolvedType; } @@ -8321,16 +8325,6 @@ namespace ts { return container === declarationContainer; } - function updateReferencesForInterfaceHeritiageClauseTargets(node: InterfaceDeclaration): void { - const extendedTypeNode = getClassExtendsHeritageClauseElement(node); - if (extendedTypeNode) { - const t = getTypeFromTypeNode(extendedTypeNode); - if (t !== unknownType && t.symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { - t.symbol.hasReference = true; - } - } - } - function checkIdentifier(node: Identifier): Type { const symbol = getResolvedSymbol(node); if (symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { @@ -13620,9 +13614,6 @@ namespace ts { checkGrammarTypeArguments(node, node.typeArguments); const type = getTypeFromTypeReference(node); if (type !== unknownType) { - if (type.symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { - type.symbol.hasReference = true; - } if (node.typeArguments) { // Do type argument local checks only if referenced type is successfully resolved forEach(node.typeArguments, checkSourceElement); @@ -16099,7 +16090,6 @@ namespace ts { if (produceDiagnostics) { checkTypeForDuplicateIndexSignatures(node); - updateReferencesForInterfaceHeritiageClauseTargets(node); checkUnusedTypeParameters(node); } } From 97aa9879784c4b4720099fd12a902341ab0838aa Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 14:07:55 -0700 Subject: [PATCH 10/18] Handel type aliases --- src/compiler/checker.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26b94358f3693..b715310ad02d9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14546,15 +14546,15 @@ namespace ts { for (const key in node.locals) { if (hasProperty(node.locals, key)) { const local = node.locals[key]; - if (!local.hasReference && local.valueDeclaration) { - if (local.valueDeclaration.kind !== SyntaxKind.Parameter && compilerOptions.noUnusedLocals) { - error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name); - } - else if (local.valueDeclaration.kind === SyntaxKind.Parameter && compilerOptions.noUnusedParameters) { - if (!isParameterPropertyDeclaration(local.valueDeclaration)) { + if (!local.hasReference) { + if (local.valueDeclaration && local.valueDeclaration.kind === SyntaxKind.Parameter) { + if (compilerOptions.noUnusedParameters && !isParameterPropertyDeclaration(local.valueDeclaration)) { error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name); } } + else if (compilerOptions.noUnusedLocals) { + forEach(local.declarations, d => error(d.name || d, Diagnostics._0_is_declared_but_never_used, local.name)); + } } } } From f81a8e7382820ec94815ee2dbbb94818b052c1b0 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 14:08:20 -0700 Subject: [PATCH 11/18] Add tests --- .../unusedLocalsAndParametersTypeAliases.js | 35 +++++++++++ ...usedLocalsAndParametersTypeAliases.symbols | 59 +++++++++++++++++ ...unusedLocalsAndParametersTypeAliases.types | 63 +++++++++++++++++++ ...LocalsAndParametersTypeAliases2.errors.txt | 20 ++++++ .../unusedLocalsAndParametersTypeAliases2.js | 18 ++++++ .../unusedLocalsAndParametersTypeAliases.ts | 29 +++++++++ .../unusedLocalsAndParametersTypeAliases2.ts | 13 ++++ 7 files changed, 237 insertions(+) create mode 100644 tests/baselines/reference/unusedLocalsAndParametersTypeAliases.js create mode 100644 tests/baselines/reference/unusedLocalsAndParametersTypeAliases.symbols create mode 100644 tests/baselines/reference/unusedLocalsAndParametersTypeAliases.types create mode 100644 tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.errors.txt create mode 100644 tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.js create mode 100644 tests/cases/compiler/unusedLocalsAndParametersTypeAliases.ts create mode 100644 tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts diff --git a/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.js b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.js new file mode 100644 index 0000000000000..b854278a3e30d --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.js @@ -0,0 +1,35 @@ +//// [unusedLocalsAndParametersTypeAliases.ts] + +// used in a declaration +type handler1 = () => void; +export interface I1 { + getHandler: handler1; +} + +// exported +export type handler2 = () => void; + +// used in extends clause +type handler3 = () => void; +export interface I3 { + getHandler: T; +} + +// used in another type alias declaration +type handler4 = () => void; +type handler5 = handler4 | (()=>number); +var x: handler5; +x(); + +// used as type argument +type handler6 = () => void; +var y: Array; +y[0](); + + +//// [unusedLocalsAndParametersTypeAliases.js] +"use strict"; +var x; +x(); +var y; +y[0](); diff --git a/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.symbols b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.symbols new file mode 100644 index 0000000000000..9f9004d7a288e --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.symbols @@ -0,0 +1,59 @@ +=== tests/cases/compiler/unusedLocalsAndParametersTypeAliases.ts === + +// used in a declaration +type handler1 = () => void; +>handler1 : Symbol(handler1, Decl(unusedLocalsAndParametersTypeAliases.ts, 0, 0)) + +export interface I1 { +>I1 : Symbol(I1, Decl(unusedLocalsAndParametersTypeAliases.ts, 2, 27)) + + getHandler: handler1; +>getHandler : Symbol(I1.getHandler, Decl(unusedLocalsAndParametersTypeAliases.ts, 3, 21)) +>handler1 : Symbol(handler1, Decl(unusedLocalsAndParametersTypeAliases.ts, 0, 0)) +} + +// exported +export type handler2 = () => void; +>handler2 : Symbol(handler2, Decl(unusedLocalsAndParametersTypeAliases.ts, 5, 1)) + +// used in extends clause +type handler3 = () => void; +>handler3 : Symbol(handler3, Decl(unusedLocalsAndParametersTypeAliases.ts, 8, 34)) + +export interface I3 { +>I3 : Symbol(I3, Decl(unusedLocalsAndParametersTypeAliases.ts, 11, 27)) +>T : Symbol(T, Decl(unusedLocalsAndParametersTypeAliases.ts, 12, 20)) +>handler3 : Symbol(handler3, Decl(unusedLocalsAndParametersTypeAliases.ts, 8, 34)) + + getHandler: T; +>getHandler : Symbol(I3.getHandler, Decl(unusedLocalsAndParametersTypeAliases.ts, 12, 41)) +>T : Symbol(T, Decl(unusedLocalsAndParametersTypeAliases.ts, 12, 20)) +} + +// used in another type alias declaration +type handler4 = () => void; +>handler4 : Symbol(handler4, Decl(unusedLocalsAndParametersTypeAliases.ts, 14, 1)) + +type handler5 = handler4 | (()=>number); +>handler5 : Symbol(handler5, Decl(unusedLocalsAndParametersTypeAliases.ts, 17, 27)) +>handler4 : Symbol(handler4, Decl(unusedLocalsAndParametersTypeAliases.ts, 14, 1)) + +var x: handler5; +>x : Symbol(x, Decl(unusedLocalsAndParametersTypeAliases.ts, 19, 3)) +>handler5 : Symbol(handler5, Decl(unusedLocalsAndParametersTypeAliases.ts, 17, 27)) + +x(); +>x : Symbol(x, Decl(unusedLocalsAndParametersTypeAliases.ts, 19, 3)) + +// used as type argument +type handler6 = () => void; +>handler6 : Symbol(handler6, Decl(unusedLocalsAndParametersTypeAliases.ts, 20, 4)) + +var y: Array; +>y : Symbol(y, Decl(unusedLocalsAndParametersTypeAliases.ts, 24, 3)) +>Array : Symbol(Array, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>handler6 : Symbol(handler6, Decl(unusedLocalsAndParametersTypeAliases.ts, 20, 4)) + +y[0](); +>y : Symbol(y, Decl(unusedLocalsAndParametersTypeAliases.ts, 24, 3)) + diff --git a/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.types b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.types new file mode 100644 index 0000000000000..82c87deb7d07c --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/unusedLocalsAndParametersTypeAliases.ts === + +// used in a declaration +type handler1 = () => void; +>handler1 : () => void + +export interface I1 { +>I1 : I1 + + getHandler: handler1; +>getHandler : () => void +>handler1 : () => void +} + +// exported +export type handler2 = () => void; +>handler2 : () => void + +// used in extends clause +type handler3 = () => void; +>handler3 : () => void + +export interface I3 { +>I3 : I3 +>T : T +>handler3 : () => void + + getHandler: T; +>getHandler : T +>T : T +} + +// used in another type alias declaration +type handler4 = () => void; +>handler4 : () => void + +type handler5 = handler4 | (()=>number); +>handler5 : (() => void) | (() => number) +>handler4 : () => void + +var x: handler5; +>x : (() => void) | (() => number) +>handler5 : (() => void) | (() => number) + +x(); +>x() : void | number +>x : (() => void) | (() => number) + +// used as type argument +type handler6 = () => void; +>handler6 : () => void + +var y: Array; +>y : (() => void)[] +>Array : T[] +>handler6 : () => void + +y[0](); +>y[0]() : void +>y[0] : () => void +>y : (() => void)[] +>0 : number + diff --git a/tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.errors.txt b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.errors.txt new file mode 100644 index 0000000000000..d6abf6f2f3f73 --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.errors.txt @@ -0,0 +1,20 @@ +tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(3,6): error TS6133: 'handler1' is declared but never used. +tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(7,10): error TS6133: 'handler2' is declared but never used. + + +==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (2 errors) ==== + + // unused + type handler1 = () => void; + ~~~~~~~~ +!!! error TS6133: 'handler1' is declared but never used. + + + function foo() { + type handler2 = () => void; + ~~~~~~~~ +!!! error TS6133: 'handler2' is declared but never used. + foo(); + } + + export {} \ No newline at end of file diff --git a/tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.js b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.js new file mode 100644 index 0000000000000..7da916370ca72 --- /dev/null +++ b/tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.js @@ -0,0 +1,18 @@ +//// [unusedLocalsAndParametersTypeAliases2.ts] + +// unused +type handler1 = () => void; + + +function foo() { + type handler2 = () => void; + foo(); +} + +export {} + +//// [unusedLocalsAndParametersTypeAliases2.js] +"use strict"; +function foo() { + foo(); +} diff --git a/tests/cases/compiler/unusedLocalsAndParametersTypeAliases.ts b/tests/cases/compiler/unusedLocalsAndParametersTypeAliases.ts new file mode 100644 index 0000000000000..b94f88845bc2e --- /dev/null +++ b/tests/cases/compiler/unusedLocalsAndParametersTypeAliases.ts @@ -0,0 +1,29 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +// used in a declaration +type handler1 = () => void; +export interface I1 { + getHandler: handler1; +} + +// exported +export type handler2 = () => void; + +// used in extends clause +type handler3 = () => void; +export interface I3 { + getHandler: T; +} + +// used in another type alias declaration +type handler4 = () => void; +type handler5 = handler4 | (()=>number); +var x: handler5; +x(); + +// used as type argument +type handler6 = () => void; +var y: Array; +y[0](); + \ No newline at end of file diff --git a/tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts b/tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts new file mode 100644 index 0000000000000..23d23a5bc1892 --- /dev/null +++ b/tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts @@ -0,0 +1,13 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +// unused +type handler1 = () => void; + + +function foo() { + type handler2 = () => void; + foo(); +} + +export {} \ No newline at end of file From dc5cf3386182233e135d31b222b1683a963f9718 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 22:54:18 -0700 Subject: [PATCH 12/18] Do not report unused errors for module augmentations --- src/compiler/checker.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b715310ad02d9..d593683a2a9b6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14604,7 +14604,11 @@ namespace ts { if (hasProperty(node.locals, key)) { const local = node.locals[key]; if (!local.hasReference && !local.exportSymbol) { - forEach(local.declarations, d => error(d.name, Diagnostics._0_is_declared_but_never_used, local.name)); + for (const declaration of local.declarations) { + if (!isAmbientModule(declaration)) { + error(declaration.name, Diagnostics._0_is_declared_but_never_used, local.name); + } + } } } } @@ -16487,7 +16491,9 @@ namespace ts { if (node.body) { checkSourceElement(node.body); - checkUnusedIdentifiersDeferred(node); + if (!isGlobalScopeAugmentation(node)) { + checkUnusedIdentifiersDeferred(node); + } } } From f751901eee100fea85bf17917700e4d465e50ede Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 23:46:41 -0700 Subject: [PATCH 13/18] Consolidate refernce marking in resolveName to allow marking aliases correctelly --- src/compiler/checker.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d593683a2a9b6..40ff595b0ad35 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -899,6 +899,10 @@ namespace ts { error(errorLocation, Diagnostics.Identifier_0_must_be_imported_from_a_module, name); } } + + if (result && noUnusedIdentifiers && !isInAmbientContext(location)) { + result.hasReference = true; + } } return result; } @@ -4961,10 +4965,6 @@ namespace ts { // type reference in checkTypeReferenceOrExpressionWithTypeArguments. links.resolvedSymbol = symbol; links.resolvedType = type; - - if (noUnusedIdentifiers && symbol !== unknownSymbol && !isInAmbientContext(node)) { - symbol.hasReference = true; - } } return links.resolvedType; } @@ -8327,9 +8327,6 @@ namespace ts { function checkIdentifier(node: Identifier): Type { const symbol = getResolvedSymbol(node); - if (symbol && noUnusedIdentifiers && !isInAmbientContext(node)) { - symbol.hasReference = true; - } // As noted in ECMAScript 6 language spec, arrow functions never have an arguments objects. // Although in down-level emit of arrow function, we emit it using function expression which means that @@ -16674,9 +16671,6 @@ namespace ts { if (target.flags & SymbolFlags.Type) { checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0); } - if (noUnusedIdentifiers && !isInAmbientContext(node)) { - target.hasReference = true; - } } } else { From 8fb3b25c1e3874334c668a9b82165316a3ad223b Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 29 Jun 2016 23:46:50 -0700 Subject: [PATCH 14/18] add tests --- tests/baselines/reference/unusedImports11.js | 41 ++++++++++++++++ .../reference/unusedImports11.symbols | 43 +++++++++++++++++ .../baselines/reference/unusedImports11.types | 48 +++++++++++++++++++ .../reference/unusedImports12.errors.txt | 29 +++++++++++ tests/baselines/reference/unusedImports12.js | 27 +++++++++++ tests/cases/compiler/unusedImports11.ts | 19 ++++++++ tests/cases/compiler/unusedImports12.ts | 13 +++++ 7 files changed, 220 insertions(+) create mode 100644 tests/baselines/reference/unusedImports11.js create mode 100644 tests/baselines/reference/unusedImports11.symbols create mode 100644 tests/baselines/reference/unusedImports11.types create mode 100644 tests/baselines/reference/unusedImports12.errors.txt create mode 100644 tests/baselines/reference/unusedImports12.js create mode 100644 tests/cases/compiler/unusedImports11.ts create mode 100644 tests/cases/compiler/unusedImports12.ts diff --git a/tests/baselines/reference/unusedImports11.js b/tests/baselines/reference/unusedImports11.js new file mode 100644 index 0000000000000..86561e1021e58 --- /dev/null +++ b/tests/baselines/reference/unusedImports11.js @@ -0,0 +1,41 @@ +//// [tests/cases/compiler/unusedImports11.ts] //// + +//// [b.ts] + +export class Member {} +export default Member; + + +//// [a.ts] +import { Member } from './b'; +import d, { Member as M } from './b'; +import * as ns from './b'; +import r = require("./b"); + +new Member(); +new d(); +new M(); +new ns.Member(); +new r.Member(); + +//// [b.js] +"use strict"; +var Member = (function () { + function Member() { + } + return Member; +}()); +exports.Member = Member; +exports.__esModule = true; +exports["default"] = Member; +//// [a.js] +"use strict"; +var b_1 = require('./b'); +var b_2 = require('./b'); +var ns = require('./b'); +var r = require("./b"); +new b_1.Member(); +new b_2["default"](); +new b_2.Member(); +new ns.Member(); +new r.Member(); diff --git a/tests/baselines/reference/unusedImports11.symbols b/tests/baselines/reference/unusedImports11.symbols new file mode 100644 index 0000000000000..995b4a40c2a85 --- /dev/null +++ b/tests/baselines/reference/unusedImports11.symbols @@ -0,0 +1,43 @@ +=== tests/cases/compiler/a.ts === +import { Member } from './b'; +>Member : Symbol(Member, Decl(a.ts, 0, 8)) + +import d, { Member as M } from './b'; +>d : Symbol(d, Decl(a.ts, 1, 6)) +>Member : Symbol(M, Decl(a.ts, 1, 11)) +>M : Symbol(M, Decl(a.ts, 1, 11)) + +import * as ns from './b'; +>ns : Symbol(ns, Decl(a.ts, 2, 6)) + +import r = require("./b"); +>r : Symbol(r, Decl(a.ts, 2, 26)) + +new Member(); +>Member : Symbol(Member, Decl(a.ts, 0, 8)) + +new d(); +>d : Symbol(d, Decl(a.ts, 1, 6)) + +new M(); +>M : Symbol(M, Decl(a.ts, 1, 11)) + +new ns.Member(); +>ns.Member : Symbol(Member, Decl(b.ts, 0, 0)) +>ns : Symbol(ns, Decl(a.ts, 2, 6)) +>Member : Symbol(Member, Decl(b.ts, 0, 0)) + +new r.Member(); +>r.Member : Symbol(Member, Decl(b.ts, 0, 0)) +>r : Symbol(r, Decl(a.ts, 2, 26)) +>Member : Symbol(Member, Decl(b.ts, 0, 0)) + +=== tests/cases/compiler/b.ts === + +export class Member {} +>Member : Symbol(Member, Decl(b.ts, 0, 0)) + +export default Member; +>Member : Symbol(Member, Decl(b.ts, 0, 0)) + + diff --git a/tests/baselines/reference/unusedImports11.types b/tests/baselines/reference/unusedImports11.types new file mode 100644 index 0000000000000..1d71a0226b6d5 --- /dev/null +++ b/tests/baselines/reference/unusedImports11.types @@ -0,0 +1,48 @@ +=== tests/cases/compiler/a.ts === +import { Member } from './b'; +>Member : typeof Member + +import d, { Member as M } from './b'; +>d : typeof Member +>Member : typeof Member +>M : typeof Member + +import * as ns from './b'; +>ns : typeof ns + +import r = require("./b"); +>r : typeof ns + +new Member(); +>new Member() : Member +>Member : typeof Member + +new d(); +>new d() : Member +>d : typeof Member + +new M(); +>new M() : Member +>M : typeof Member + +new ns.Member(); +>new ns.Member() : Member +>ns.Member : typeof Member +>ns : typeof ns +>Member : typeof Member + +new r.Member(); +>new r.Member() : Member +>r.Member : typeof Member +>r : typeof ns +>Member : typeof Member + +=== tests/cases/compiler/b.ts === + +export class Member {} +>Member : Member + +export default Member; +>Member : Member + + diff --git a/tests/baselines/reference/unusedImports12.errors.txt b/tests/baselines/reference/unusedImports12.errors.txt new file mode 100644 index 0000000000000..89b0687317b6b --- /dev/null +++ b/tests/baselines/reference/unusedImports12.errors.txt @@ -0,0 +1,29 @@ +tests/cases/compiler/a.ts(1,10): error TS6133: 'Member' is declared but never used. +tests/cases/compiler/a.ts(2,8): error TS6133: 'd' is declared but never used. +tests/cases/compiler/a.ts(2,23): error TS6133: 'M' is declared but never used. +tests/cases/compiler/a.ts(3,13): error TS6133: 'ns' is declared but never used. +tests/cases/compiler/a.ts(4,8): error TS6133: 'r' is declared but never used. + + +==== tests/cases/compiler/a.ts (5 errors) ==== + import { Member } from './b'; + ~~~~~~ +!!! error TS6133: 'Member' is declared but never used. + import d, { Member as M } from './b'; + ~ +!!! error TS6133: 'd' is declared but never used. + ~ +!!! error TS6133: 'M' is declared but never used. + import * as ns from './b'; + ~~ +!!! error TS6133: 'ns' is declared but never used. + import r = require("./b"); + ~ +!!! error TS6133: 'r' is declared but never used. + +==== tests/cases/compiler/b.ts (0 errors) ==== + + export class Member {} + export default Member; + + \ No newline at end of file diff --git a/tests/baselines/reference/unusedImports12.js b/tests/baselines/reference/unusedImports12.js new file mode 100644 index 0000000000000..ece9b105bc90f --- /dev/null +++ b/tests/baselines/reference/unusedImports12.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/unusedImports12.ts] //// + +//// [b.ts] + +export class Member {} +export default Member; + + +//// [a.ts] +import { Member } from './b'; +import d, { Member as M } from './b'; +import * as ns from './b'; +import r = require("./b"); + + +//// [b.js] +"use strict"; +var Member = (function () { + function Member() { + } + return Member; +}()); +exports.Member = Member; +exports.__esModule = true; +exports["default"] = Member; +//// [a.js] +"use strict"; diff --git a/tests/cases/compiler/unusedImports11.ts b/tests/cases/compiler/unusedImports11.ts new file mode 100644 index 0000000000000..4f2fed649d152 --- /dev/null +++ b/tests/cases/compiler/unusedImports11.ts @@ -0,0 +1,19 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +// @filename: b.ts +export class Member {} +export default Member; + + +// @filename: a.ts +import { Member } from './b'; +import d, { Member as M } from './b'; +import * as ns from './b'; +import r = require("./b"); + +new Member(); +new d(); +new M(); +new ns.Member(); +new r.Member(); \ No newline at end of file diff --git a/tests/cases/compiler/unusedImports12.ts b/tests/cases/compiler/unusedImports12.ts new file mode 100644 index 0000000000000..14206284b6439 --- /dev/null +++ b/tests/cases/compiler/unusedImports12.ts @@ -0,0 +1,13 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +// @filename: b.ts +export class Member {} +export default Member; + + +// @filename: a.ts +import { Member } from './b'; +import d, { Member as M } from './b'; +import * as ns from './b'; +import r = require("./b"); From 3d9c9206e437542ffce326b7d9820ec98613fead Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 30 Jun 2016 00:03:54 -0700 Subject: [PATCH 15/18] Code review comments --- src/compiler/checker.ts | 60 ++++++++++++++++++++--------------------- src/compiler/types.ts | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 40ff595b0ad35..f42ca9ffe34d0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -901,7 +901,7 @@ namespace ts { } if (result && noUnusedIdentifiers && !isInAmbientContext(location)) { - result.hasReference = true; + result.isReferenced = true; } } return result; @@ -10242,7 +10242,7 @@ namespace ts { } if (noUnusedIdentifiers && !isInAmbientContext(node)) { - prop.hasReference = true; + prop.isReferenced = true; } getNodeLinks(node).resolvedSymbol = prop; @@ -12187,7 +12187,7 @@ namespace ts { } } } - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } } @@ -13415,7 +13415,7 @@ namespace ts { checkGrammarConstructorTypeParameters(node) || checkGrammarConstructorTypeAnnotation(node); checkSourceElement(node.body); - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); const symbol = getSymbolOfNode(node); const firstDeclaration = getDeclarationOfKind(symbol, node.kind); @@ -13561,7 +13561,7 @@ namespace ts { } if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } else { checkNodeDeferred(node); @@ -13578,7 +13578,7 @@ namespace ts { function checkAccessorDeferred(node: AccessorDeclaration) { checkSourceElement(node.body); - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } function checkMissingDeclaration(node: Node) { @@ -14482,26 +14482,26 @@ namespace ts { } } - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } - function checkUnusedIdentifiersDeferred(node: Node) { + function registerForUnusedIdentifiersCheck(node: Node) { if (deferredUnusedIdentifierNodes) { deferredUnusedIdentifierNodes.push(node); } } - function checkUnusedIdentifiersDeferredNodes() { + function checkUnusedIdentifiers() { if (deferredUnusedIdentifierNodes) { for (const node of deferredUnusedIdentifierNodes) { switch (node.kind) { case SyntaxKind.SourceFile: case SyntaxKind.ModuleDeclaration: - checkUnusedModuleLocals(node); + checkUnusedModuleMembers(node); break; case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: - checkUnusedClassLocals(node); + checkUnusedClassMembers(node); checkUnusedTypeParameters(node); break; case SyntaxKind.InterfaceDeclaration: @@ -14511,7 +14511,7 @@ namespace ts { case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: - checkUnusedIdentifiers(node); + checkUnusedLocalsAndParameters(node); break; case SyntaxKind.Constructor: case SyntaxKind.FunctionExpression: @@ -14521,7 +14521,7 @@ namespace ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: if ((node).body) { - checkUnusedIdentifiers(node); + checkUnusedLocalsAndParameters(node); } checkUnusedTypeParameters(node); break; @@ -14538,12 +14538,12 @@ namespace ts { } } - function checkUnusedIdentifiers(node: FunctionLikeDeclaration | ForStatement | Block): void { + function checkUnusedLocalsAndParameters(node: FunctionLikeDeclaration | ForStatement | Block): void { if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) { for (const key in node.locals) { if (hasProperty(node.locals, key)) { const local = node.locals[key]; - if (!local.hasReference) { + if (!local.isReferenced) { if (local.valueDeclaration && local.valueDeclaration.kind === SyntaxKind.Parameter) { if (compilerOptions.noUnusedParameters && !isParameterPropertyDeclaration(local.valueDeclaration)) { error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name); @@ -14558,18 +14558,18 @@ namespace ts { } } - function checkUnusedClassLocals(node: ClassDeclaration | ClassExpression): void { + function checkUnusedClassMembers(node: ClassDeclaration | ClassExpression): void { if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { if (node.members) { for (const member of node.members) { if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.PropertyDeclaration) { - if (isPrivateNode(member) && !member.symbol.hasReference) { + if (isPrivateNode(member) && !member.symbol.isReferenced) { error(member.name, Diagnostics._0_is_declared_but_never_used, member.symbol.name); } } else if (member.kind === SyntaxKind.Constructor) { for (const parameter of (member).parameters) { - if (isPrivateNode(parameter) && !parameter.symbol.hasReference) { + if (isPrivateNode(parameter) && !parameter.symbol.isReferenced) { error(parameter.name, Diagnostics._0_is_declared_but_never_used, parameter.symbol.name); } } @@ -14583,7 +14583,7 @@ namespace ts { if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { if (node.typeParameters) { for (const typeParameter of node.typeParameters) { - if (!typeParameter.symbol.hasReference) { + if (!typeParameter.symbol.isReferenced) { error(typeParameter.name, Diagnostics._0_is_declared_but_never_used, typeParameter.symbol.name); } } @@ -14595,12 +14595,12 @@ namespace ts { return (node.flags & NodeFlags.Private) !== 0; } - function checkUnusedModuleLocals(node: ModuleDeclaration | SourceFile): void { + function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void { if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { for (const key in node.locals) { if (hasProperty(node.locals, key)) { const local = node.locals[key]; - if (!local.hasReference && !local.exportSymbol) { + if (!local.isReferenced && !local.exportSymbol) { for (const declaration of local.declarations) { if (!isAmbientModule(declaration)) { error(declaration.name, Diagnostics._0_is_declared_but_never_used, local.name); @@ -14619,7 +14619,7 @@ namespace ts { } forEach(node.statements, checkSourceElement); if (node.locals) { - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } } @@ -15085,7 +15085,7 @@ namespace ts { if (node.condition) checkExpression(node.condition); if (node.incrementor) checkExpression(node.incrementor); checkSourceElement(node.statement); - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } function checkForOfStatement(node: ForOfStatement): void { @@ -15127,7 +15127,7 @@ namespace ts { checkSourceElement(node.statement); if (node.locals) { - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } } @@ -15177,7 +15177,7 @@ namespace ts { checkSourceElement(node.statement); if (node.locals) { - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } } @@ -15771,7 +15771,7 @@ namespace ts { function checkClassExpressionDeferred(node: ClassExpression) { forEach(node.members, checkSourceElement); - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } function checkClassDeclaration(node: ClassDeclaration) { @@ -15781,7 +15781,7 @@ namespace ts { checkClassLikeDeclaration(node); forEach(node.members, checkSourceElement); - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } function checkClassLikeDeclaration(node: ClassLikeDeclaration) { @@ -16489,7 +16489,7 @@ namespace ts { if (node.body) { checkSourceElement(node.body); if (!isGlobalScopeAugmentation(node)) { - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } } } @@ -17019,11 +17019,11 @@ namespace ts { checkDeferredNodes(); if (isExternalModule(node)) { - checkUnusedIdentifiersDeferred(node); + registerForUnusedIdentifiersCheck(node); } if (!node.isDeclarationFile) { - checkUnusedIdentifiersDeferredNodes(); + checkUnusedIdentifiers(); } deferredNodes = undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 56029fd316cdb..a3d7fd4823d9c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2128,7 +2128,7 @@ namespace ts { /* @internal */ parent?: Symbol; // Parent symbol /* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol /* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums - /* @internal */ hasReference?: boolean; // True if the symbol is referenced elsewhere + /* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere } /* @internal */ From b40512d8a21f5dd66df4b4c5a4940b68509effb9 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 30 Jun 2016 01:00:53 -0700 Subject: [PATCH 16/18] Only mark symbols found in a local symbol table --- src/compiler/checker.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f42ca9ffe34d0..0bedc9f404a5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -51,7 +51,7 @@ namespace ts { const compilerOptions = host.getCompilerOptions(); const languageVersion = compilerOptions.target || ScriptTarget.ES3; const modulekind = getEmitModuleKind(compilerOptions); - const noUnusedIdentifiers = compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters; + const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters; const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System; const strictNullChecks = compilerOptions.strictNullChecks; @@ -849,6 +849,10 @@ namespace ts { location = location.parent; } + if (result && nameNotFoundMessage && noUnusedIdentifiers) { + result.isReferenced = true; + } + if (!result) { result = getSymbol(globals, name, meaning); } @@ -899,10 +903,6 @@ namespace ts { error(errorLocation, Diagnostics.Identifier_0_must_be_imported_from_a_module, name); } } - - if (result && noUnusedIdentifiers && !isInAmbientContext(location)) { - result.isReferenced = true; - } } return result; } From 1fa69caf13ddb9474bb4231d02268701ddbbf67f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 30 Jun 2016 10:38:59 -0700 Subject: [PATCH 17/18] handel private properties correctelly --- src/compiler/checker.ts | 9 +- src/compiler/types.ts | 2 + .../reference/unusedPrivateMembers.js | 114 +++++++++++++++++ .../reference/unusedPrivateMembers.symbols | 113 ++++++++++++++++ .../reference/unusedPrivateMembers.types | 121 ++++++++++++++++++ tests/cases/compiler/unusedPrivateMembers.ts | 51 ++++++++ 6 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/unusedPrivateMembers.js create mode 100644 tests/baselines/reference/unusedPrivateMembers.symbols create mode 100644 tests/baselines/reference/unusedPrivateMembers.types create mode 100644 tests/cases/compiler/unusedPrivateMembers.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0bedc9f404a5d..33ff04697f9c5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10241,8 +10241,13 @@ namespace ts { return unknownType; } - if (noUnusedIdentifiers && !isInAmbientContext(node)) { - prop.isReferenced = true; + if (noUnusedIdentifiers && (prop.flags & SymbolFlags.ClassMember)) { + if (prop.flags & SymbolFlags.Instantiated) { + getSymbolLinks(prop).target.isReferenced = true; + } + else { + prop.isReferenced = true; + } } getNodeLinks(node).resolvedSymbol = prop; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index a3d7fd4823d9c..7d7e92f27c3cd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2107,6 +2107,8 @@ namespace ts { PropertyOrAccessor = Property | Accessor, Export = ExportNamespace | ExportType | ExportValue, + ClassMember = Method | Accessor | Property, + /* @internal */ // The set of things we consider semantically classifiable. Used to speed up the LS during // classification. diff --git a/tests/baselines/reference/unusedPrivateMembers.js b/tests/baselines/reference/unusedPrivateMembers.js new file mode 100644 index 0000000000000..cdb540349c323 --- /dev/null +++ b/tests/baselines/reference/unusedPrivateMembers.js @@ -0,0 +1,114 @@ +//// [unusedPrivateMembers.ts] + +class Test1 { + private initializeInternal() { + } + + public test() { + var x = new Test1(); + x.initializeInternal(); + } +} + +class Test2 { + private p = 0; + public test() { + var x = new Test2(); + x.p; + } +} + +class Test3 { + private get x () { + return 0; + } + + public test() { + var x = new Test3(); + x.x; + } +} + +class Test4 { + private set x(v) { + v; + } + + public test() { + var x = new Test4(); + x.x; + } +} + +class Test5 { + private p: T; + public test() { + var x = new Test5(); + x.p; + } +} + + +//// [unusedPrivateMembers.js] +var Test1 = (function () { + function Test1() { + } + Test1.prototype.initializeInternal = function () { + }; + Test1.prototype.test = function () { + var x = new Test1(); + x.initializeInternal(); + }; + return Test1; +}()); +var Test2 = (function () { + function Test2() { + this.p = 0; + } + Test2.prototype.test = function () { + var x = new Test2(); + x.p; + }; + return Test2; +}()); +var Test3 = (function () { + function Test3() { + } + Object.defineProperty(Test3.prototype, "x", { + get: function () { + return 0; + }, + enumerable: true, + configurable: true + }); + Test3.prototype.test = function () { + var x = new Test3(); + x.x; + }; + return Test3; +}()); +var Test4 = (function () { + function Test4() { + } + Object.defineProperty(Test4.prototype, "x", { + set: function (v) { + v; + }, + enumerable: true, + configurable: true + }); + Test4.prototype.test = function () { + var x = new Test4(); + x.x; + }; + return Test4; +}()); +var Test5 = (function () { + function Test5() { + } + Test5.prototype.test = function () { + var x = new Test5(); + x.p; + }; + return Test5; +}()); diff --git a/tests/baselines/reference/unusedPrivateMembers.symbols b/tests/baselines/reference/unusedPrivateMembers.symbols new file mode 100644 index 0000000000000..0d4426a594ae7 --- /dev/null +++ b/tests/baselines/reference/unusedPrivateMembers.symbols @@ -0,0 +1,113 @@ +=== tests/cases/compiler/unusedPrivateMembers.ts === + +class Test1 { +>Test1 : Symbol(Test1, Decl(unusedPrivateMembers.ts, 0, 0)) + + private initializeInternal() { +>initializeInternal : Symbol(Test1.initializeInternal, Decl(unusedPrivateMembers.ts, 1, 13)) + } + + public test() { +>test : Symbol(Test1.test, Decl(unusedPrivateMembers.ts, 3, 5)) + + var x = new Test1(); +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 6, 11)) +>Test1 : Symbol(Test1, Decl(unusedPrivateMembers.ts, 0, 0)) + + x.initializeInternal(); +>x.initializeInternal : Symbol(Test1.initializeInternal, Decl(unusedPrivateMembers.ts, 1, 13)) +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 6, 11)) +>initializeInternal : Symbol(Test1.initializeInternal, Decl(unusedPrivateMembers.ts, 1, 13)) + } +} + +class Test2 { +>Test2 : Symbol(Test2, Decl(unusedPrivateMembers.ts, 9, 1)) + + private p = 0; +>p : Symbol(Test2.p, Decl(unusedPrivateMembers.ts, 11, 13)) + + public test() { +>test : Symbol(Test2.test, Decl(unusedPrivateMembers.ts, 12, 18)) + + var x = new Test2(); +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 14, 11)) +>Test2 : Symbol(Test2, Decl(unusedPrivateMembers.ts, 9, 1)) + + x.p; +>x.p : Symbol(Test2.p, Decl(unusedPrivateMembers.ts, 11, 13)) +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 14, 11)) +>p : Symbol(Test2.p, Decl(unusedPrivateMembers.ts, 11, 13)) + } +} + +class Test3 { +>Test3 : Symbol(Test3, Decl(unusedPrivateMembers.ts, 17, 1)) + + private get x () { +>x : Symbol(Test3.x, Decl(unusedPrivateMembers.ts, 19, 13)) + + return 0; + } + + public test() { +>test : Symbol(Test3.test, Decl(unusedPrivateMembers.ts, 22, 5)) + + var x = new Test3(); +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 25, 11)) +>Test3 : Symbol(Test3, Decl(unusedPrivateMembers.ts, 17, 1)) + + x.x; +>x.x : Symbol(Test3.x, Decl(unusedPrivateMembers.ts, 19, 13)) +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 25, 11)) +>x : Symbol(Test3.x, Decl(unusedPrivateMembers.ts, 19, 13)) + } +} + +class Test4 { +>Test4 : Symbol(Test4, Decl(unusedPrivateMembers.ts, 28, 1)) + + private set x(v) { +>x : Symbol(Test4.x, Decl(unusedPrivateMembers.ts, 30, 13)) +>v : Symbol(v, Decl(unusedPrivateMembers.ts, 31, 18)) + + v; +>v : Symbol(v, Decl(unusedPrivateMembers.ts, 31, 18)) + } + + public test() { +>test : Symbol(Test4.test, Decl(unusedPrivateMembers.ts, 33, 5)) + + var x = new Test4(); +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 36, 11)) +>Test4 : Symbol(Test4, Decl(unusedPrivateMembers.ts, 28, 1)) + + x.x; +>x.x : Symbol(Test4.x, Decl(unusedPrivateMembers.ts, 30, 13)) +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 36, 11)) +>x : Symbol(Test4.x, Decl(unusedPrivateMembers.ts, 30, 13)) + } +} + +class Test5 { +>Test5 : Symbol(Test5, Decl(unusedPrivateMembers.ts, 39, 1)) +>T : Symbol(T, Decl(unusedPrivateMembers.ts, 41, 12)) + + private p: T; +>p : Symbol(Test5.p, Decl(unusedPrivateMembers.ts, 41, 16)) +>T : Symbol(T, Decl(unusedPrivateMembers.ts, 41, 12)) + + public test() { +>test : Symbol(Test5.test, Decl(unusedPrivateMembers.ts, 42, 17)) + + var x = new Test5(); +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 44, 11)) +>Test5 : Symbol(Test5, Decl(unusedPrivateMembers.ts, 39, 1)) + + x.p; +>x.p : Symbol(Test5.p, Decl(unusedPrivateMembers.ts, 41, 16)) +>x : Symbol(x, Decl(unusedPrivateMembers.ts, 44, 11)) +>p : Symbol(Test5.p, Decl(unusedPrivateMembers.ts, 41, 16)) + } +} + diff --git a/tests/baselines/reference/unusedPrivateMembers.types b/tests/baselines/reference/unusedPrivateMembers.types new file mode 100644 index 0000000000000..1d303068f24ba --- /dev/null +++ b/tests/baselines/reference/unusedPrivateMembers.types @@ -0,0 +1,121 @@ +=== tests/cases/compiler/unusedPrivateMembers.ts === + +class Test1 { +>Test1 : Test1 + + private initializeInternal() { +>initializeInternal : () => void + } + + public test() { +>test : () => void + + var x = new Test1(); +>x : Test1 +>new Test1() : Test1 +>Test1 : typeof Test1 + + x.initializeInternal(); +>x.initializeInternal() : void +>x.initializeInternal : () => void +>x : Test1 +>initializeInternal : () => void + } +} + +class Test2 { +>Test2 : Test2 + + private p = 0; +>p : number +>0 : number + + public test() { +>test : () => void + + var x = new Test2(); +>x : Test2 +>new Test2() : Test2 +>Test2 : typeof Test2 + + x.p; +>x.p : number +>x : Test2 +>p : number + } +} + +class Test3 { +>Test3 : Test3 + + private get x () { +>x : number + + return 0; +>0 : number + } + + public test() { +>test : () => void + + var x = new Test3(); +>x : Test3 +>new Test3() : Test3 +>Test3 : typeof Test3 + + x.x; +>x.x : number +>x : Test3 +>x : number + } +} + +class Test4 { +>Test4 : Test4 + + private set x(v) { +>x : any +>v : any + + v; +>v : any + } + + public test() { +>test : () => void + + var x = new Test4(); +>x : Test4 +>new Test4() : Test4 +>Test4 : typeof Test4 + + x.x; +>x.x : any +>x : Test4 +>x : any + } +} + +class Test5 { +>Test5 : Test5 +>T : T + + private p: T; +>p : T +>T : T + + public test() { +>test : () => void + + var x = new Test5(); +>x : Test5 +>new Test5() : Test5 +>Test5 : typeof Test5 + + x.p; +>x.p : number +>x : Test5 +>p : number + } +} + diff --git a/tests/cases/compiler/unusedPrivateMembers.ts b/tests/cases/compiler/unusedPrivateMembers.ts new file mode 100644 index 0000000000000..ab4e5ba9bca33 --- /dev/null +++ b/tests/cases/compiler/unusedPrivateMembers.ts @@ -0,0 +1,51 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true +//@target:ES5 + +class Test1 { + private initializeInternal() { + } + + public test() { + var x = new Test1(); + x.initializeInternal(); + } +} + +class Test2 { + private p = 0; + public test() { + var x = new Test2(); + x.p; + } +} + +class Test3 { + private get x () { + return 0; + } + + public test() { + var x = new Test3(); + x.x; + } +} + +class Test4 { + private set x(v) { + v; + } + + public test() { + var x = new Test4(); + x.x; + } +} + +class Test5 { + private p: T; + public test() { + var x = new Test5(); + x.p; + } +} From 54b4bef8c8eea59c56c0d2a1b5ffa19cd03a3316 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 30 Jun 2016 15:18:17 -0700 Subject: [PATCH 18/18] Handel Swtich statements check for locals on for statments only mark private properties --- src/compiler/checker.ts | 25 +++++++----- .../reference/unusedSwitchStatment.errors.txt | 31 +++++++++++++++ .../reference/unusedSwitchStatment.js | 38 +++++++++++++++++++ tests/cases/compiler/unusedSwitchStatment.ts | 21 ++++++++++ 4 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 tests/baselines/reference/unusedSwitchStatment.errors.txt create mode 100644 tests/baselines/reference/unusedSwitchStatment.js create mode 100644 tests/cases/compiler/unusedSwitchStatment.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 33ff04697f9c5..be94a7ce4e39c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10241,9 +10241,12 @@ namespace ts { return unknownType; } - if (noUnusedIdentifiers && (prop.flags & SymbolFlags.ClassMember)) { + if (noUnusedIdentifiers && + (prop.flags & SymbolFlags.ClassMember) && + prop.valueDeclaration && (prop.valueDeclaration.flags & NodeFlags.Private)) { if (prop.flags & SymbolFlags.Instantiated) { getSymbolLinks(prop).target.isReferenced = true; + } else { prop.isReferenced = true; @@ -14513,10 +14516,11 @@ namespace ts { checkUnusedTypeParameters(node); break; case SyntaxKind.Block: + case SyntaxKind.CaseBlock: case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: case SyntaxKind.ForOfStatement: - checkUnusedLocalsAndParameters(node); + checkUnusedLocalsAndParameters(node); break; case SyntaxKind.Constructor: case SyntaxKind.FunctionExpression: @@ -14543,7 +14547,7 @@ namespace ts { } } - function checkUnusedLocalsAndParameters(node: FunctionLikeDeclaration | ForStatement | Block): void { + function checkUnusedLocalsAndParameters(node: Node): void { if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) { for (const key in node.locals) { if (hasProperty(node.locals, key)) { @@ -14568,13 +14572,13 @@ namespace ts { if (node.members) { for (const member of node.members) { if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.PropertyDeclaration) { - if (isPrivateNode(member) && !member.symbol.isReferenced) { + if (!member.symbol.isReferenced && member.flags & NodeFlags.Private) { error(member.name, Diagnostics._0_is_declared_but_never_used, member.symbol.name); } } else if (member.kind === SyntaxKind.Constructor) { for (const parameter of (member).parameters) { - if (isPrivateNode(parameter) && !parameter.symbol.isReferenced) { + if (!parameter.symbol.isReferenced && parameter.flags & NodeFlags.Private) { error(parameter.name, Diagnostics._0_is_declared_but_never_used, parameter.symbol.name); } } @@ -14596,10 +14600,6 @@ namespace ts { } } - function isPrivateNode(node: Node): boolean { - return (node.flags & NodeFlags.Private) !== 0; - } - function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void { if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) { for (const key in node.locals) { @@ -15090,7 +15090,9 @@ namespace ts { if (node.condition) checkExpression(node.condition); if (node.incrementor) checkExpression(node.incrementor); checkSourceElement(node.statement); - registerForUnusedIdentifiersCheck(node); + if (node.locals) { + registerForUnusedIdentifiersCheck(node); + } } function checkForOfStatement(node: ForOfStatement): void { @@ -15556,6 +15558,9 @@ namespace ts { } forEach(clause.statements, checkSourceElement); }); + if (node.caseBlock.locals) { + registerForUnusedIdentifiersCheck(node.caseBlock); + } } function checkLabeledStatement(node: LabeledStatement) { diff --git a/tests/baselines/reference/unusedSwitchStatment.errors.txt b/tests/baselines/reference/unusedSwitchStatment.errors.txt new file mode 100644 index 0000000000000..58359eed90d27 --- /dev/null +++ b/tests/baselines/reference/unusedSwitchStatment.errors.txt @@ -0,0 +1,31 @@ +tests/cases/compiler/unusedSwitchStatment.ts(4,13): error TS6133: 'x' is declared but never used. +tests/cases/compiler/unusedSwitchStatment.ts(7,15): error TS6133: 'c' is declared but never used. +tests/cases/compiler/unusedSwitchStatment.ts(10,13): error TS6133: 'z' is declared but never used. + + +==== tests/cases/compiler/unusedSwitchStatment.ts (3 errors) ==== + + switch (1) { + case 0: + let x; + ~ +!!! error TS6133: 'x' is declared but never used. + break; + case 1: + const c = 1; + ~ +!!! error TS6133: 'c' is declared but never used. + break; + default: + let z = 2; + ~ +!!! error TS6133: 'z' is declared but never used. + } + + + switch (2) { + case 0: + let x; + case 1: + x++; + } \ No newline at end of file diff --git a/tests/baselines/reference/unusedSwitchStatment.js b/tests/baselines/reference/unusedSwitchStatment.js new file mode 100644 index 0000000000000..2fd0d1fc49ee8 --- /dev/null +++ b/tests/baselines/reference/unusedSwitchStatment.js @@ -0,0 +1,38 @@ +//// [unusedSwitchStatment.ts] + +switch (1) { + case 0: + let x; + break; + case 1: + const c = 1; + break; + default: + let z = 2; +} + + +switch (2) { + case 0: + let x; + case 1: + x++; +} + +//// [unusedSwitchStatment.js] +switch (1) { + case 0: + var x = void 0; + break; + case 1: + var c = 1; + break; + default: + var z = 2; +} +switch (2) { + case 0: + var x = void 0; + case 1: + x++; +} diff --git a/tests/cases/compiler/unusedSwitchStatment.ts b/tests/cases/compiler/unusedSwitchStatment.ts new file mode 100644 index 0000000000000..53f93b913aad0 --- /dev/null +++ b/tests/cases/compiler/unusedSwitchStatment.ts @@ -0,0 +1,21 @@ +//@noUnusedLocals:true +//@noUnusedParameters:true + +switch (1) { + case 0: + let x; + break; + case 1: + const c = 1; + break; + default: + let z = 2; +} + + +switch (2) { + case 0: + let x; + case 1: + x++; +} \ No newline at end of file