Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d78247a402
176 changed files with 1747 additions and 255 deletions
14
Jakefile.js
14
Jakefile.js
|
@ -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);
|
||||
}));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
3
src/lib/es5.d.ts
vendored
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) => {
|
|
@ -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 } }] }]
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -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' />
|
||||
|
||||
|
|
156
src/services/codefixes/helpers.ts
Normal file
156
src/services/codefixes/helpers.ts
Normal 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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
8
tests/baselines/reference/arraySlice.js
Normal file
8
tests/baselines/reference/arraySlice.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
//// [arraySlice.ts]
|
||||
var arr: string[] | number[];
|
||||
arr.splice(1, 1);
|
||||
|
||||
|
||||
//// [arraySlice.js]
|
||||
var arr;
|
||||
arr.splice(1, 1);
|
9
tests/baselines/reference/arraySlice.symbols
Normal file
9
tests/baselines/reference/arraySlice.symbols
Normal 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, --, --))
|
||||
|
12
tests/baselines/reference/arraySlice.types
Normal file
12
tests/baselines/reference/arraySlice.types
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
2
tests/cases/compiler/arraySlice.ts
Normal file
2
tests/cases/compiler/arraySlice.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
var arr: string[] | number[];
|
||||
arr.splice(1, 1);
|
|
@ -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>;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {}
|
||||
//// [|/* */ class /* */ C /* */ extends /* */ I|]{}
|
||||
|
||||
verify.rangeAfterCodeFix("/* */ class /* */ C /* */ implements /* */ I");
|
|
@ -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");
|
|
@ -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>");
|
|
@ -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 { }");
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
11
tests/cases/fourslash/codeFixClassExtendAbstractGetter.ts
Normal file
11
tests/cases/fourslash/codeFixClassExtendAbstractGetter.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract get b(): number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
b: number;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
18
tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts
Normal file
18
tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts
Normal 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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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();
|
12
tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts
Normal file
12
tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
`);
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// protected abstract x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
protected x: number;
|
||||
`);
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// public abstract x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
public x: number;
|
||||
`);
|
11
tests/cases/fourslash/codeFixClassExtendAbstractSetter.ts
Normal file
11
tests/cases/fourslash/codeFixClassExtendAbstractSetter.ts
Normal 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;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -0,0 +1,9 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I { x: number; }
|
||||
////
|
||||
//// export default class implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
`);
|
20
tests/cases/fourslash/codeFixClassImplementInterface36.ts
Normal file
20
tests/cases/fourslash/codeFixClassImplementInterface36.ts
Normal 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.');
|
||||
}
|
||||
`);
|
18
tests/cases/fourslash/codeFixClassImplementInterface39.ts
Normal file
18
tests/cases/fourslash/codeFixClassImplementInterface39.ts
Normal 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.');
|
||||
}
|
||||
`);
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
|
||||
//// interface I { x: number; }
|
||||
////
|
||||
//// new class implements I {[| |]};
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -0,0 +1,13 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I1 {
|
||||
//// x: number;
|
||||
//// }
|
||||
//// interface I2 {
|
||||
//// x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I1,I2 {[|
|
||||
//// |]}
|
||||
|
||||
verify.codeFixAvailable();
|
|
@ -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();
|
|
@ -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;
|
||||
`);
|
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I4 {
|
||||
//// [x: string, y: number]: number;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.not.codeFixAvailable();
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// [x: number]: I;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[|
|
||||
//// |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
[x: number]: I;
|
||||
`);
|
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<X> {
|
||||
//// [x: string]: X;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I<number> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
[x: string]: number;
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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();
|
|
@ -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();
|
|
@ -0,0 +1,13 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I1 {
|
||||
//// x: number;
|
||||
//// }
|
||||
//// interface I2 {
|
||||
//// x: string;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I1,I2 {[|
|
||||
//// |]}
|
||||
|
||||
verify.codeFixAvailable();
|
|
@ -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();
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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;
|
||||
`);
|
|
@ -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;
|
||||
`);
|
||||
*/
|
|
@ -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; };
|
||||
`);
|
|
@ -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[]; };
|
||||
`);
|
|
@ -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();
|
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<T> {
|
||||
//// x: T;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I<number> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
`);
|
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<T> {
|
||||
//// x: T;
|
||||
//// }
|
||||
////
|
||||
//// class C<T> implements I<T> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: T;
|
||||
`);
|
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<T> {
|
||||
//// x: T;
|
||||
//// }
|
||||
////
|
||||
//// class C<U> implements I<U> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: U;
|
||||
`);
|
|
@ -0,0 +1,9 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<T> {
|
||||
//// x: T;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I { }
|
||||
|
||||
verify.not.codeFixAvailable();
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -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();
|
|
@ -10,4 +10,4 @@
|
|||
//// }
|
||||
////}
|
||||
|
||||
verify.codeFixAtPosition("super(); this.a = 12;");
|
||||
verify.rangeAfterCodeFix("super(); this.a = 12;");
|
|
@ -7,4 +7,4 @@
|
|||
//// }
|
||||
////}
|
||||
|
||||
verify.codeFixAtPosition('super();');
|
||||
verify.rangeAfterCodeFix('super();');
|
15
tests/cases/fourslash/completionForStringLiteral5.ts
Normal file
15
tests/cases/fourslash/completionForStringLiteral5.ts
Normal 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);
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////class Base{
|
||||
////}
|
||||
////class C extends Base{
|
||||
//// constructor() {[| |]
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.codeFixAtPosition('super();');
|
|
@ -6,5 +6,5 @@
|
|||
//// }
|
||||
//// } |]
|
||||
|
||||
verify.codeFixAtPosition(`namespace greeter {
|
||||
verify.rangeAfterCodeFix(`namespace greeter {
|
||||
}`);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//// }
|
||||
//// } |]
|
||||
|
||||
verify.codeFixAtPosition(`namespace greeter {
|
||||
verify.rangeAfterCodeFix(`namespace greeter {
|
||||
export class class2 {
|
||||
}
|
||||
}`);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
//// }
|
||||
////} |]
|
||||
|
||||
verify.codeFixAtPosition(`namespace Validation {
|
||||
verify.rangeAfterCodeFix(`namespace Validation {
|
||||
class c1 {
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
//// }
|
||||
////} |]
|
||||
|
||||
verify.codeFixAtPosition(`namespace Validation {
|
||||
verify.rangeAfterCodeFix(`namespace Validation {
|
||||
class c1 {
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
//// const x: string = "x";
|
||||
//// } |]
|
||||
|
||||
verify.codeFixAtPosition(`function f1 () {
|
||||
verify.rangeAfterCodeFix(`function f1 () {
|
||||
}`);
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue