Api Changes and simple superfixes

This commit is contained in:
Paul van Brenk
2016-08-05 16:20:16 -07:00
parent 269b828538
commit 94ea825f95
6 changed files with 194 additions and 3 deletions

View File

@@ -0,0 +1,53 @@
/* @internal */
namespace ts {
export interface CodeFix {
name: string;
errorCodes: string[];
getCodeActions(context: CodeFixContext): CodeAction[];
}
export interface CodeFixContext {
errorCode: string;
sourceFile: SourceFile;
span: TextSpan;
checker: TypeChecker;
newLineCharacter: string;
}
export namespace codeFix {
const codeFixes: Map<CodeFix[]> = {};
export function registerCodeFix(action: CodeFix) {
forEach(action.errorCodes, error => {
let fixes = codeFixes[error];
if (!fixes) {
fixes = [];
codeFixes[error] = fixes;
}
fixes.push(action);
});
}
export class CodeFixProvider {
public static getSupportedErrorCodes() {
return getKeys(codeFixes);
}
public getFixes(context: CodeFixContext): CodeAction[] {
const fixes = codeFixes[context.errorCode];
let allActions: CodeAction[] = [];
Debug.assert(fixes && fixes.length > 0, "No fixes found for error: '${errorCode}'.");
forEach(fixes, f => {
const actions = f.getCodeActions(context);
if (actions && actions.length > 0) {
allActions = allActions.concat(actions);
}
});
return allActions;
}
}
}
}

View File

@@ -0,0 +1,6 @@
///<reference path='..\services.ts' />
///<reference path='codeFixProvider.ts' />
///<reference path='superFixes.ts' />
///<reference path='unusedIdentifierFixes.ts' />
///<reference path='changeExtendsToImplementsFix.ts' />
///<reference path='interfaceFixes.ts' />

View File

@@ -0,0 +1,65 @@
/* @internal */
namespace ts.codeFix {
function getOpenBraceEnd(constructor: ConstructorDeclaration, sourceFile: SourceFile) {
// First token is the open curly, this is where we want to put the 'super' call.
return constructor.body.getFirstToken(sourceFile).getEnd();
}
registerCodeFix({
name: "AddMissingSuperCallFix",
errorCodes: ["TS2377"],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const token = getTokenAtPosition(sourceFile, context.span.start);
Debug.assert(token.kind === SyntaxKind.ConstructorKeyword, "Failed to find the constructor.");
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>token.parent, sourceFile);
return [{
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }]
}];
}
});
registerCodeFix({
name: "MakeSuperCallTheFirstStatementInTheConstructor",
errorCodes: ["TS17009"],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const token = getTokenAtPosition(sourceFile, context.span.start);
const constructor = getContainingFunction(token);
Debug.assert(constructor.kind === SyntaxKind.Constructor, "Failed to find the constructor.");
const superCall = findSuperCall((<ConstructorDeclaration>constructor).body);
Debug.assert(!!superCall, "Failed to find super call.");
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>constructor, sourceFile);
const changes = [{
fileName: sourceFile.fileName, textChanges: [{
newText: superCall.getText(sourceFile),
span: { start: newPosition, length: 0 }
},
{
newText: "",
span: { start: superCall.getStart(sourceFile), length: superCall.getWidth(sourceFile) }
}]
}];
return [{
description: getLocaleSpecificMessage(Diagnostics.Make_super_call_the_first_statement_in_the_constructor),
changes
}];
function findSuperCall(n: Node): Node {
if (n.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((<ExpressionStatement>n).expression)) {
return n;
}
if (isFunctionLike(n)) {
return undefined;
}
return forEachChild(n, findSuperCall);
}
}
});
}