Skip to content

Commit

Permalink
check for unreachable code
Browse files Browse the repository at this point in the history
  • Loading branch information
ashwinr committed Aug 19, 2013
1 parent dbe82b9 commit 68c8c91
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Supported Rules
* `noarg` disallows access to `arguments.callee`.
* `noconsole` disallows access to the specified properties on `console`. Rule options are properties to ban on the console variable.
* `noconstruct` disallows access to the constructors of `String`, `Number`, and `Boolean`.
* `nounreachable` disallows unreachable code after `break`, `catch`, `throw`, and `return` statements.
* `noempty` disallows empty blocks.
* `oneline` enforces the specified tokens to be on the same line as the expression preceding it. Rule options:
* `"check-catch"` checks that `catch` is on the same line as the closing brace for `try`
Expand Down
63 changes: 63 additions & 0 deletions bin/tslint-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -27584,6 +27584,68 @@ var Lint;
var Rules = Lint.Rules;
})(Lint || (Lint = {}));
var Lint;
(function (Lint) {
(function (Rules) {
var NoUnreachableRule = (function (_super) {
__extends(NoUnreachableRule, _super);
function NoUnreachableRule() {
_super.apply(this, arguments);
}
NoUnreachableRule.prototype.apply = function (syntaxTree) {
return this.applyWithWalker(new UnreachableWalker(syntaxTree));
};
NoUnreachableRule.FAILURE_STRING = "unreachable code";
return NoUnreachableRule;
})(Rules.AbstractRule);
Rules.NoUnreachableRule = NoUnreachableRule;

var UnreachableWalker = (function (_super) {
__extends(UnreachableWalker, _super);
function UnreachableWalker(syntaxTree) {
_super.call(this, syntaxTree);
this.hasReturned = false;
}
UnreachableWalker.prototype.visitNode = function (node) {
if (this.hasReturned) {
this.hasReturned = false;
var position = this.position() + node.leadingTriviaWidth();
this.addFailure(this.createFailure(position, node.width(), NoUnreachableRule.FAILURE_STRING));
}

_super.prototype.visitNode.call(this, node);
};

UnreachableWalker.prototype.visitBlock = function (node) {
this.hasReturned = false;
_super.prototype.visitBlock.call(this, node);
this.hasReturned = false;
};

UnreachableWalker.prototype.visitBreakStatement = function (node) {
_super.prototype.visitBreakStatement.call(this, node);
this.hasReturned = true;
};

UnreachableWalker.prototype.visitContinueStatement = function (node) {
_super.prototype.visitContinueStatement.call(this, node);
this.hasReturned = true;
};

UnreachableWalker.prototype.visitReturnStatement = function (node) {
_super.prototype.visitReturnStatement.call(this, node);
this.hasReturned = true;
};

UnreachableWalker.prototype.visitThrowStatement = function (node) {
_super.prototype.visitThrowStatement.call(this, node);
this.hasReturned = true;
};
return UnreachableWalker;
})(Lint.RuleWalker);
})(Lint.Rules || (Lint.Rules = {}));
var Rules = Lint.Rules;
})(Lint || (Lint = {}));
var Lint;
(function (Lint) {
(function (Rules) {
var NoEmptyRule = (function (_super) {
Expand Down Expand Up @@ -28172,6 +28234,7 @@ var Lint;
"noarg": Rules.NoArgRule.prototype,
"noconsole": Rules.NoConsoleRule.prototype,
"noconstruct": Rules.NoConstructRule.prototype,
"nounreachable": Rules.NoUnreachableRule.prototype,
"noempty": Rules.NoEmptyRule.prototype,
"oneline": Rules.OneLineRule.prototype,
"quotemark": Rules.QuoteMarkRule.prototype,
Expand Down
63 changes: 63 additions & 0 deletions lib/tslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -27584,6 +27584,68 @@ var Lint;
var Rules = Lint.Rules;
})(Lint || (Lint = {}));
var Lint;
(function (Lint) {
(function (Rules) {
var NoUnreachableRule = (function (_super) {
__extends(NoUnreachableRule, _super);
function NoUnreachableRule() {
_super.apply(this, arguments);
}
NoUnreachableRule.prototype.apply = function (syntaxTree) {
return this.applyWithWalker(new UnreachableWalker(syntaxTree));
};
NoUnreachableRule.FAILURE_STRING = "unreachable code";
return NoUnreachableRule;
})(Rules.AbstractRule);
Rules.NoUnreachableRule = NoUnreachableRule;

var UnreachableWalker = (function (_super) {
__extends(UnreachableWalker, _super);
function UnreachableWalker(syntaxTree) {
_super.call(this, syntaxTree);
this.hasReturned = false;
}
UnreachableWalker.prototype.visitNode = function (node) {
if (this.hasReturned) {
this.hasReturned = false;
var position = this.position() + node.leadingTriviaWidth();
this.addFailure(this.createFailure(position, node.width(), NoUnreachableRule.FAILURE_STRING));
}

_super.prototype.visitNode.call(this, node);
};

UnreachableWalker.prototype.visitBlock = function (node) {
this.hasReturned = false;
_super.prototype.visitBlock.call(this, node);
this.hasReturned = false;
};

UnreachableWalker.prototype.visitBreakStatement = function (node) {
_super.prototype.visitBreakStatement.call(this, node);
this.hasReturned = true;
};

UnreachableWalker.prototype.visitContinueStatement = function (node) {
_super.prototype.visitContinueStatement.call(this, node);
this.hasReturned = true;
};

UnreachableWalker.prototype.visitReturnStatement = function (node) {
_super.prototype.visitReturnStatement.call(this, node);
this.hasReturned = true;
};

UnreachableWalker.prototype.visitThrowStatement = function (node) {
_super.prototype.visitThrowStatement.call(this, node);
this.hasReturned = true;
};
return UnreachableWalker;
})(Lint.RuleWalker);
})(Lint.Rules || (Lint.Rules = {}));
var Rules = Lint.Rules;
})(Lint || (Lint = {}));
var Lint;
(function (Lint) {
(function (Rules) {
var NoEmptyRule = (function (_super) {
Expand Down Expand Up @@ -28172,6 +28234,7 @@ var Lint;
"noarg": Rules.NoArgRule.prototype,
"noconsole": Rules.NoConsoleRule.prototype,
"noconstruct": Rules.NoConstructRule.prototype,
"nounreachable": Rules.NoUnreachableRule.prototype,
"noempty": Rules.NoEmptyRule.prototype,
"oneline": Rules.OneLineRule.prototype,
"quotemark": Rules.QuoteMarkRule.prototype,
Expand Down
73 changes: 73 additions & 0 deletions src/rules/noUnreachableRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2013 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/// <reference path='rule.ts'/>
/// <reference path='abstractRule.ts'/>

module Lint.Rules {
export class NoUnreachableRule extends AbstractRule {
public static FAILURE_STRING = "unreachable code";

public apply(syntaxTree: TypeScript.SyntaxTree): RuleFailure[] {
return this.applyWithWalker(new UnreachableWalker(syntaxTree));
}
}

class UnreachableWalker extends Lint.RuleWalker {
private hasReturned: boolean;

constructor(syntaxTree: TypeScript.SyntaxTree) {
super(syntaxTree);
this.hasReturned = false;
}

public visitNode(node: TypeScript.SyntaxNode): void {
if (this.hasReturned) {
this.hasReturned = false;
var position = this.position() + node.leadingTriviaWidth();
this.addFailure(this.createFailure(position, node.width(), NoUnreachableRule.FAILURE_STRING));
}

super.visitNode(node);
}

public visitBlock(node: TypeScript.BlockSyntax): void {
this.hasReturned = false;
super.visitBlock(node);
this.hasReturned = false;
}

public visitBreakStatement(node: TypeScript.BreakStatementSyntax): void {
super.visitBreakStatement(node);
this.hasReturned = true;
}

public visitContinueStatement(node: TypeScript.ContinueStatementSyntax): void {
super.visitContinueStatement(node);
this.hasReturned = true;
}

public visitReturnStatement(node: TypeScript.ReturnStatementSyntax): void {
super.visitReturnStatement(node);
this.hasReturned = true;
}

public visitThrowStatement(node: TypeScript.ThrowStatementSyntax): void {
super.visitThrowStatement(node);
this.hasReturned = true;
}
}
}
2 changes: 2 additions & 0 deletions src/rules/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
/// <reference path='noArgRule.ts'/>
/// <reference path='noConsoleRule.ts'/>
/// <reference path='noConstructRule.ts'/>
/// <reference path='noUnreachableRule.ts'/>
/// <reference path='noEmptyRule.ts' />
/// <reference path='oneLineRule.ts'/>
/// <reference path='quoteMarkRule.ts'/>
Expand Down Expand Up @@ -60,6 +61,7 @@ module Lint.Rules {
"noarg": NoArgRule.prototype,
"noconsole": NoConsoleRule.prototype,
"noconstruct": NoConstructRule.prototype,
"nounreachable": NoUnreachableRule.prototype,
"noempty": NoEmptyRule.prototype,
"oneline": OneLineRule.prototype,
"quotemark": QuoteMarkRule.prototype,
Expand Down
41 changes: 41 additions & 0 deletions test/files/rules/nounreachable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// invalid code

function f1() {
var x = 3;
return;
var y;
var z;
}

var f2 = () => {
if (x === 3) {
throw new Error("error");
"123";
} else {
return y;
}

return 123;
};

lab:
for (var i = 0; i < 10; ++i) {
if (i === 3) {
break;
console.log("hi");
} else {
continue lab;
i = 4;
}
}

// valid code
var f2 = () => {
if (x === 3) {
throw new Error("error");
} else {
return y;
}

return 123;
};
1 change: 1 addition & 0 deletions tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"trace"
],
"noconstruct": true,
"nounreachable": true,
"noempty": true,
"oneline": [true,
"check-open-brace",
Expand Down

0 comments on commit 68c8c91

Please sign in to comment.