refactor fix

This commit is contained in:
Arthur Ozga 2016-12-14 08:41:55 -08:00
parent 3cfac081d5
commit 467381273e

View File

@ -2,73 +2,75 @@
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const start = context.span.start;
const token = getTokenAtPosition(sourceFile, start);
const checker = context.program.getTypeChecker();
getCodeActions: getActionForClassLikeIncorrectImplementsInterface
});
const classDecl = getContainingClass(token);
if (!classDecl) {
return undefined;
}
function getActionForClassLikeIncorrectImplementsInterface(context: CodeFixContext): CodeAction[] | undefined {
const sourceFile = context.sourceFile;
const start = context.span.start;
const token = getTokenAtPosition(sourceFile, start);
const checker = context.program.getTypeChecker();
const startPos: number = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl);
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
const result: CodeAction[] = [];
const classDecl = getContainingClass(token);
if (!classDecl) {
return undefined;
}
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
const startPos: number = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl);
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
for (const implementedTypeNode of implementedTypeNodes) {
const implementedType = checker.getTypeFromTypeReference(implementedTypeNode) as InterfaceType;
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
const nonPrivateMembers = implementedTypeSymbols.filter(symbolRefersToNonPrivateMember);
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
let insertion = getMissingIndexSignatureInsertion(implementedType, IndexKind.Number, classDecl, hasNumericIndexSignature);
insertion += getMissingIndexSignatureInsertion(implementedType, IndexKind.String, classDecl, hasStringIndexSignature);
insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
const result: CodeAction[] = [];
for (const implementedTypeNode of implementedTypeNodes) {
const implementedType = checker.getTypeFromTypeReference(implementedTypeNode) as InterfaceType;
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
const nonPrivateMembers = implementedTypeSymbols.filter(symbolRefersToNonPrivateMember);
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
if (insertion) {
pushAction(result, insertion, message);
}
}
let insertion = getMissingIndexSignatureInsertion(implementedType, IndexKind.Number, classDecl, hasNumericIndexSignature);
insertion += getMissingIndexSignatureInsertion(implementedType, IndexKind.String, classDecl, hasStringIndexSignature);
insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
return result;
function getMissingIndexSignatureInsertion(type: InterfaceType, kind: IndexKind, enclosingDeclaration: ClassLikeDeclaration, hasIndexSigOfKind: boolean) {
if (!hasIndexSigOfKind) {
const IndexInfoOfKind = checker.getIndexInfoOfType(type, kind);
if (IndexInfoOfKind) {
return checker.indexSignatureToString(IndexInfoOfKind, kind, enclosingDeclaration);
}
}
return "";
}
function symbolRefersToNonPrivateMember(symbol: Symbol): boolean {
const decls = symbol.getDeclarations();
Debug.assert(!!(decls && decls.length > 0));
return !(getModifierFlags(decls[0]) & ModifierFlags.Private);
}
function pushAction(result: CodeAction[], insertion: string, description: string): void {
const newAction: CodeAction = {
description: description,
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: insertion
}]
}]
};
result.push(newAction);
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
if (insertion) {
pushAction(result, insertion, message);
}
}
});
return result;
function getMissingIndexSignatureInsertion(type: InterfaceType, kind: IndexKind, enclosingDeclaration: ClassLikeDeclaration, hasIndexSigOfKind: boolean) {
if (!hasIndexSigOfKind) {
const IndexInfoOfKind = checker.getIndexInfoOfType(type, kind);
if (IndexInfoOfKind) {
return checker.indexSignatureToString(IndexInfoOfKind, kind, enclosingDeclaration);
}
}
return "";
}
function symbolRefersToNonPrivateMember(symbol: Symbol): boolean {
const decls = symbol.getDeclarations();
Debug.assert(!!(decls && decls.length > 0));
return !(getModifierFlags(decls[0]) & ModifierFlags.Private);
}
function pushAction(result: CodeAction[], insertion: string, description: string): void {
const newAction: CodeAction = {
description: description,
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: insertion
}]
}]
};
result.push(newAction);
}
}
}