Merge branch 'master' of github.com:Microsoft/TypeScript
This commit is contained in:
commit
f0997c1e50
10 changed files with 78 additions and 68 deletions
|
@ -32,16 +32,16 @@ namespace ts.codefix {
|
|||
|
||||
const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false);
|
||||
let declaration!: Declaration;
|
||||
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken); });
|
||||
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeenseen*/ returnTrue); });
|
||||
return changes.length === 0 ? undefined
|
||||
: [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), getNameOfDeclaration(declaration).getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)];
|
||||
},
|
||||
fixIds: [fixId],
|
||||
getAllCodeActions(context) {
|
||||
const { sourceFile, program, cancellationToken } = context;
|
||||
const seenFunctions = createMap<true>();
|
||||
const markSeen = nodeSeenTracker();
|
||||
return codeFixAll(context, errorCodes, (changes, err) => {
|
||||
doChange(changes, sourceFile, getTokenAtPosition(err.file!, err.start!, /*includeJsDocComment*/ false), err.code, program, cancellationToken, seenFunctions);
|
||||
doChange(changes, sourceFile, getTokenAtPosition(err.file!, err.start!, /*includeJsDocComment*/ false), err.code, program, cancellationToken, markSeen);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -57,7 +57,7 @@ namespace ts.codefix {
|
|||
}
|
||||
}
|
||||
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, seenFunctions?: Map<true>): Declaration | undefined {
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker): Declaration | undefined {
|
||||
if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ namespace ts.codefix {
|
|||
// Variable and Property declarations
|
||||
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
|
||||
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
|
||||
if (isVariableDeclaration(parent) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location
|
||||
if ((isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location
|
||||
annotateVariableDeclaration(changes, sourceFile, parent, program, cancellationToken);
|
||||
return parent;
|
||||
}
|
||||
|
@ -75,10 +75,11 @@ namespace ts.codefix {
|
|||
|
||||
case Diagnostics.Variable_0_implicitly_has_an_1_type.code: {
|
||||
const symbol = program.getTypeChecker().getSymbolAtLocation(token);
|
||||
if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration)) {
|
||||
if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && markSeen(symbol.valueDeclaration)) {
|
||||
annotateVariableDeclaration(changes, sourceFile, symbol.valueDeclaration, program, cancellationToken);
|
||||
return symbol.valueDeclaration;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ namespace ts.codefix {
|
|||
}
|
||||
// falls through
|
||||
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
|
||||
if (!seenFunctions || addToSeen(seenFunctions, getNodeId(containingFunction))) {
|
||||
if (markSeen(containingFunction)) {
|
||||
const param = cast(parent, isParameter);
|
||||
annotateParameters(changes, param, containingFunction, sourceFile, program, cancellationToken);
|
||||
return param;
|
||||
|
@ -318,6 +319,16 @@ namespace ts.codefix {
|
|||
case SyntaxKind.ElementAccessExpression:
|
||||
inferTypeFromPropertyElementExpressionContext(<ElementAccessExpression>node.parent, node, checker, usageContext);
|
||||
break;
|
||||
case SyntaxKind.VariableDeclaration: {
|
||||
const { name, initializer } = node.parent as VariableDeclaration;
|
||||
if (node === name) {
|
||||
if (initializer) { // This can happen for `let x = null;` which still has an implicit-any error.
|
||||
addCandidateType(usageContext, checker.getTypeAtLocation(initializer));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// falls through
|
||||
default:
|
||||
return inferTypeFromContextualType(node, checker, usageContext);
|
||||
}
|
||||
|
@ -511,7 +522,7 @@ namespace ts.codefix {
|
|||
return checker.getStringType();
|
||||
}
|
||||
else if (usageContext.candidateTypes) {
|
||||
return checker.getWidenedType(checker.getUnionType(map(usageContext.candidateTypes, t => checker.getBaseTypeOfLiteralType(t)), UnionReduction.Subtype));
|
||||
return checker.getWidenedType(checker.getUnionType(usageContext.candidateTypes.map(t => checker.getBaseTypeOfLiteralType(t)), UnionReduction.Subtype));
|
||||
}
|
||||
else if (usageContext.properties && hasCallContext(usageContext.properties.get("then" as __String))) {
|
||||
const paramType = getParameterTypeFromCallContexts(0, usageContext.properties.get("then" as __String).callContexts, /*isRestParameter*/ false, checker);
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
|||
fieldName: AcceptedNameType;
|
||||
accessorName: AcceptedNameType;
|
||||
originalName: AcceptedNameType;
|
||||
renameAccessor: boolean;
|
||||
}
|
||||
|
||||
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
|
||||
|
@ -43,7 +44,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
|||
|
||||
const isJS = isSourceFileJavaScript(file);
|
||||
const changeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
const { isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration } = fieldInfo;
|
||||
const { isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration, renameAccessor } = fieldInfo;
|
||||
|
||||
suppressLeadingAndTrailingTrivia(fieldName);
|
||||
suppressLeadingAndTrailingTrivia(declaration);
|
||||
|
@ -80,8 +81,10 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
|||
|
||||
const edits = changeTracker.getChanges();
|
||||
const renameFilename = file.fileName;
|
||||
const renameLocationOffset = isIdentifier(fieldName) ? 0 : -1;
|
||||
const renameLocation = renameLocationOffset + getRenameLocation(edits, renameFilename, fieldName.text, /*preferLastLocation*/ isParameter(declaration));
|
||||
|
||||
const nameNeedRename = renameAccessor ? accessorName : fieldName;
|
||||
const renameLocationOffset = isIdentifier(nameNeedRename) ? 0 : -1;
|
||||
const renameLocation = renameLocationOffset + getRenameLocation(edits, renameFilename, nameNeedRename.text, /*preferLastLocation*/ isParameter(declaration));
|
||||
return { renameFilename, renameLocation, edits };
|
||||
}
|
||||
|
||||
|
@ -110,6 +113,10 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
|||
return modifiers && createNodeArray(modifiers);
|
||||
}
|
||||
|
||||
function startsWithUnderscore(name: string): boolean {
|
||||
return name.charCodeAt(0) === CharacterCodes._;
|
||||
}
|
||||
|
||||
function getConvertibleFieldAtPosition(file: SourceFile, startPosition: number): Info | undefined {
|
||||
const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false);
|
||||
const declaration = findAncestor(node.parent, isAcceptedDeclaration);
|
||||
|
@ -117,8 +124,10 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
|||
const meaning = ModifierFlags.AccessibilityModifier | ModifierFlags.Static | ModifierFlags.Readonly;
|
||||
if (!declaration || !isConvertableName(declaration.name) || (getModifierFlags(declaration) | meaning) !== meaning) return undefined;
|
||||
|
||||
const fieldName = createPropertyName(getUniqueName(`_${declaration.name.text}`, file.text), declaration.name);
|
||||
const accessorName = createPropertyName(declaration.name.text, declaration.name);
|
||||
const name = declaration.name.text;
|
||||
const startWithUnderscore = startsWithUnderscore(name);
|
||||
const fieldName = createPropertyName(startWithUnderscore ? name : getUniqueName(`_${name}`, file.text), declaration.name);
|
||||
const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file.text) : name, declaration.name);
|
||||
return {
|
||||
isStatic: hasStaticModifier(declaration),
|
||||
isReadonly: hasReadonlyModifier(declaration),
|
||||
|
@ -128,6 +137,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
|||
declaration,
|
||||
fieldName,
|
||||
accessorName,
|
||||
renameAccessor: startWithUnderscore
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1188,7 +1188,8 @@ namespace ts {
|
|||
}
|
||||
|
||||
/** Returns `true` the first time it encounters a node and `false` afterwards. */
|
||||
export function nodeSeenTracker<T extends Node>(): (node: T) => boolean {
|
||||
export type NodeSeenTracker<T = Node> = (node: T) => boolean;
|
||||
export function nodeSeenTracker<T extends Node>(): NodeSeenTracker<T> {
|
||||
const seen: true[] = [];
|
||||
return node => {
|
||||
const id = getNodeId(node);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noImplicitAny: true
|
||||
// @strictNullChecks: true
|
||||
|
||||
////function f(x, y) {
|
||||
//// x += 0;
|
||||
|
@ -10,6 +11,11 @@
|
|||
////function g(z) {
|
||||
//// return z * 2;
|
||||
////}
|
||||
////
|
||||
////let x = null;
|
||||
////function h() {
|
||||
//// if (!x) x = 2;
|
||||
////}
|
||||
|
||||
verify.codeFixAll({
|
||||
fixId: "inferFromUsage",
|
||||
|
@ -22,5 +28,10 @@ verify.codeFixAll({
|
|||
|
||||
function g(z: number) {
|
||||
return z * 2;
|
||||
}
|
||||
|
||||
let x: number | null = null;
|
||||
function h() {
|
||||
if (!x) x = 2;
|
||||
}`,
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
//// class A {
|
||||
//// /*a*/public _a: number = 1;/*b*/
|
||||
//// /*c*/public a: string = "foo";/*d*/
|
||||
//// public a: string = "foo";
|
||||
//// }
|
||||
|
||||
goTo.select("a", "b");
|
||||
|
@ -11,36 +11,13 @@ edit.applyRefactor({
|
|||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private /*RENAME*/__a: number = 1;
|
||||
public get _a(): number {
|
||||
return this.__a;
|
||||
private _a: number = 1;
|
||||
public get /*RENAME*/a_1(): number {
|
||||
return this._a;
|
||||
}
|
||||
public set _a(value: number) {
|
||||
this.__a = value;
|
||||
public set a_1(value: number) {
|
||||
this._a = value;
|
||||
}
|
||||
public a: string = "foo";
|
||||
}`,
|
||||
});
|
||||
|
||||
goTo.select("c", "d");
|
||||
edit.applyRefactor({
|
||||
refactorName: "Generate 'get' and 'set' accessors",
|
||||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private __a: number = 1;
|
||||
public get _a(): number {
|
||||
return this.__a;
|
||||
}
|
||||
public set _a(value: number) {
|
||||
this.__a = value;
|
||||
}
|
||||
private /*RENAME*/_a_1: string = "foo";
|
||||
public get a(): string {
|
||||
return this._a_1;
|
||||
}
|
||||
public set a(value: string) {
|
||||
this._a_1 = value;
|
||||
}
|
||||
}`,
|
||||
});
|
|
@ -28,12 +28,12 @@ edit.applyRefactor({
|
|||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private /*RENAME*/__a: number = 1;
|
||||
public get _a(): number {
|
||||
return this.__a;
|
||||
private _a: number = 1;
|
||||
public get /*RENAME*/a_2(): number {
|
||||
return this._a;
|
||||
}
|
||||
public set _a(value: number) {
|
||||
this.__a = value;
|
||||
public set a_2(value: number) {
|
||||
this._a = value;
|
||||
}
|
||||
private _a_1: string = "foo";
|
||||
public get a(): string {
|
||||
|
|
|
@ -10,12 +10,12 @@ edit.applyRefactor({
|
|||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private /*RENAME*/__a: string;
|
||||
public get _a(): string {
|
||||
return this.__a;
|
||||
private _a: string;
|
||||
public get /*RENAME*/a_1(): string {
|
||||
return this._a;
|
||||
}
|
||||
public set _a(value: string) {
|
||||
this.__a = value;
|
||||
public set a_1(value: string) {
|
||||
this._a = value;
|
||||
}
|
||||
}`,
|
||||
});
|
||||
|
|
|
@ -10,12 +10,12 @@ edit.applyRefactor({
|
|||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private /*RENAME*/__a: string;
|
||||
public get _a(): string {
|
||||
return this.__a;
|
||||
private _a: string;
|
||||
public get /*RENAME*/a_1(): string {
|
||||
return this._a;
|
||||
}
|
||||
public set _a(value: string) {
|
||||
this.__a = value;
|
||||
public set a_1(value: string) {
|
||||
this._a = value;
|
||||
}
|
||||
}`,
|
||||
});
|
||||
|
|
|
@ -10,12 +10,12 @@ edit.applyRefactor({
|
|||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private /*RENAME*/__a: string;
|
||||
public get _a(): string {
|
||||
return this.__a;
|
||||
private _a: string;
|
||||
public get /*RENAME*/a_1(): string {
|
||||
return this._a;
|
||||
}
|
||||
public set _a(value: string) {
|
||||
this.__a = value;
|
||||
public set a_1(value: string) {
|
||||
this._a = value;
|
||||
}
|
||||
}`,
|
||||
});
|
||||
|
|
|
@ -10,12 +10,12 @@ edit.applyRefactor({
|
|||
actionName: "Generate 'get' and 'set' accessors",
|
||||
actionDescription: "Generate 'get' and 'set' accessors",
|
||||
newContent: `class A {
|
||||
private /*RENAME*/__a: string;
|
||||
protected get _a(): string {
|
||||
return this.__a;
|
||||
private _a: string;
|
||||
protected get /*RENAME*/a_1(): string {
|
||||
return this._a;
|
||||
}
|
||||
protected set _a(value: string) {
|
||||
this.__a = value;
|
||||
protected set a_1(value: string) {
|
||||
this._a = value;
|
||||
}
|
||||
}`,
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue