Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Add destructuring syntax & support to no-unused-variable rule for parameter declarations #412

Merged
merged 1 commit into from
Jun 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/tslint.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ declare module Lint {
function doesIntersect(failure: RuleFailure, disabledIntervals: Lint.IDisabledInterval[]): boolean;
function abstract(): string;
function scanAllTokens(scanner: ts.Scanner, callback: (scanner: ts.Scanner) => void): void;
function hasModifier(modifiers: ts.ModifiersArray, ...modifierKinds: ts.SyntaxKind[]): boolean;
}
declare module Lint {
class RuleWalker extends Lint.SyntaxWalker {
Expand Down
13 changes: 13 additions & 0 deletions src/language/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,17 @@ module Lint {
callback(scanner);
}
}

/**
* @returns true if any modifier kinds passed along exist in the given modifiers array
*/
export function hasModifier(modifiers: ts.ModifiersArray, ...modifierKinds: ts.SyntaxKind[]) {
if (modifiers == null || modifierKinds == null) {
return false;
}

return modifiers.some((m) => {
return modifierKinds.some((k) => m.kind === k);
});
}
}
49 changes: 23 additions & 26 deletions src/rules/noUnusedVariableRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
}

public visitImportDeclaration(node: ts.ImportDeclaration): void {
if (!this.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
var importClause = node.importClause;

// named imports & namespace imports handled by other walker methods
Expand All @@ -67,7 +67,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
}

public visitImportEqualsDeclaration(node: ts.ImportEqualsDeclaration): void {
if (!this.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
var name = node.name;
this.validateReferencesForVariable(name.text, name.getStart());
}
Expand Down Expand Up @@ -119,8 +119,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {

// skip exported and declared variables
public visitVariableStatement(node: ts.VariableStatement): void {
if (this.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)
|| this.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword)) {
if (Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword, ts.SyntaxKind.DeclareKeyword)) {
this.skipBindingElement = true;
this.skipVariableDeclaration = true;
}
Expand All @@ -140,23 +139,35 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
public visitFunctionDeclaration(node: ts.FunctionDeclaration): void {
var variableName = node.name.text;

if (!this.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
this.validateReferencesForVariable(variableName, node.name.getStart());
}

super.visitFunctionDeclaration(node);
}

public visitParameterDeclaration(node: ts.ParameterDeclaration): void {
var nameNode = <ts.Identifier> node.name;
var variableName = nameNode.text;
var isSingleVariable = node.name.kind === ts.SyntaxKind.Identifier;
var isPropertyParameter = Lint.hasModifier(node.modifiers,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice.

ts.SyntaxKind.PublicKeyword,
ts.SyntaxKind.PrivateKeyword,
ts.SyntaxKind.ProtectedKeyword);

if (!this.hasModifier(node.modifiers, ts.SyntaxKind.PublicKeyword)
&& !this.skipParameterDeclaration && this.hasOption(OPTION_CHECK_PARAMETERS)) {
this.validateReferencesForVariable(variableName, node.name.getStart());
if (!isSingleVariable && isPropertyParameter) {
// tsc error: a parameter property may not be a binding pattern
this.skipBindingElement = true;
}

if (this.hasOption(OPTION_CHECK_PARAMETERS)
&& isSingleVariable
&& !this.skipParameterDeclaration
&& !Lint.hasModifier(node.modifiers, ts.SyntaxKind.PublicKeyword)) {
var nameNode = <ts.Identifier> node.name;
this.validateReferencesForVariable(nameNode.text, node.name.getStart());
}

super.visitParameterDeclaration(node);
this.skipBindingElement = false;
}

// check private member variables
Expand All @@ -166,7 +177,7 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
var variableName = (<ts.Identifier> node.name).text;

// check only if an explicit 'private' modifier is specified
if (this.hasModifier(modifiers, ts.SyntaxKind.PrivateKeyword)) {
if (Lint.hasModifier(modifiers, ts.SyntaxKind.PrivateKeyword)) {
this.validateReferencesForVariable(variableName, node.name.getStart());
}
}
Expand All @@ -180,28 +191,14 @@ class NoUnusedVariablesWalker extends Lint.RuleWalker {
var modifiers = node.modifiers;
var variableName = (<ts.Identifier> node.name).text;

if (this.hasModifier(modifiers, ts.SyntaxKind.PrivateKeyword)) {
if (Lint.hasModifier(modifiers, ts.SyntaxKind.PrivateKeyword)) {
this.validateReferencesForVariable(variableName, node.name.getStart());
}
}

super.visitMethodDeclaration(node);
}

private hasModifier(modifiers: ts.ModifiersArray, modifierKind: ts.SyntaxKind) {
if (modifiers == null) {
return false;
}
for (var i = 0, n = modifiers.length; i < n; i++) {
var modifier = modifiers[i];
if (modifier.kind === modifierKind) {
return true;
}
}

return false;
}

private validateReferencesForVariable(name: string, position: number) {
var highlights = this.languageService.getDocumentHighlights("file.ts", position, ["file.ts"]);
if (highlights[0].highlightSpans.length <= 1) {
Expand Down
30 changes: 26 additions & 4 deletions test/files/rules/nounusedvariable-parameter.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
export function func1(x: number, y: number, ...args: number[]) {
export function func1(x: number, y: number, ...args: number[]) { // 'args' failure
return x + y;
}

export function func2(x: number, y: number, ...args: number[]) {
export function func2(x: number, y: number, ...args: number[]) { // 'y' failure
return x + args[0];
}

export function func3(x?: number, y?: number) {
export function func3(x?: number, y?: number) { // 'y' failure
return x;
}

Expand All @@ -15,7 +15,7 @@ export interface ITestInterface {
}

export class ABCD {
constructor(private x: number, public y: number, private z: number) {
constructor(private x: number, public y: number, private z: number) { // 'x' failure
}

func5() {
Expand All @@ -34,3 +34,25 @@ export function func6(...args: number[]) {
export function func7(f: (x: number) => number) {
return f;
}

export function func8([x, y]: [number, number]) { // 'y' failure
return x;
}

export class DestructuringTests {
constructor(public x: number, public [y, z]) { // tsc error on binding pattern
}

public func9({a, b}) { // 'b' failure
return a;
}

public func10([a, b]) { // 'b' failure
return [a];
}

// destructuring with default value
public func11([x = 0]) { // 'x' failure
return;
}
}
11 changes: 9 additions & 2 deletions test/rules/noUnusedVariableRuleTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,21 @@ describe("<no-unused-variable>", () => {
var failure2 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'y'")([5, 34], [5, 35]);
var failure3 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'y'")([9, 35], [9, 36]);
var failure4 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'x'")([18, 25], [18, 26]);
var failure5 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'y'")([38, 27], [38, 28]);
var failure6 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'b'")([46, 22], [46, 23]);
var failure7 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'b'")([50, 23], [50, 24]);
var failure8 = Lint.Test.createFailuresOnFile(fileName, Rule.FAILURE_STRING + "'x'")([55, 20], [55, 21]);

var actualFailures = Lint.Test.applyRuleOnFile(fileName, Rule, [true, "check-parameters"]);

assert.lengthOf(actualFailures, 4);

assert.lengthOf(actualFailures, 8);
Lint.Test.assertContainsFailure(actualFailures, failure1);
Lint.Test.assertContainsFailure(actualFailures, failure2);
Lint.Test.assertContainsFailure(actualFailures, failure3);
Lint.Test.assertContainsFailure(actualFailures, failure4);
Lint.Test.assertContainsFailure(actualFailures, failure5);
Lint.Test.assertContainsFailure(actualFailures, failure6);
Lint.Test.assertContainsFailure(actualFailures, failure7);
Lint.Test.assertContainsFailure(actualFailures, failure8);
});
});