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

Commit

Permalink
applyWithFunction: allow passing TypeChecker or Program directly (#3140)
Browse files Browse the repository at this point in the history
With this change we no longer need a closure to pass the TypeChecker of Program to the walkFn.

[api] `applyWithFunction` allows additional parameter that is passed through to `walkFn`
  • Loading branch information
ajafff authored and adidahiya committed Aug 18, 2017
1 parent 2ed0fc2 commit a66fc77
Show file tree
Hide file tree
Showing 21 changed files with 56 additions and 35 deletions.
15 changes: 13 additions & 2 deletions src/language/rule/abstractRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,20 @@ export abstract class AbstractRule implements IRule {

protected applyWithFunction(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext<void>) => void): RuleFailure[];
protected applyWithFunction<T>(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext<T>) => void, options: NoInfer<T>): RuleFailure[];
protected applyWithFunction<T>(sourceFile: ts.SourceFile, walkFn: (ctx: WalkContext<T | void>) => void, options?: T): RuleFailure[] {
protected applyWithFunction<T, U>(
sourceFile: ts.SourceFile,
walkFn: (ctx: WalkContext<T>, programOrChecker: U) => void,
options: NoInfer<T>,
checker: NoInfer<U>,
): RuleFailure[];
protected applyWithFunction<T, U>(
sourceFile: ts.SourceFile,
walkFn: (ctx: WalkContext<T | void>, programOrChecker?: U) => void,
options?: T,
programOrChecker?: U,
): RuleFailure[] {
const ctx = new WalkContext(sourceFile, this.ruleName, options);
walkFn(ctx);
walkFn(ctx, programOrChecker);
return ctx.failures;
}

Expand Down
6 changes: 3 additions & 3 deletions src/rules/awaitPromiseRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ export class Rule extends Lint.Rules.TypedRule {

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
const promiseTypes = new Set(["Promise", ...this.ruleArguments as string[]]);
const tc = program.getTypeChecker();
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, tc, promiseTypes));
return this.applyWithFunction(sourceFile, walk, promiseTypes, program.getTypeChecker());
}
}

function walk(ctx: Lint.WalkContext<void>, tc: ts.TypeChecker, promiseTypes: Set<string>) {
function walk(ctx: Lint.WalkContext<Set<string>>, tc: ts.TypeChecker) {
const promiseTypes = ctx.options;
return ts.forEachChild(ctx.sourceFile, cb);

function cb(node: ts.Node): void {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/deprecationRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/matchDefaultExportNameRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/noBooleanLiteralCompareRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/rules/noFloatingPromisesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ export class Rule extends Lint.Rules.TypedRule {
public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(
sourceFile,
(ctx) => walk(ctx, program.getTypeChecker()),
walk,
["Promise", ...this.ruleArguments as string[]],
program.getTypeChecker(),
);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/rules/noForInArrayRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ export class Rule extends Lint.Rules.TypedRule {
public static FAILURE_STRING = "for-in loops over arrays are forbidden. Use for-of or array.forEach instead.";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

function walk(ctx: Lint.WalkContext<void>, program: ts.Program) {
function walk(ctx: Lint.WalkContext<void>, checker: ts.TypeChecker) {
return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void {
if (node.kind === ts.SyntaxKind.ForInStatement) {
const type = program.getTypeChecker().getTypeAtLocation((node as ts.ForInStatement).expression);
const type = checker.getTypeAtLocation((node as ts.ForInStatement).expression);
if (type.symbol !== undefined && type.symbol.name === "Array" ||
// tslint:disable-next-line:no-bitwise
(type.flags & ts.TypeFlags.StringLike) !== 0) {
Expand Down
11 changes: 8 additions & 3 deletions src/rules/noUnboundMethodRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ export class Rule extends Lint.Rules.TypedRule {
public static FAILURE_STRING = "Avoid referencing unbound methods which may cause unintentional scoping of 'this'.";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()), {
ignoreStatic: this.ruleArguments.indexOf(OPTION_IGNORE_STATIC) !== -1,
});
return this.applyWithFunction(
sourceFile,
walk,
{
ignoreStatic: this.ruleArguments.indexOf(OPTION_IGNORE_STATIC) !== -1,
},
program.getTypeChecker(),
);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/noUnnecessaryQualifierRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/noUnsafeAnyRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.TypedRule {
public static FAILURE_STRING = "Unsafe use of expression of type 'any'.";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/rules/noUnusedVariableRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class Rule extends Lint.Rules.TypedRule {
"the 'no-unused-locals' and 'no-unused-parameters' compiler options are enabled.");
}

return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program, parseOptions(this.ruleArguments)));
return this.applyWithFunction(sourceFile, walk, parseOptions(this.ruleArguments), program);
}
}

Expand All @@ -99,8 +99,8 @@ function parseOptions(options: any[]): Options {
return { checkParameters, ignorePattern };
}

function walk(ctx: Lint.WalkContext<void>, program: ts.Program, { checkParameters, ignorePattern }: Options): void {
const { sourceFile } = ctx;
function walk(ctx: Lint.WalkContext<Options>, program: ts.Program): void {
const { sourceFile, options: { checkParameters, ignorePattern } } = ctx;
const unusedCheckedProgram = getUnusedCheckedProgram(program, checkParameters);
const diagnostics = ts.getPreEmitDiagnostics(unusedCheckedProgram, sourceFile);
const checker = unusedCheckedProgram.getTypeChecker(); // Doesn't matter which program is used for this.
Expand Down Expand Up @@ -151,7 +151,7 @@ function walk(ctx: Lint.WalkContext<void>, program: ts.Program, { checkParameter
* - If all of the import specifiers in an import are unused, add a combined failure for them all.
* - Unused imports are fixable.
*/
function addImportSpecifierFailures(ctx: Lint.WalkContext<void>, failures: Map<ts.Identifier, string>, sourceFile: ts.SourceFile) {
function addImportSpecifierFailures(ctx: Lint.WalkContext<Options>, failures: Map<ts.Identifier, string>, sourceFile: ts.SourceFile) {
forEachImport(sourceFile, (importNode) => {
if (importNode.kind === ts.SyntaxKind.ImportEqualsDeclaration) {
tryRemoveAll(importNode.name);
Expand Down
2 changes: 1 addition & 1 deletion src/rules/noUseBeforeDeclareRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class Rule extends Lint.Rules.TypedRule {
}

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/rules/noVoidExpressionRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,7 @@ export class Rule extends Lint.Rules.TypedRule {

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
const ignoreArrowFunctionShorthand = this.ruleArguments.indexOf(OPTION_IGNORE_ARROW_FUNCTION_SHORTHAND) !== -1;
return this.applyWithFunction(
sourceFile, (ctx) => walk(ctx, program.getTypeChecker()), { ignoreArrowFunctionShorthand });
return this.applyWithFunction(sourceFile, walk, { ignoreArrowFunctionShorthand }, program.getTypeChecker());
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/rules/objectLiteralSortKeysRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ export class Rule extends Lint.Rules.OptionallyTypedRule {
public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(
sourceFile,
(ctx) => walk(ctx, program.getTypeChecker()),
walk,
parseOptions(this.ruleArguments),
program.getTypeChecker(),
);
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/rules/preferTemplateRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import * as Lint from "../index";

const OPTION_SINGLE_CONCAT = "allow-single-concat";

interface Options {
allowSingleConcat: boolean;
}

export class Rule extends Lint.Rules.AbstractRule {
/* tslint:disable:object-literal-sort-keys */
public static metadata: Lint.IRuleMetadata = {
Expand All @@ -48,11 +52,12 @@ export class Rule extends Lint.Rules.AbstractRule {
}

const allowSingleConcat = this.ruleArguments.indexOf(OPTION_SINGLE_CONCAT) !== -1;
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, allowSingleConcat));
return this.applyWithFunction(sourceFile, walk, {allowSingleConcat});
}
}

function walk(ctx: Lint.WalkContext<void>, allowSingleConcat: boolean): void {
function walk(ctx: Lint.WalkContext<Options>): void {
const allowSingleConcat = ctx.options.allowSingleConcat;
return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void {
const failure = getError(node, allowSingleConcat);
if (failure !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/promiseFunctionAsyncRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class Rule extends Lint.Rules.TypedRule {
public static FAILURE_STRING = "functions that return promises must be async";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/rules/restrictPlusOperandsRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ export class Rule extends Lint.Rules.TypedRule {
public static INVALID_TYPES_ERROR = "Operands of '+' operation must either be both strings or both numbers";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

function walk(ctx: Lint.WalkContext<void>, program: ts.Program) {
function walk(ctx: Lint.WalkContext<void>, tc: ts.TypeChecker) {
return ts.forEachChild(ctx.sourceFile, function cb(node: ts.Node): void {
if (isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
const tc = program.getTypeChecker();
const leftType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.left));
const rightType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.right));
if (leftType === "invalid" || rightType === "invalid" || leftType !== rightType) {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/returnUndefinedRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class Rule extends Lint.Rules.TypedRule {
"`void` function should use `return;`, not `return undefined;`.";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/strictBooleanExpressionsRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class Rule extends Lint.Rules.TypedRule {

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
const options = parseOptions(this.ruleArguments, Lint.isStrictNullChecksEnabled(program.getCompilerOptions()));
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()), options);
return this.applyWithFunction(sourceFile, walk, options, program.getTypeChecker());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/strictTypePredicatesRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class Rule extends Lint.Rules.TypedRule {
showWarningOnce("strict-type-predicates does not work without --strictNullChecks");
return [];
}
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rules/useDefaultTypeParameterRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class Rule extends Lint.Rules.TypedRule {
public static FAILURE_STRING = "This is the default value for this type parameter, so it can be omitted.";

public applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, (ctx) => walk(ctx, program.getTypeChecker()));
return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
}
}

Expand Down

0 comments on commit a66fc77

Please sign in to comment.