Merge remote-tracking branch 'upstream/master'

This commit is contained in:
about-code 2017-01-03 14:07:51 +01:00
commit d78247a402
176 changed files with 1747 additions and 255 deletions

View file

@ -151,6 +151,7 @@ var servicesSources = [
"signatureHelp.ts",
"symbolDisplay.ts",
"transpile.ts",
// Formatting
"formatting/formatting.ts",
"formatting/formattingContext.ts",
"formatting/formattingRequestKind.ts",
@ -166,7 +167,18 @@ var servicesSources = [
"formatting/rulesMap.ts",
"formatting/rulesProvider.ts",
"formatting/smartIndenter.ts",
"formatting/tokenRange.ts"
"formatting/tokenRange.ts",
// CodeFixes
"codeFixProvider.ts",
"codefixes/fixes.ts",
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"codefixes/helpers.ts",
"codefixes/importFixes.ts",
"codefixes/unusedIdentifierFixes.ts"
].map(function (f) {
return path.join(servicesDirectory, f);
}));

View file

@ -79,9 +79,11 @@ namespace ts {
getDeclaredTypeOfSymbol,
getPropertiesOfType,
getPropertyOfType,
getIndexInfoOfType,
getSignaturesOfType,
getIndexTypeOfType,
getBaseTypes,
getTypeFromTypeNode,
getReturnTypeOfSignature,
getNonNullableType,
getSymbolsInScope,
@ -90,6 +92,7 @@ namespace ts {
getExportSpecifierLocalTargetSymbol,
getTypeAtLocation: getTypeOfNode,
getPropertySymbolOfDestructuringAssignment,
signatureToString,
typeToString,
getSymbolDisplayBuilder,
symbolToString,
@ -114,7 +117,8 @@ namespace ts {
// we deliberately exclude augmentations
// since we are only interested in declarations of the module itself
return tryFindAmbientModule(moduleName, /*withAugmentations*/ false);
}
},
getApparentType
};
const tupleTypes: GenericType[] = [];
@ -1368,7 +1372,9 @@ namespace ts {
return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol);
}
// Resolves a qualified name and any involved aliases
/**
* Resolves a qualified name and any involved aliases.
*/
function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined {
if (nodeIsMissing(name)) {
return undefined;
@ -2109,7 +2115,7 @@ namespace ts {
return result || types;
}
function visibilityToString(flags: ModifierFlags) {
function visibilityToString(flags: ModifierFlags): string | undefined {
if (flags === ModifierFlags.Private) {
return "private";
}
@ -2488,26 +2494,6 @@ namespace ts {
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags);
}
function writeIndexSignature(info: IndexInfo, keyword: SyntaxKind) {
if (info) {
if (info.isReadonly) {
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
writeSpace(writer);
}
writePunctuation(writer, SyntaxKind.OpenBracketToken);
writer.writeParameter(info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x");
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
writeKeyword(writer, keyword);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
writeType(info.type, TypeFormatFlags.None);
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
function writePropertyWithModifiers(prop: Symbol) {
if (isReadonlySymbol(prop)) {
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
@ -2595,8 +2581,8 @@ namespace ts {
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword);
writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword);
buildIndexSignatureDisplay(resolved.stringIndexInfo, writer, IndexKind.String, enclosingDeclaration, globalFlags, symbolStack);
buildIndexSignatureDisplay(resolved.numberIndexInfo, writer, IndexKind.Number, enclosingDeclaration, globalFlags, symbolStack);
for (const p of resolved.properties) {
const t = getTypeOfSymbol(p);
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) {
@ -2787,6 +2773,11 @@ namespace ts {
}
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
const returnType = getReturnTypeOfSignature(signature);
if (flags & TypeFormatFlags.SuppressAnyReturnType && isTypeAny(returnType)) {
return;
}
if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
writeSpace(writer);
writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
@ -2800,7 +2791,6 @@ namespace ts {
buildTypePredicateDisplay(signature.typePredicate, writer, enclosingDeclaration, flags, symbolStack);
}
else {
const returnType = getReturnTypeOfSignature(signature);
buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack);
}
}
@ -2825,6 +2815,34 @@ namespace ts {
buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack);
}
function buildIndexSignatureDisplay(info: IndexInfo, writer: SymbolWriter, kind: IndexKind, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
if (info) {
if (info.isReadonly) {
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
writeSpace(writer);
}
writePunctuation(writer, SyntaxKind.OpenBracketToken);
writer.writeParameter(info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x");
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
switch (kind) {
case IndexKind.Number:
writeKeyword(writer, SyntaxKind.NumberKeyword);
break;
case IndexKind.String:
writeKeyword(writer, SyntaxKind.StringKeyword);
break;
}
writePunctuation(writer, SyntaxKind.CloseBracketToken);
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
buildTypeDisplay(info.type, writer, enclosingDeclaration, globalFlags, symbolStack);
writePunctuation(writer, SyntaxKind.SemicolonToken);
writer.writeLine();
}
}
return _displayBuilder || (_displayBuilder = {
buildSymbolDisplay,
buildTypeDisplay,
@ -2835,6 +2853,7 @@ namespace ts {
buildDisplayForTypeParametersAndDelimiters,
buildTypeParameterDisplayFromSymbol,
buildSignatureDisplay,
buildIndexSignatureDisplay,
buildReturnTypeDisplay
});
}
@ -3786,11 +3805,13 @@ namespace ts {
return signatures;
}
// The base constructor of a class can resolve to
// undefinedType if the class has no extends clause,
// unknownType if an error occurred during resolution of the extends expression,
// nullType if the extends expression is the null value, or
// an object type with at least one construct signature.
/**
* The base constructor of a class can resolve to
* * undefinedType if the class has no extends clause,
* * unknownType if an error occurred during resolution of the extends expression,
* * nullType if the extends expression is the null value, or
* * an object type with at least one construct signature.
*/
function getBaseConstructorTypeOfClass(type: InterfaceType): Type {
if (!type.resolvedBaseConstructorType) {
const baseTypeNode = getBaseTypeNodeOfClass(type);
@ -4271,7 +4292,7 @@ namespace ts {
return <InterfaceTypeWithDeclaredMembers>type;
}
function getTypeWithThisArgument(type: Type, thisArgument?: Type) {
function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
if (getObjectFlags(type) & ObjectFlags.Reference) {
return createTypeReference((<TypeReference>type).target,
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
@ -4497,6 +4518,9 @@ namespace ts {
setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
}
/**
* Converts an AnonymousType to a ResolvedType.
*/
function resolveAnonymousTypeMembers(type: AnonymousType) {
const symbol = type.symbol;
if (type.target) {
@ -6629,17 +6653,19 @@ namespace ts {
const constraintType = getConstraintTypeFromMappedType(type);
if (constraintType.flags & TypeFlags.Index) {
const typeVariable = (<IndexType>constraintType).type;
const mappedTypeVariable = instantiateType(typeVariable, mapper);
if (typeVariable !== mappedTypeVariable) {
return mapType(mappedTypeVariable, t => {
if (isMappableType(t)) {
const replacementMapper = createUnaryTypeMapper(typeVariable, t);
const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper);
combinedMapper.mappedTypes = mapper.mappedTypes;
return instantiateMappedObjectType(type, combinedMapper);
}
return t;
});
if (typeVariable.flags & TypeFlags.TypeParameter) {
const mappedTypeVariable = instantiateType(typeVariable, mapper);
if (typeVariable !== mappedTypeVariable) {
return mapType(mappedTypeVariable, t => {
if (isMappableType(t)) {
const replacementMapper = createUnaryTypeMapper(typeVariable, t);
const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper);
combinedMapper.mappedTypes = mapper.mappedTypes;
return instantiateMappedObjectType(type, combinedMapper);
}
return t;
});
}
}
}
return instantiateMappedObjectType(type, mapper);
@ -7278,10 +7304,12 @@ namespace ts {
return false;
}
// Compare two types and return
// Ternary.True if they are related with no assumptions,
// Ternary.Maybe if they are related with assumptions of other relationships, or
// Ternary.False if they are not related.
/**
* Compare two types and return
* * Ternary.True if they are related with no assumptions,
* * Ternary.Maybe if they are related with assumptions of other relationships, or
* * Ternary.False if they are not related.
*/
function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
let result: Ternary;
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {

View file

@ -1060,7 +1060,7 @@ namespace ts {
}
}
function formatStringFromArgs(text: string, args: { [index: number]: string; }, baseIndex?: number): string {
export function formatStringFromArgs(text: string, args: { [index: number]: string; }, baseIndex?: number): string {
baseIndex = baseIndex || 0;
return text.replace(/{(\d+)}/g, (_match, index?) => args[+index + baseIndex]);

View file

@ -3243,23 +3243,19 @@
"category": "Message",
"code": 90002
},
"Change 'extends' to 'implements'": {
"Change 'extends' to 'implements'.": {
"category": "Message",
"code": 90003
},
"Remove unused identifiers": {
"Remove unused identifiers.": {
"category": "Message",
"code": 90004
},
"Implement interface on reference": {
"category": "Message",
"code": 90005
},
"Implement interface on class": {
"Implement interface '{0}'.": {
"category": "Message",
"code": 90006
},
"Implement inherited abstract class": {
"Implement inherited abstract class.": {
"category": "Message",
"code": 90007
},

View file

@ -640,9 +640,9 @@ namespace ts {
export interface ParameterDeclaration extends Declaration {
kind: SyntaxKind.Parameter;
dotDotDotToken?: DotDotDotToken; // Present on rest parameter
dotDotDotToken?: DotDotDotToken; // Present on rest parameter
name: BindingName; // Declared parameter name
questionToken?: QuestionToken; // Present on optional parameter
questionToken?: QuestionToken; // Present on optional parameter
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
@ -658,14 +658,14 @@ namespace ts {
export interface PropertySignature extends TypeElement {
kind: SyntaxKind.PropertySignature | SyntaxKind.JSDocRecordMember;
name: PropertyName; // Declared property name
questionToken?: QuestionToken; // Present on optional property
questionToken?: QuestionToken; // Present on optional property
type?: TypeNode; // Optional type annotation
initializer?: Expression; // Optional initializer
}
export interface PropertyDeclaration extends ClassElement {
kind: SyntaxKind.PropertyDeclaration;
questionToken?: QuestionToken; // Present for use with reporting a grammar error
questionToken?: QuestionToken; // Present for use with reporting a grammar error
name: PropertyName;
type?: TypeNode;
initializer?: Expression; // Optional initializer
@ -2334,6 +2334,7 @@ namespace ts {
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
getPropertiesOfType(type: Type): Symbol[];
getPropertyOfType(type: Type, propertyName: string): Symbol;
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo;
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
getBaseTypes(type: InterfaceType): ObjectType[];
@ -2347,6 +2348,8 @@ namespace ts {
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol;
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol;
getTypeAtLocation(node: Node): Type;
getTypeFromTypeNode(node: TypeNode): Type;
signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
getSymbolDisplayBuilder(): SymbolDisplayBuilder;
@ -2372,6 +2375,7 @@ namespace ts {
getAmbientModules(): Symbol[];
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
/* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol;
@ -2390,6 +2394,7 @@ namespace ts {
buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void;
buildIndexSignatureDisplay(info: IndexInfo, writer: SymbolWriter, kind: IndexKind, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]): void;
buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
@ -2433,6 +2438,7 @@ namespace ts {
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
InTypeAlias = 0x00000200, // Writing type in type alias declaration
UseTypeAliasValue = 0x00000400, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
}
export const enum SymbolFormatFlags {
@ -2865,7 +2871,7 @@ namespace ts {
objectFlags: ObjectFlags;
}
// Class and interface types (TypeFlags.Class and TypeFlags.Interface)
/** Class and interface types (TypeFlags.Class and TypeFlags.Interface). */
export interface InterfaceType extends ObjectType {
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none)
@ -2885,14 +2891,16 @@ namespace ts {
declaredNumberIndexInfo: IndexInfo; // Declared numeric indexing info
}
// Type references (TypeFlags.Reference). When a class or interface has type parameters or
// a "this" type, references to the class or interface are made using type references. The
// typeArguments property specifies the types to substitute for the type parameters of the
// class or interface and optionally includes an extra element that specifies the type to
// substitute for "this" in the resulting instantiation. When no extra argument is present,
// the type reference itself is substituted for "this". The typeArguments property is undefined
// if the class or interface has no type parameters and the reference isn't specifying an
// explicit "this" argument.
/**
* Type references (TypeFlags.Reference). When a class or interface has type parameters or
* a "this" type, references to the class or interface are made using type references. The
* typeArguments property specifies the types to substitute for the type parameters of the
* class or interface and optionally includes an extra element that specifies the type to
* substitute for "this" in the resulting instantiation. When no extra argument is present,
* the type reference itself is substituted for "this". The typeArguments property is undefined
* if the class or interface has no type parameters and the reference isn't specifying an
* explicit "this" argument.
*/
export interface TypeReference extends ObjectType {
target: GenericType; // Type reference target
typeArguments: Type[]; // Type reference type arguments (undefined if none)

View file

@ -1830,7 +1830,7 @@ namespace ts {
}
}
export function getAncestor(node: Node, kind: SyntaxKind): Node {
export function getAncestor(node: Node | undefined, kind: SyntaxKind): Node {
while (node) {
if (node.kind === kind) {
return node;

View file

@ -44,6 +44,14 @@ namespace FourSlash {
markers: Marker[];
/**
* Inserted in source files by surrounding desired text
* in a range with `[|` and `|]`. For example,
*
* [|text in range|]
*
* is a range with `text in range` "selected".
*/
ranges: Range[];
}
@ -1533,7 +1541,8 @@ namespace FourSlash {
let runningOffset = 0;
edits = edits.sort((a, b) => a.span.start - b.span.start);
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
const oldContent = this.getFileContent(this.activeFile.fileName);
const oldContent = this.getFileContent(fileName);
for (const edit of edits) {
this.languageServiceAdapterHost.editScript(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
this.updateMarkersForEdit(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
@ -1970,54 +1979,93 @@ namespace FourSlash {
});
}
private getCodeFixes(errorCode?: number) {
const fileName = this.activeFile.fileName;
const diagnostics = this.getDiagnostics(fileName);
if (diagnostics.length === 0) {
this.raiseError("Errors expected.");
}
if (diagnostics.length > 1 && errorCode === undefined) {
this.raiseError("When there's more than one error, you must specify the errror to fix.");
}
const diagnostic = !errorCode ? diagnostics[0] : ts.find(diagnostics, d => d.code == errorCode);
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.start + diagnostic.length, [diagnostic.code]);
}
public verifyCodeFixAtPosition(expectedText: string, errorCode?: number) {
/**
* Compares expected text to the text that would be in the sole range
* (ie: [|...|]) in the file after applying the codefix sole codefix
* in the source file.
*
* Because codefixes are only applied on the working file, it is unsafe
* to apply this more than once (consider a refactoring across files).
*/
public verifyRangeAfterCodeFix(expectedText: string, errorCode?: number) {
const ranges = this.getRanges();
if (ranges.length == 0) {
this.raiseError("At least one range should be specified in the testfile.");
if (ranges.length !== 1) {
this.raiseError("Exactly one range should be specified in the testfile.");
}
const actual = this.getCodeFixes(errorCode);
const fileName = this.activeFile.fileName;
if (!actual || actual.length == 0) {
this.raiseError("No codefixes returned.");
}
this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName, errorCode));
if (actual.length > 1) {
this.raiseError("More than 1 codefix returned.");
}
this.applyEdits(actual[0].changes[0].fileName, actual[0].changes[0].textChanges, /*isFormattingEdit*/ false);
const actualText = this.rangeText(ranges[0]);
if (this.removeWhitespace(actualText) !== this.removeWhitespace(expectedText)) {
this.raiseError(`Actual text doesn't match expected text. Actual: '${actualText}' Expected: '${expectedText}'`);
this.raiseError(`Actual text doesn't match expected text. Actual:\n'${actualText}'\nExpected:\n'${expectedText}'`);
}
}
/**
* Applies fixes for the errors in fileName and compares the results to
* expectedContents after all fixes have been applied.
* Note: applying one codefix may generate another (eg: remove duplicate implements
* may generate an extends -> interface conversion fix).
* @param expectedContents The contents of the file after the fixes are applied.
* @param fileName The file to check. If not supplied, the current open file is used.
*/
public verifyFileAfterCodeFix(expectedContents: string, fileName?: string) {
fileName = fileName ? fileName : this.activeFile.fileName;
this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName));
const actualContents: string = this.getFileContent(fileName);
if (this.removeWhitespace(actualContents) !== this.removeWhitespace(expectedContents)) {
this.raiseError(`Actual text doesn't match expected text. Actual:\n${actualContents}\n\nExpected:\n${expectedContents}`);
}
}
/**
* Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found.
* @param fileName Path to file where error should be retrieved from.
*/
private getCodeFixActions(fileName: string, errorCode?: number): ts.CodeAction[] {
const diagnostics: ts.Diagnostic[] = this.getDiagnostics(fileName);
let actions: ts.CodeAction[] = undefined;
for (const diagnostic of diagnostics) {
if (errorCode && errorCode !== diagnostic.code) {
continue;
}
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code]);
if (newActions && newActions.length) {
actions = actions ? actions.concat(newActions) : newActions;
}
}
return actions;
}
private applyCodeFixActions(fileName: string, actions: ts.CodeAction[]): void {
if (!(actions && actions.length === 1)) {
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`);
}
const fileChanges = ts.find(actions[0].changes, change => change.fileName === fileName);
if (!fileChanges) {
this.raiseError("The CodeFix found doesn't provide any changes in this file.");
}
this.applyEdits(fileChanges.fileName, fileChanges.textChanges, /*isFormattingEdit*/ false);
}
public verifyImportFixAtPosition(expectedTextArray: string[], errorCode?: number) {
const ranges = this.getRanges();
if (ranges.length == 0) {
this.raiseError("At least one range should be specified in the testfile.");
}
const codeFixes = this.getCodeFixes(errorCode);
const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode);
if (!codeFixes || codeFixes.length == 0) {
this.raiseError("No codefixes returned.");
@ -2315,15 +2363,15 @@ namespace FourSlash {
}
}
public verifyCodeFixAvailable(negative: boolean, errorCode?: number) {
const fixes = this.getCodeFixes(errorCode);
public verifyCodeFixAvailable(negative: boolean) {
const codeFix = this.getCodeFixActions(this.activeFile.fileName);
if (negative && fixes && fixes.length > 0) {
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes, actual: ${fixes.length}`);
if (negative && codeFix) {
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`);
}
if (!negative && (fixes === undefined || fixes.length === 0)) {
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes, actual: 0`);
if (!(negative || codeFix)) {
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes but none found.`);
}
}
@ -3095,8 +3143,8 @@ namespace FourSlashInterface {
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
}
public codeFixAvailable(errorCode?: number) {
this.state.verifyCodeFixAvailable(this.negative, errorCode);
public codeFixAvailable() {
this.state.verifyCodeFixAvailable(this.negative);
}
}
@ -3281,8 +3329,8 @@ namespace FourSlashInterface {
this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true);
}
public codeFixAtPosition(expectedText: string, errorCode?: number): void {
this.state.verifyCodeFixAtPosition(expectedText, errorCode);
public rangeAfterCodeFix(expectedText: string, errorCode?: number): void {
this.state.verifyRangeAfterCodeFix(expectedText, errorCode);
}
public importFixAtPosition(expectedTextArray: string[], errorCode?: number): void {

View file

@ -74,7 +74,18 @@
"../services/formatting/rulesProvider.ts",
"../services/formatting/smartIndenter.ts",
"../services/formatting/tokenRange.ts",
"harness.ts",
"../services/codeFixProvider.ts",
"../services/codefixes/fixes.ts",
"../services/codefixes/fixExtendsInterfaceBecomesImplements.ts",
"../services/codefixes/fixClassIncorrectlyImplementsInterface.ts",
"../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"../services/codefixes/helpers.ts",
"../services/codefixes/importFixes.ts",
"../services/codefixes/unusedIdentifierFixes.ts",
"../services/harness.ts",
"sourceMapRecorder.ts",
"harnessLanguageService.ts",
"fourslash.ts",

3
src/lib/es5.d.ts vendored
View file

@ -1171,8 +1171,9 @@ interface Array<T> {
/**
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
* @param start The zero-based location in the array from which to start removing elements.
* @param deleteCount The number of elements to remove.
*/
splice(start: number): T[];
splice(start: number, deleteCount?: number): T[];
/**
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
* @param start The zero-based location in the array from which to start removing elements.

View file

@ -0,0 +1,59 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code],
getCodeActions: getActionForClassLikeMissingAbstractMember
});
registerCodeFix({
errorCodes: [Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1.code],
getCodeActions: getActionForClassLikeMissingAbstractMember
});
function getActionForClassLikeMissingAbstractMember(context: CodeFixContext): CodeAction[] | undefined {
const sourceFile = context.sourceFile;
const start = context.span.start;
// This is the identifier in the case of a class declaration
// or the class keyword token in the case of a class expression.
const token = getTokenAtPosition(sourceFile, start);
const checker = context.program.getTypeChecker();
if (isClassLike(token.parent)) {
const classDecl = token.parent as ClassLikeDeclaration;
const startPos = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
const instantiatedExtendsType = checker.getBaseTypes(classType)[0];
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
const extendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType);
const abstractAndNonPrivateExtendsSymbols = extendsSymbols.filter(symbolPointsToNonPrivateAndAbstractMember);
const insertion = getMissingMembersInsertion(classDecl, abstractAndNonPrivateExtendsSymbols, checker, context.newLineCharacter);
if (insertion.length) {
return [{
description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: startPos, length: 0 },
newText: insertion
}]
}]
}];
}
}
return undefined;
}
function symbolPointsToNonPrivateAndAbstractMember(symbol: Symbol): boolean {
const decls = symbol.getDeclarations();
Debug.assert(!!(decls && decls.length > 0));
const flags = getModifierFlags(decls[0]);
return !(flags & ModifierFlags.Private) && !!(flags & ModifierFlags.Abstract);
}
}

View file

@ -0,0 +1,75 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code],
getCodeActions: getActionForClassLikeIncorrectImplementsInterface
});
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 classDecl = getContainingClass(token);
if (!classDecl) {
return undefined;
}
const startPos: number = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl);
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
const result: CodeAction[] = [];
for (const implementedTypeNode of implementedTypeNodes) {
const implementedType = checker.getTypeFromTypeNode(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(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private));
let insertion = getMissingIndexSignatureInsertion(implementedType, IndexKind.Number, classDecl, hasNumericIndexSignature);
insertion += getMissingIndexSignatureInsertion(implementedType, IndexKind.String, classDecl, hasStringIndexSignature);
insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
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) {
const writer = getSingleLineStringWriter();
checker.getSymbolDisplayBuilder().buildIndexSignatureDisplay(IndexInfoOfKind, writer, kind, enclosingDeclaration);
const result = writer.string();
releaseStringWriter(writer);
return result;
}
}
return "";
}
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);
}
}
}

View file

@ -1,28 +1,5 @@
/* @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({
errorCodes: [Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call.code],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const token = getTokenAtPosition(sourceFile, context.span.start);
if (token.kind !== SyntaxKind.ConstructorKeyword) {
return undefined;
}
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({
errorCodes: [Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class.code],
getCodeActions: (context: CodeFixContext) => {

View file

@ -0,0 +1,20 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call.code],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const token = getTokenAtPosition(sourceFile, context.span.start);
if (token.kind !== SyntaxKind.ConstructorKeyword) {
return undefined;
}
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 } }] }]
}];
}
});
}

View file

@ -0,0 +1,49 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: [Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements.code],
getCodeActions: (context: CodeFixContext) => {
const sourceFile = context.sourceFile;
const start = context.span.start;
const token = getTokenAtPosition(sourceFile, start);
const classDeclNode = getContainingClass(token);
if (!(token.kind === SyntaxKind.Identifier && isClassLike(classDeclNode))) {
return undefined;
}
const heritageClauses = classDeclNode.heritageClauses;
if (!(heritageClauses && heritageClauses.length > 0)) {
return undefined;
}
const extendsToken = heritageClauses[0].getFirstToken();
if (!(extendsToken && extendsToken.kind === SyntaxKind.ExtendsKeyword)) {
return undefined;
}
let changeStart = extendsToken.getStart(sourceFile);
let changeEnd = extendsToken.getEnd();
const textChanges: TextChange[] = [{ newText: " implements", span: { start: changeStart, length: changeEnd - changeStart } }];
// We replace existing keywords with commas.
for (let i = 1; i < heritageClauses.length; i++) {
const keywordToken = heritageClauses[i].getFirstToken();
if (keywordToken) {
changeStart = keywordToken.getStart(sourceFile);
changeEnd = keywordToken.getEnd();
textChanges.push({ newText: ",", span: { start: changeStart, length: changeEnd - changeStart } });
}
}
const result = [{
description: getLocaleSpecificMessage(Diagnostics.Change_extends_to_implements),
changes: [{
fileName: sourceFile.fileName,
textChanges: textChanges
}]
}];
return result;
}
});
}

View file

@ -1,3 +1,9 @@
///<reference path='superFixes.ts' />
///<reference path='importFixes.ts' />
///<reference path='unusedIdentifierFixes.ts' />
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
/// <reference path="fixClassDoesntImplementInheritedAbstractMember.ts" />
/// <reference path="fixClassSuperMustPrecedeThisAccess.ts" />
/// <reference path="fixConstructorForDerivedNeedSuperCall.ts" />
/// <reference path="fixExtendsInterfaceBecomesImplements.ts" />
/// <reference path='unusedIdentifierFixes.ts' />
/// <reference path='importFixes.ts' />
/// <reference path='helpers.ts' />

View file

@ -0,0 +1,156 @@
/* @internal */
namespace ts.codefix {
/**
* Finds members of the resolved type that are missing in the class pointed to by class decl
* and generates source code for the missing members.
* @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for.
* @returns Empty string iff there are no member insertions.
*/
export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string {
const classMembers = classDeclaration.symbol.members;
const missingMembers = possiblyMissingSymbols.filter(symbol => !(symbol.getName() in classMembers));
let insertion = "";
for (const symbol of missingMembers) {
insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar));
}
return insertion;
}
/**
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
*/
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
// const name = symbol.getName();
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
const declarations = symbol.getDeclarations();
if (!(declarations && declarations.length)) {
return "";
}
const declaration = declarations[0] as Declaration;
const name = declaration.name ? declaration.name.getText() : undefined;
const visibility = getVisibilityPrefix(getModifierFlags(declaration));
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None);
return `${visibility}${name}: ${typeString};${newlineChar}`;
case SyntaxKind.MethodSignature:
case SyntaxKind.MethodDeclaration:
// The signature for the implementation appears as an entry in `signatures` iff
// there is only one signature.
// If there are overloads and an implementation signature, it appears as an
// extra declaration that isn't a signature for `type`.
// If there is more than one overload but no implementation signature
// (eg: an abstract method or interface declaration), there is a 1-1
// correspondence of declarations and signatures.
const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
if (!(signatures && signatures.length > 0)) {
return "";
}
if (declarations.length === 1) {
Debug.assert(signatures.length === 1);
const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
}
let result = "";
for (let i = 0; i < signatures.length; i++) {
const sigString = checker.signatureToString(signatures[i], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
result += `${visibility}${name}${sigString};${newlineChar}`;
}
// If there is a declaration with a body, it is the last declaration,
// and it isn't caught by `getSignaturesOfType`.
let bodySig: Signature | undefined = undefined;
if (declarations.length > signatures.length) {
bodySig = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
}
else {
Debug.assert(declarations.length === signatures.length);
bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker);
}
const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
return result;
default:
return "";
}
}
function createBodySignatureWithAnyTypes(signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
const newSignatureDeclaration = createNode(SyntaxKind.CallSignature) as SignatureDeclaration;
newSignatureDeclaration.parent = enclosingDeclaration;
newSignatureDeclaration.name = signatures[0].getDeclaration().name;
let maxNonRestArgs = -1;
let maxArgsIndex = 0;
let minArgumentCount = signatures[0].minArgumentCount;
let hasRestParameter = false;
for (let i = 0; i < signatures.length; i++) {
const sig = signatures[i];
minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount);
hasRestParameter = hasRestParameter || sig.hasRestParameter;
const nonRestLength = sig.parameters.length - (sig.hasRestParameter ? 1 : 0);
if (nonRestLength > maxNonRestArgs) {
maxNonRestArgs = nonRestLength;
maxArgsIndex = i;
}
}
const maxArgsParameterSymbolNames = signatures[maxArgsIndex].getParameters().map(symbol => symbol.getName());
const optionalToken = createToken(SyntaxKind.QuestionToken);
newSignatureDeclaration.parameters = createNodeArray<ParameterDeclaration>();
for (let i = 0; i < maxNonRestArgs; i++) {
const newParameter = createParameterDeclarationWithoutType(i, minArgumentCount, newSignatureDeclaration);
newSignatureDeclaration.parameters.push(newParameter);
}
if (hasRestParameter) {
const restParameter = createParameterDeclarationWithoutType(maxNonRestArgs, minArgumentCount, newSignatureDeclaration);
restParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken);
newSignatureDeclaration.parameters.push(restParameter);
}
return checker.getSignatureFromDeclaration(newSignatureDeclaration);
function createParameterDeclarationWithoutType(index: number, minArgCount: number, enclosingSignatureDeclaration: SignatureDeclaration): ParameterDeclaration {
const newParameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration;
newParameter.symbol = new SymbolConstructor(SymbolFlags.FunctionScopedVariable, maxArgsParameterSymbolNames[index] || "rest");
newParameter.symbol.valueDeclaration = newParameter;
newParameter.symbol.declarations = [newParameter];
newParameter.parent = enclosingSignatureDeclaration;
if (index >= minArgCount) {
newParameter.questionToken = optionalToken;
}
return newParameter;
}
}
function getMethodBodyStub(newLineChar: string) {
return ` {${newLineChar}throw new Error('Method not implemented.');${newLineChar}}${newLineChar}`;
}
function getVisibilityPrefix(flags: ModifierFlags): string {
if (flags & ModifierFlags.Public) {
return "public ";
}
else if (flags & ModifierFlags.Protected) {
return "protected ";
}
return "";
}
const SymbolConstructor = objectAllocator.getSymbolConstructor();
}

View file

@ -244,6 +244,9 @@ namespace ts.Completions {
}
function addStringLiteralCompletionsFromType(type: Type, result: CompletionEntry[]): void {
if (type && type.flags & TypeFlags.TypeParameter) {
type = typeChecker.getApparentType(type);
}
if (!type) {
return;
}

View file

@ -24,7 +24,7 @@
/// <reference path='transpile.ts' />
/// <reference path='formatting\formatting.ts' />
/// <reference path='formatting\smartIndenter.ts' />
/// <reference path='codefixes\codeFixProvider.ts' />
/// <reference path='codeFixProvider.ts' />
/// <reference path='codefixes\fixes.ts' />
namespace ts {

View file

@ -87,7 +87,15 @@
"formatting/rulesProvider.ts",
"formatting/smartIndenter.ts",
"formatting/tokenRange.ts",
"codeFixes/codeFixProvider.ts",
"codeFixes/fixes.ts"
"codeFixProvider.ts",
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"codefixes/fixes.ts",
"codefixes/helpers.ts",
"codefixes/importFixes.ts",
"codefixes/unusedIdentifierFixes.ts"
]
}
}

View file

@ -1358,4 +1358,9 @@ namespace ts {
diagnostics: error ? concatenate(diagnostics, [error]) : diagnostics
};
}
}
export 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();
}
}

View file

@ -0,0 +1,8 @@
//// [arraySlice.ts]
var arr: string[] | number[];
arr.splice(1, 1);
//// [arraySlice.js]
var arr;
arr.splice(1, 1);

View file

@ -0,0 +1,9 @@
=== tests/cases/compiler/arraySlice.ts ===
var arr: string[] | number[];
>arr : Symbol(arr, Decl(arraySlice.ts, 0, 3))
arr.splice(1, 1);
>arr.splice : Symbol(splice, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
>arr : Symbol(arr, Decl(arraySlice.ts, 0, 3))
>splice : Symbol(splice, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))

View file

@ -0,0 +1,12 @@
=== tests/cases/compiler/arraySlice.ts ===
var arr: string[] | number[];
>arr : string[] | number[]
arr.splice(1, 1);
>arr.splice(1, 1) : string[] | number[]
>arr.splice : { (start: number, deleteCount?: number): string[]; (start: number, deleteCount: number, ...items: string[]): string[]; } | { (start: number, deleteCount?: number): number[]; (start: number, deleteCount: number, ...items: number[]): number[]; }
>arr : string[] | number[]
>splice : { (start: number, deleteCount?: number): string[]; (start: number, deleteCount: number, ...items: string[]): string[]; } | { (start: number, deleteCount?: number): number[]; (start: number, deleteCount: number, ...items: number[]): number[]; }
>1 : 1
>1 : 1

View file

@ -2,9 +2,9 @@
var arr = [].splice(0,3,4,5);
>arr : any[]
>[].splice(0,3,4,5) : any[]
>[].splice : { (start: number): any[]; (start: number, deleteCount: number, ...items: any[]): any[]; }
>[].splice : { (start: number, deleteCount?: number): any[]; (start: number, deleteCount: number, ...items: any[]): any[]; }
>[] : undefined[]
>splice : { (start: number): any[]; (start: number, deleteCount: number, ...items: any[]): any[]; }
>splice : { (start: number, deleteCount?: number): any[]; (start: number, deleteCount: number, ...items: any[]): any[]; }
>0 : 0
>3 : 3
>4 : 4

View file

@ -58,7 +58,19 @@ type DeepReadonlyFoo = {
};
var x1: DeepReadonly<Foo>;
var x1: DeepReadonlyFoo;
var x1: DeepReadonlyFoo;
// Repro from #13232
type Z = { a: number };
type Clone<T> = {
[P in keyof (T & {})]: T[P];
};
type M = Clone<Z>; // M should be { a: number }
var z1: Z;
var z1: Clone<Z>;
//// [mappedTypes4.js]
function boxify(obj) {
@ -76,6 +88,8 @@ function f1(x) {
}
var x1;
var x1;
var z1;
var z1;
//// [mappedTypes4.d.ts]
@ -127,3 +141,12 @@ declare type DeepReadonlyFoo = {
};
declare var x1: DeepReadonly<Foo>;
declare var x1: DeepReadonlyFoo;
declare type Z = {
a: number;
};
declare type Clone<T> = {
[P in keyof (T & {})]: T[P];
};
declare type M = Clone<Z>;
declare var z1: Z;
declare var z1: Clone<Z>;

View file

@ -196,3 +196,34 @@ var x1: DeepReadonlyFoo;
>x1 : Symbol(x1, Decl(mappedTypes4.ts, 58, 3), Decl(mappedTypes4.ts, 59, 3))
>DeepReadonlyFoo : Symbol(DeepReadonlyFoo, Decl(mappedTypes4.ts, 50, 2))
// Repro from #13232
type Z = { a: number };
>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24))
>a : Symbol(a, Decl(mappedTypes4.ts, 63, 10))
type Clone<T> = {
>Clone : Symbol(Clone, Decl(mappedTypes4.ts, 63, 23))
>T : Symbol(T, Decl(mappedTypes4.ts, 64, 11))
[P in keyof (T & {})]: T[P];
>P : Symbol(P, Decl(mappedTypes4.ts, 65, 3))
>T : Symbol(T, Decl(mappedTypes4.ts, 64, 11))
>T : Symbol(T, Decl(mappedTypes4.ts, 64, 11))
>P : Symbol(P, Decl(mappedTypes4.ts, 65, 3))
};
type M = Clone<Z>; // M should be { a: number }
>M : Symbol(M, Decl(mappedTypes4.ts, 66, 2))
>Clone : Symbol(Clone, Decl(mappedTypes4.ts, 63, 23))
>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24))
var z1: Z;
>z1 : Symbol(z1, Decl(mappedTypes4.ts, 69, 3), Decl(mappedTypes4.ts, 70, 3))
>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24))
var z1: Clone<Z>;
>z1 : Symbol(z1, Decl(mappedTypes4.ts, 69, 3), Decl(mappedTypes4.ts, 70, 3))
>Clone : Symbol(Clone, Decl(mappedTypes4.ts, 63, 23))
>Z : Symbol(Z, Decl(mappedTypes4.ts, 59, 24))

View file

@ -211,3 +211,34 @@ var x1: DeepReadonlyFoo;
>x1 : DeepReadonly<Foo>
>DeepReadonlyFoo : DeepReadonlyFoo
// Repro from #13232
type Z = { a: number };
>Z : Z
>a : number
type Clone<T> = {
>Clone : Clone<T>
>T : T
[P in keyof (T & {})]: T[P];
>P : P
>T : T
>T : T
>P : P
};
type M = Clone<Z>; // M should be { a: number }
>M : Clone<Z>
>Clone : Clone<T>
>Z : Z
var z1: Z;
>z1 : Z
>Z : Z
var z1: Clone<Z>;
>z1 : Z
>Clone : Clone<T>
>Z : Z

View file

@ -364,9 +364,9 @@ class ListWrapper {
>value : T
>T : T
>list.splice(index, 0, value) : T[]
>list.splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list.splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list : T[]
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>index : number
>0 : 0
>value : T
@ -389,9 +389,9 @@ class ListWrapper {
list.splice(index, 1);
>list.splice(index, 1) : T[]
>list.splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list.splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list : T[]
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>index : number
>1 : 1
@ -431,9 +431,9 @@ class ListWrapper {
list.splice(index, 1);
>list.splice(index, 1) : T[]
>list.splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list.splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list : T[]
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>index : number
>1 : 1
}
@ -464,9 +464,9 @@ class ListWrapper {
list.splice(index, 1);
>list.splice(index, 1) : T[]
>list.splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list.splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>list : T[]
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>index : number
>1 : 1
@ -603,9 +603,9 @@ class ListWrapper {
>length : number
>T : T
>l.splice(from, length) : T[]
>l.splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>l.splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>l : T[]
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>splice : { (start: number, deleteCount?: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>from : number
>length : number

View file

@ -0,0 +1,2 @@
var arr: string[] | number[];
arr.splice(1, 1);

View file

@ -59,4 +59,15 @@ type DeepReadonlyFoo = {
};
var x1: DeepReadonly<Foo>;
var x1: DeepReadonlyFoo;
var x1: DeepReadonlyFoo;
// Repro from #13232
type Z = { a: number };
type Clone<T> = {
[P in keyof (T & {})]: T[P];
};
type M = Clone<Z>; // M should be { a: number }
var z1: Z;
var z1: Clone<Z>;

View file

@ -0,0 +1,6 @@
/// <reference path='fourslash.ts' />
//// interface I {}
//// [|/* */ class /* */ C /* */ extends /* */ I|]{}
verify.rangeAfterCodeFix("/* */ class /* */ C /* */ implements /* */ I");

View file

@ -0,0 +1,8 @@
/// <reference path='fourslash.ts' />
//// interface I1 { }
//// interface I2 { }
//// [|abstract class A extends I1 implements I2|] { }
verify.rangeAfterCodeFix("abstract class A implements I1, I2");

View file

@ -0,0 +1,6 @@
/// <reference path='fourslash.ts' />
////interface I<X> { x: X}
////[|class C<T extends string , U> extends I<T>|]{}
verify.rangeAfterCodeFix("class C<T extends string , U> implements I<T>");

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// interface I1 { }
//// interface I2 { }
//// function sealed(constructor: Function) {
//// Object.seal(constructor);
//// Object.seal(constructor.prototype);
//// }
//// @sealed
//// [|class A extends I1 implements I2 { }|]
verify.rangeAfterCodeFix("class A implements I1, I2 { }");

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// class A {
//// f() {}
//// }
////
//// let B = class implements A {[| |]}
verify.rangeAfterCodeFix(`
f(): void{
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// function foo<T>(a: T) {
//// abstract class C<U> {
//// abstract a: T | U;
//// }
//// return C;
//// }
////
//// let B = class extends foo("s")<number> {[| |]}
verify.rangeAfterCodeFix(`
a: string | number;
`);

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// function foo<T>(a: T) {
//// abstract class C<U> {
//// abstract a: T | U;
//// }
//// return C;
//// }
////
//// class B extends foo("s")<number> {[| |]}
verify.rangeAfterCodeFix(`
a: string | number;
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract get b(): number;
//// }
////
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
b: number;
`);

View file

@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// private _a: string;
////
//// abstract get a(): string;
//// abstract set a(newName: string);
//// }
////
//// // Don't need to add anything in this case.
//// abstract class B extends A {}
////
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
a: string;
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract f(a: number, b: string): boolean;
//// abstract f(a: string, b: number): Function;
//// abstract f(a: string): Function;
//// }
////
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
f(a: number, b: string): boolean;
f(a: string, b: number): Function;
f(a: string): Function;
f(a: any, b?: any) {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// abstract class A<T> {
//// abstract f(x: T): T;
//// }
////
//// class C extends A<number> {[|
//// |]}
verify.rangeAfterCodeFix(`f(x: number): number{
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// abstract class A<T> {
//// abstract f(x: T): T;
//// }
////
//// class C<U> extends A<U> {[|
//// |]}
verify.rangeAfterCodeFix(`f(x: U): U{
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,15 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// private abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
// We don't know how to fix this problem. We can:
// 1) Make x protected, and then insert.
// 2) Make x private, and then insert.
// 3) Make x not abstract.
// So we offer no fixes.
verify.not.codeFixAvailable();

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
verify.rangeAfterCodeFix(`
x: number;
`);

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// protected abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
verify.rangeAfterCodeFix(`
protected x: number;
`);

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// public abstract x: number;
//// }
////
//// class C extends A {[|
//// |]}
verify.rangeAfterCodeFix(`
public x: number;
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract set c(arg: number | string);
//// }
////
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
c: string | number;
`);

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract x: number;
//// abstract y: number;
//// abstract z: number;
//// }
////
//// class C extends A {[| |]
//// constructor(public x: number) { super(); }
//// y: number;
//// }
verify.rangeAfterCodeFix(`
z: number;
`);

View file

@ -0,0 +1,20 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// private _a: string;
////
//// abstract get a(): string;
//// abstract set a(newName: string);
////
//// abstract get b(): number;
////
//// abstract set c(arg: number | string);
//// }
////
//// class C implements A {[| |]}
verify.rangeAfterCodeFix(`
a: string;
b: number;
c: string | number;
`);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// class A {
//// f() {}
//// }
////
//// class B implements A {[| |]}
verify.rangeAfterCodeFix(`
f(): void{
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// class C1 {
//// f1() {}
//// }
////
//// class C2 extends C1 {
////
//// }
////
//// class C3 implements C2 {[|
//// |]f2(){}
//// }
verify.rangeAfterCodeFix(`f1(): void{
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// class A {
//// method(a: number, b: string): boolean;
//// method(a: string | number, b?: string | number): boolean | Function { return true; }
////
//// class C implements A {[| |]}
verify.rangeAfterCodeFix(`
method(a: number, b: string): boolean;
method(a: string | number, b?: string | number): boolean | Function {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// class A {
//// method(a: any, b: string): boolean;
//// method(a: string, b: number): Function;
//// method(a: string): Function;
//// method(a: string | number, b?: string | number): boolean | Function { return true; }
////
//// class C implements A {[| |]}
verify.rangeAfterCodeFix(`
method(a: any, b: string): boolean;
method(a: string, b: number): Function;
method(a: string): Function;
method(a: string | number, b?: string | number): boolean | Function {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract x: number;
//// private y: number;
//// protected z: number;
//// public w: number;
//// }
////
//// class C implements A {[| |]}
verify.rangeAfterCodeFix(`
x: number;
protected z: number;
public w: number;
`);

View file

@ -0,0 +1,63 @@
/// <reference path='fourslash.ts' />
//// // Referenced throughout the inheritance chain.
//// interface I0 { a: number }
////
//// class C1 implements I0 { a: number }
//// interface I1 { b: number }
//// interface I2 extends C1, I1 {}
////
//// class C2 { c: number }
//// interface I3 {d: number}
//// class C3 extends C2 implements I0, I2, I3 {
//// a: number;
//// b: number;
//// d: number;
//// }
////
//// interface I4 { e: number }
//// interface I5 { f: number }
//// class C4 extends C3 implements I0, I4, I5 {
//// e: number;
//// f: number;
//// }
////
//// interface I6 extends C4 {}
//// class C5 implements I6 {[|
//// |]}
/**
* We want to check whether the search for member to replace actually searches through
* the various possible paths of the inheritance chain correctly, and that We
* don't issue duplicates for the same member.
*
* Our class DAG:
*
* C5
* |-I6
* |-C4
* |-I4
* |-I5
* |------------------------ I0
* |-C3
* |-I2
* |-I1
* |-C1
* |-------------------I0
* |-I3
* |-----------------------I0
* |-C2
*/
verify.rangeAfterCodeFix(
`
e: number;
f: number;
a: number;
b: number;
d: number;
c: number;
`);

View file

@ -0,0 +1,9 @@
/// <reference path='fourslash.ts' />
//// interface I { x: number; }
////
//// export default class implements I {[| |]}
verify.rangeAfterCodeFix(`
x: number;
`);

View file

@ -0,0 +1,20 @@
/// <reference path='fourslash.ts' />
//// abstract class C1 {
////
//// }
////
//// abstract class C2 {
//// abstract f1<T extends number>();
//// }
////
//// interface I1 extends C1, C2 {}
////
//// class C3 implements I1 {[|
////
//// |]}
verify.rangeAfterCodeFix(`f1<T extends number>(){
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// namespace N1 {
//// export interface I1 {
//// f1():string;
//// }
//// }
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
verify.rangeAfterCodeFix(`f1(): string{
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
//// interface I { x: number; }
////
//// new class implements I {[| |]};
verify.rangeAfterCodeFix(`
x: number;
`);

View file

@ -0,0 +1,21 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// ["foo"](o: any): boolean;
//// ["x"]: boolean;
//// [1](): string;
//// [2]: boolean;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
[1](): string {
throw new Error('Method not implemented.');
}
[2]: boolean;
["foo"](o: any): boolean {
throw new Error('Method not implemented.');
}
["x"]: boolean;
`);

View file

@ -0,0 +1,52 @@
/// <reference path='fourslash.ts' />
// @lib: es2017
//// interface I<Species> {
//// [Symbol.hasInstance](o: any): boolean;
//// [Symbol.isConcatSpreadable]: boolean;
//// [Symbol.iterator](): any;
//// [Symbol.match]: boolean;
//// [Symbol.replace](...args);
//// [Symbol.search](str: string): number;
//// [Symbol.species](): Species;
//// [Symbol.split](str: string, limit?: number): string[];
//// [Symbol.toPrimitive](hint: "number"): number;
//// [Symbol.toPrimitive](hint: "default"): number;
//// [Symbol.toPrimitive](hint: "string"): string;
//// [Symbol.toStringTag]: string;
//// [Symbol.unscopables]: any;
//// }
////
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
[Symbol.hasInstance](o: any): boolean {
throw new Error('Method not implemented.');
}
[Symbol.isConcatSpreadable]: boolean;
[Symbol.iterator]() {
throw new Error('Method not implemented.');
}
[Symbol.match]: boolean;
[Symbol.replace](...args: {}) {
throw new Error('Method not implemented.');
}
[Symbol.search](str: string): number {
throw new Error('Method not implemented.');
}
[Symbol.species](): number {
throw new Error('Method not implemented.');
}
[Symbol.split](str: string, limit?: number): {} {
throw new Error('Method not implemented.');
}
[Symbol.toPrimitive](hint: "number"): number;
[Symbol.toPrimitive](hint: "default"): number;
[Symbol.toPrimitive](hint: "string"): string;
[Symbol.toPrimitive](hint: any) {
throw new Error('Method not implemented.');
}
[Symbol.toStringTag]: string;
[Symbol.unscopables]: any;
`);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number;
//// }
//// interface I2 {
//// x: number;
//// }
////
//// class C implements I1,I2 {[|
//// |]}
verify.codeFixAvailable();

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number;
//// }
//// interface I2 {
//// x: number;
//// }
////
//// class C implements I1,I2 {
//// x: number;
//// }
verify.not.codeFixAvailable();

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// [x: number]: I;
//// [y: string]: I;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
[x: number]: I;
[y: string]: I;
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I4 {
//// [x: string, y: number]: number;
//// }
////
//// class C implements I {[| |]}
verify.not.codeFixAvailable();

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// [x: number]: I;
//// }
////
//// class C implements I {[|
//// |]}
verify.rangeAfterCodeFix(`
[x: number]: I;
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I<X> {
//// [x: string]: X;
//// }
////
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
[x: string]: number;
`);

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// f(x: number, y: string): I
//// }
////
//// class C implements I {[|
//// |]}
verify.rangeAfterCodeFix(`
f(x: number,y: string): I {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,19 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number;
//// }
//// interface I2 {
//// y: number;
//// }
////
//// class C implements I1,I2 {[|
//// y: number;
//// |]}
verify.rangeAfterCodeFix(`
x: number;
y: number;
`);
verify.not.codeFixAvailable();

View file

@ -0,0 +1,19 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number;
//// }
//// interface I2 {
//// y: number;
//// }
////
//// class C implements I1,I2 {[|
//// x: number;
//// |]}
verify.rangeAfterCodeFix(`
y: number;
x: number;
`);
verify.not.codeFixAvailable();

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number;
//// }
//// interface I2 {
//// x: string;
//// }
////
//// class C implements I1,I2 {[|
//// |]}
verify.codeFixAvailable();

View file

@ -0,0 +1,14 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number;
//// }
//// interface I2 {
//// x: string;
//// }
////
//// class C implements I1,I2 {
//// x: string;
//// }
verify.not.codeFixAvailable();

View file

@ -0,0 +1,28 @@
/// <reference path='fourslash.ts' />
//// interface I1 {
//// x: number,
//// y: number
//// z: number;
//// f(),
//// g()
//// h();
//// }
////
//// class C1 implements I1 {[|
//// |]}
verify.rangeAfterCodeFix(`
x: number;
y: number;
z: number;
f() {
throw new Error('Method not implemented.');
}
g() {
throw new Error('Method not implemented.');
}
h() {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// method(a: number, b: string): boolean;
//// method(a: string, b: number): Function;
//// method(a: string): Function;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
method(a: number, b: string): boolean;
method(a: string, b: number): Function;
method(a: string): Function;
method(a: any, b?: any) {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// method(a: number, ...b: string[]): boolean;
//// method(a: string, ...b: number[]): Function;
//// method(a: string): Function;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
method(a: number, ...b: string[]): boolean;
method(a: string, ...b: number[]): Function;
method(a: string): Function;
method(a: any, ...b?: any[]) {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,18 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// method(a: number, ...b: string[]): boolean;
//// method(a: string, b: number): Function;
//// method(a: string): Function;
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`
method(a: number, ...b: string[]): boolean;
method(a: string, b: number): Function;
method(a: string): Function;
method(a: any, b?: any, ...rest?: any[]) {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />
//// namespace N1 {
//// export interface I1 {
//// x: number;
//// }
//// }
//// interface I1 {
//// f1();
//// }
////
//// class C1 implements N1.I1 {[|
//// |]}
verify.rangeAfterCodeFix(`
x: number;
`);

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// class A {
//// constructor(public x: number) { }
//// }
////
//// class B implements A {[| |]}
verify.not.codeFixAvailable();
// TODO: (arozga) Get this working.
/*
verify.rangeAfterCodeFix(`
public x: number;
`);
*/

View file

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// x: number;
//// y: number;
//// z: number & { __iBrand: any };
//// }
////
//// class C implements I {[| |]
//// constructor(public x: number) { }
//// y: number;
//// }
verify.rangeAfterCodeFix(`
z: number & { __iBrand: any; };
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I<T> {
//// x: { y: T, z: T[] };
//// }
////
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
x: { y: number; z: number[]; };
`);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// interface I<T extends string> {
//// x: T;
//// }
////
//// class C implements I<number> { }
verify.codeFixAvailable();
// TODO: (arozga) Don't know how to instantiate in codeFix
// if instantiation is invalid.
// verify.not.codeFixAvailable();

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I<T> {
//// x: T;
//// }
////
//// class C implements I<number> {[| |]}
verify.rangeAfterCodeFix(`
x: number;
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I<T> {
//// x: T;
//// }
////
//// class C<T> implements I<T> {[| |]}
verify.rangeAfterCodeFix(`
x: T;
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// interface I<T> {
//// x: T;
//// }
////
//// class C<U> implements I<U> {[| |]}
verify.rangeAfterCodeFix(`
x: U;
`);

View file

@ -0,0 +1,9 @@
/// <reference path='fourslash.ts' />
//// interface I<T> {
//// x: T;
//// }
////
//// class C implements I { }
verify.not.codeFixAvailable();

View file

@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// f<T extends number>(x: T);
//// }
////
//// class C implements I {[| |]}
verify.rangeAfterCodeFix(`f<T extends number>(x: T){
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,19 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// x: T;
//// }
////
//// class C implements I { }
// T is not a declared symbol. There are a couple fixes:
// 1) Declare T.
// 2) Rename T to an existing symbol.
// 3) Make T a type parameter to I.
//
// In the latter two cases, it is premature to copy `x:T` into C.
// Since we can't guess the programmer's intent here, we do nothing.
verify.codeFixAvailable();
// TODO: (aozgaa) Acknowledge other errors on class/implemented interface/extended abstract class.
// verify.not.codeFixAvailable();

View file

@ -10,4 +10,4 @@
//// }
////}
verify.codeFixAtPosition("super(); this.a = 12;");
verify.rangeAfterCodeFix("super(); this.a = 12;");

View file

@ -7,4 +7,4 @@
//// }
////}
verify.codeFixAtPosition('super();');
verify.rangeAfterCodeFix('super();');

View file

@ -0,0 +1,15 @@
/// <reference path='fourslash.ts'/>
////interface Foo {
//// foo: string;
//// bar: string;
////}
////
////function f<K extends keyof Foo>(a: K) { };
////f("/*1*/
goTo.marker('1');
verify.completionListContains("foo");
verify.completionListContains("bar");
verify.completionListCount(2);

View file

@ -208,7 +208,7 @@ declare namespace FourSlashInterface {
noMatchingBracePositionInCurrentFile(bracePosition: number): void;
DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void;
noDocCommentTemplate(): void;
codeFixAtPosition(expectedText: string, errorCode?: number): void;
rangeAfterCodeFix(expectedText: string, errorCode?: number): void;
importFixAtPosition(expectedTextArray: string[], errorCode?: number): void;
navigationBar(json: any): void;

View file

@ -1,10 +0,0 @@
/// <reference path='fourslash.ts' />
////class Base{
////}
////class C extends Base{
//// constructor() {[| |]
//// }
////}
verify.codeFixAtPosition('super();');

View file

@ -6,5 +6,5 @@
//// }
//// } |]
verify.codeFixAtPosition(`namespace greeter {
verify.rangeAfterCodeFix(`namespace greeter {
}`);

View file

@ -8,7 +8,7 @@
//// }
//// } |]
verify.codeFixAtPosition(`namespace greeter {
verify.rangeAfterCodeFix(`namespace greeter {
export class class2 {
}
}`);

View file

@ -16,7 +16,7 @@
//// }
////} |]
verify.codeFixAtPosition(`namespace Validation {
verify.rangeAfterCodeFix(`namespace Validation {
class c1 {
}

View file

@ -16,7 +16,7 @@
//// }
////} |]
verify.codeFixAtPosition(`namespace Validation {
verify.rangeAfterCodeFix(`namespace Validation {
class c1 {
}

View file

@ -5,6 +5,6 @@
//// const x: string = "x";
//// } |]
verify.codeFixAtPosition(`function f1 () {
verify.rangeAfterCodeFix(`function f1 () {
}`);

View file

@ -5,7 +5,7 @@
//// enum Directions { Up, Down}
//// } |]
verify.codeFixAtPosition(`function f1 () {
verify.rangeAfterCodeFix(`function f1 () {
}
`);

Some files were not shown because too many files have changed in this diff Show more