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

Commit

Permalink
Add "no-invalid-this" rule (#1105)
Browse files Browse the repository at this point in the history
[no-invalid-this], when enabled, complains about the usage of the
`this` keyword outside of class bodies. This is useful because `this`
used in non-method bodies is /usually/ a bug outside of some older
javascript styles.
  • Loading branch information
AndyMoreland authored and jkillian committed Apr 18, 2016
1 parent 7dc17de commit e49726a
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 3 deletions.
7 changes: 4 additions & 3 deletions src/language/walker/scopeAwareRuleWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ export abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
super(sourceFile, options);

// initialize stack with global scope
this.scopeStack = [this.createScope()];
this.scopeStack = [this.createScope(sourceFile)];
}

public abstract createScope(): T;
public abstract createScope(node: ts.Node): T;

public getCurrentScope(): T {
return this.scopeStack[this.scopeStack.length - 1];
Expand Down Expand Up @@ -57,7 +57,7 @@ export abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
const isNewScope = this.isScopeBoundary(node);

if (isNewScope) {
this.scopeStack.push(this.createScope());
this.scopeStack.push(this.createScope(node));
}

this.onScopeStart();
Expand All @@ -80,6 +80,7 @@ export abstract class ScopeAwareRuleWalker<T> extends RuleWalker {
|| node.kind === ts.SyntaxKind.ArrowFunction
|| node.kind === ts.SyntaxKind.ParenthesizedExpression
|| node.kind === ts.SyntaxKind.ClassDeclaration
|| node.kind === ts.SyntaxKind.ClassExpression
|| node.kind === ts.SyntaxKind.InterfaceDeclaration
|| node.kind === ts.SyntaxKind.GetAccessor
|| node.kind === ts.SyntaxKind.SetAccessor;
Expand Down
51 changes: 51 additions & 0 deletions src/rules/noInvalidThisRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @license
* Copyright 2016 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.
*/

import * as ts from "typescript";
import * as Lint from "../lint";

export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "the \"this\" keyword is disallowed outside of a class body" ;

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithWalker(new NoInvalidThisWalker(sourceFile, this.getOptions()));
}
}

class NoInvalidThisWalker extends Lint.ScopeAwareRuleWalker<{inClass: boolean}> {
public createScope(node: ts.Node): { inClass: boolean } {
const isClassScope = node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ClassExpression;

return {
inClass: isClassScope,
};
}

protected validateThisKeyword(node: ts.Node) {
if (!this.getAllScopes().some((scope) => scope.inClass)) {
this.addFailure(this.createFailure(node.getStart(), node.getWidth(), Rule.FAILURE_STRING));
}
}

public visitNode(node: ts.Node) {
if (node.kind === ts.SyntaxKind.ThisKeyword) {
this.validateThisKeyword(node);
}

super.visitNode(node);
}
}
1 change: 1 addition & 0 deletions src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"rules/noEvalRule.ts",
"rules/noInferrableTypesRule.ts",
"rules/noInternalModuleRule.ts",
"rules/noInvalidThisRule.ts",
"rules/noNullKeywordRule.ts",
"rules/noRequireImportsRule.ts",
"rules/noShadowedVariableRule.ts",
Expand Down
23 changes: 23 additions & 0 deletions test/rules/no-invalid-this/enabled/test.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function foo(x: number) {
console.log(this.x);
~~~~[the "this" keyword is disallowed outside of a class body]

this.evilMethod();
~~~~[the "this" keyword is disallowed outside of a class body]
}

class AClass {
private x: number;

public aMethod() {
this.x = 5;
}
}

const AClassExpression = class {
private x: number;

public aMethod() {
this.x = 5;
}
}
5 changes: 5 additions & 0 deletions test/rules/no-invalid-this/enabled/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-invalid-this": [true]
}
}
1 change: 1 addition & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
"../src/rules/noEvalRule.ts",
"../src/rules/noInferrableTypesRule.ts",
"../src/rules/noInternalModuleRule.ts",
"../src/rules/noInvalidThisRule.ts",
"../src/rules/noNullKeywordRule.ts",
"../src/rules/noRequireImportsRule.ts",
"../src/rules/noShadowedVariableRule.ts",
Expand Down

0 comments on commit e49726a

Please sign in to comment.