diff --git a/Jakefile b/Jakefile index 0bdb573914f..04049837f6e 100644 --- a/Jakefile +++ b/Jakefile @@ -54,6 +54,8 @@ var servicesSources = [ }).concat([ "services.ts", "shims.ts", + "signatureHelp.ts", + "utilities.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/README.md b/README.md index c87c8ce5ee9..c737c5dc716 100644 --- a/README.md +++ b/README.md @@ -47,16 +47,18 @@ npm install Use one of the following to build and test: ``` -jake local # Build the compiler into built/local -jake clean # Delete the built compiler -jake LKG # Replace the last known good with the built one. - # Bootstrapping step to be executed when the built compiler reaches a stable state. -jake tests # Build the test infrastructure using the built compiler. -jake runtests # Run tests using the built compiler and test infrastructure. - # You can override the host or specify a test for this command. - # Use host= or tests=. -jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. -jake -T # List the above commands. +jake local # Build the compiler into built/local +jake clean # Delete the built compiler +jake LKG # Replace the last known good with the built one. + # Bootstrapping step to be executed when the built compiler reaches a stable state. +jake tests # Build the test infrastructure using the built compiler. +jake runtests # Run tests using the built compiler and test infrastructure. + # You can override the host or specify a test for this command. + # Use host= or tests=. +jake runtests-browser # Runs the tests using the built run.js file. Syntax is jake runtests. Optional + parameters 'host=', 'tests=[regex], reporter=[list|spec|json|]'. +jake baseline-accept # This replaces the baseline test results with the results obtained from jake runtests. +jake -T # List the above commands. ``` diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 953bd3de49a..1ec86615949 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23,6 +23,28 @@ module ts { return undefined; } + interface SymbolWriter { + writeKind(text: string, kind: SymbolDisplayPartKind): void; + writeSymbol(text: string, symbol: Symbol): void; + writeLine(): void; + increaseIndent(): void; + decreaseIndent(): void; + clear(): void; + + // Called when the symbol writer encounters a symbol to write. Currently only used by the + // declaration emitter to help determine if it should patch up the final declaration file + // with import statements it previously saw (but chose not to emit). + trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; + } + + interface DisplayPartsSymbolWriter extends SymbolWriter { + displayParts(): SymbolDisplayPart[]; + } + + interface StringSymbolWriter extends SymbolWriter { + string(): string; + } + /// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics. /// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors /// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors. @@ -62,11 +84,15 @@ module ts { getTypeOfNode: getTypeOfNode, getApparentType: getApparentType, typeToString: typeToString, + typeToDisplayParts: typeToDisplayParts, symbolToString: symbolToString, + symbolToDisplayParts: symbolToDisplayParts, getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType, getRootSymbol: getRootSymbol, getContextualType: getContextualType, - getFullyQualifiedName: getFullyQualifiedName + getFullyQualifiedName: getFullyQualifiedName, + getResolvedSignature: getResolvedSignature, + getEnumMemberValue: getEnumMemberValue }; var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined"); @@ -895,106 +921,238 @@ module ts { { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: firstIdentifierName }; } + // Pool writers to avoid needing to allocate them for every symbol we write. + var displayPartWriters: DisplayPartsSymbolWriter[] = []; + var stringWriters: StringSymbolWriter[] = []; + + function displayPartKind(symbol: Symbol): SymbolDisplayPartKind { + var flags = symbol.flags; + + if (flags & SymbolFlags.Variable) { + return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter + ? SymbolDisplayPartKind.parameterName + : SymbolDisplayPartKind.localName; + } + else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; } + else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; } + else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; } + else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; } + else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; } + else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; } + else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; } + else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; } + else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; } + + return SymbolDisplayPartKind.text; + } + + function getDisplayPartWriter(): DisplayPartsSymbolWriter { + if (displayPartWriters.length == 0) { + var displayParts: SymbolDisplayPart[] = []; + return { + displayParts: () => displayParts, + writeKind: (text, kind) => displayParts.push(new SymbolDisplayPart(text, kind, undefined)), + writeSymbol: (text, symbol) => displayParts.push(new SymbolDisplayPart(text, displayPartKind(symbol), symbol)), + + // Completely ignore indentation for display part writers. And map newlines to + // a single space. + writeLine: () => displayParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)), + increaseIndent: () => { }, + decreaseIndent: () => { }, + clear: () => displayParts = [], + trackSymbol: () => { } + }; + } + + return displayPartWriters.pop(); + } + + function getStringWriter(): StringSymbolWriter { + if (stringWriters.length == 0) { + var str = ""; + + return { + string: () => str, + writeKind: text => str += text, + writeSymbol: text => str += text, + + // Completely ignore indentation for string writers. And map newlines to + // a single space. + writeLine: () => str += " ", + increaseIndent: () => { }, + decreaseIndent: () => { }, + clear: () => str = "", + trackSymbol: () => { } + }; + } + + return stringWriters.pop(); + } + + function releaseDisplayPartWriter(writer: DisplayPartsSymbolWriter) { + writer.clear(); + displayPartWriters.push(writer); + } + + function releaseStringWriter(writer: StringSymbolWriter) { + writer.clear() + stringWriters.push(writer); + } + + function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) { + writer.writeKind(tokenToString(kind), SymbolDisplayPartKind.keyword); + } + + function writePunctuation(writer: SymbolWriter, kind: SyntaxKind) { + writer.writeKind(tokenToString(kind), SymbolDisplayPartKind.punctuation); + } + + function writeOperator(writer: SymbolWriter, kind: SyntaxKind) { + writer.writeKind(tokenToString(kind), SymbolDisplayPartKind.operator); + } + + function writeSpace(writer: SymbolWriter) { + writer.writeKind(" ", SymbolDisplayPartKind.space); + } + + function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string { + var writer = getStringWriter(); + writeSymbol(symbol, writer, enclosingDeclaration, meaning); + + var result = writer.string(); + releaseStringWriter(writer); + + return result; + } + + function symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[] { + var writer = getDisplayPartWriter(); + writeSymbol(symbol, writer, enclosingDeclaration, meaning); + + var result = writer.displayParts(); + releaseDisplayPartWriter(writer); + + return result; + } + // Enclosing declaration is optional when we don't want to get qualified name in the enclosing declaration scope // Meaning needs to be specified if the enclosing declaration is given - function symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { - function getSymbolName(symbol: Symbol) { + function writeSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags): void { + function writeSymbolName(symbol: Symbol): void { if (symbol.declarations && symbol.declarations.length > 0) { var declaration = symbol.declarations[0]; if (declaration.name) { - return identifierToString(declaration.name); + writer.writeSymbol(identifierToString(declaration.name), symbol); + return; + } + } + + writer.writeSymbol(symbol.name, symbol); + } + + // Let the writer know we just wrote out a symbol. The declarationemitter writer uses + // this to determine if an import it has previously seen (and not writter out) needs + // to be written to the file once the walk of the tree is complete. + // + // NOTE(cyrusn): This approach feels somewhat unfortunate. A simple pass over the tree + // up front (for example, during checking) could determien if we need to emit the imports + // and we could then access that data during declaration emit. + writer.trackSymbol(symbol, enclosingDeclaration, meaning); + + var needsDot = false; + function walkSymbol(symbol: Symbol, meaning: SymbolFlags): void { + if (symbol) { + var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning); + + if (!accessibleSymbolChain || + needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { + + // Go up and add our parent. + walkSymbol( + getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol), + getQualifiedLeftMeaning(meaning)); + } + + if (accessibleSymbolChain) { + for (var i = 0, n = accessibleSymbolChain.length; i < n; i++) { + if (needsDot) { + writePunctuation(writer, SyntaxKind.DotToken); + } + + writeSymbolName(accessibleSymbolChain[i]); + needsDot = true; + } + } + else { + // If we didn't find accessible symbol chain for this symbol, break if this is external module + if (!needsDot && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) { + return; + } + + if (needsDot) { + writePunctuation(writer, SyntaxKind.DotToken); + } + + writeSymbolName(symbol); + needsDot = true; } } - return symbol.name; } // Get qualified name if (enclosingDeclaration && // TypeParameters do not need qualification !(symbol.flags & SymbolFlags.TypeParameter)) { - var symbolName: string; - while (symbol) { - var isFirstName = !symbolName; - var accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaning); - var currentSymbolName: string; - if (accessibleSymbolChain) { - currentSymbolName = ts.map(accessibleSymbolChain, accessibleSymbol => getSymbolName(accessibleSymbol)).join("."); - } - else { - // If we didn't find accessible symbol chain for this symbol, break if this is external module - if (!isFirstName && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) { - break; - } - currentSymbolName = getSymbolName(symbol); - } - symbolName = currentSymbolName + (isFirstName ? "" : ("." + symbolName)); - if (accessibleSymbolChain && !needsQualification(accessibleSymbolChain[0], enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) { - break; - } - symbol = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol); - meaning = getQualifiedLeftMeaning(meaning); - } - - return symbolName; + walkSymbol(symbol, meaning); + return; } - return getSymbolName(symbol); + return writeSymbolName(symbol); } function writeSymbolToTextWriter(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter) { writer.write(symbolToString(symbol, enclosingDeclaration, meaning)); } - function createSingleLineTextWriter(maxLength?: number) { - var result = ""; - var overflow = false; - function write(s: string) { - if (!overflow) { - result += s; - if (result.length > maxLength) { - result = result.substr(0, maxLength - 3) + "..."; - overflow = true; - } - } - } - return { - write: write, - writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { - writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, this); - }, - writeLine() { - write(" "); - }, - increaseIndent() { }, - decreaseIndent() { }, - getText() { - return result; - } - }; - } - function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string { + var writer = getStringWriter(); + writeType(type, writer, enclosingDeclaration, flags); + + var result = writer.string(); + releaseStringWriter(writer); + var maxLength = compilerOptions.noErrorTruncation || flags & TypeFormatFlags.NoTruncation ? undefined : 100; - var stringWriter = createSingleLineTextWriter(maxLength); - // TODO(shkamat): typeToString should take enclosingDeclaration as input, once we have implemented enclosingDeclaration - writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter); - return stringWriter.getText(); + if (maxLength && result.length >= maxLength) { + result = result.substr(0, maxLength - "...".length) + "..."; + } + + return result; } - function writeTypeToTextWriter(type: Type, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter) { + function typeToDisplayParts(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] { + var writer = getDisplayPartWriter(); + writeType(type, writer, enclosingDeclaration, flags); + + var result = writer.displayParts(); + releaseDisplayPartWriter(writer); + + return result; + } + + function writeType(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags) { var typeStack: Type[]; return writeType(type, /*allowFunctionOrConstructorTypeLiteral*/ true); function writeType(type: Type, allowFunctionOrConstructorTypeLiteral: boolean) { if (type.flags & TypeFlags.Intrinsic) { - writer.write((type).intrinsicName); + writer.writeKind((type).intrinsicName, SymbolDisplayPartKind.keyword); } else if (type.flags & TypeFlags.Reference) { writeTypeReference(type); } else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) { - writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Type); + writeSymbol(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type); } else if (type.flags & TypeFlags.Tuple) { writeTupleType(type); @@ -1003,18 +1161,24 @@ module ts { writeAnonymousType(type, allowFunctionOrConstructorTypeLiteral); } else if (type.flags & TypeFlags.StringLiteral) { - writer.write((type).text); + writer.writeKind((type).text, SymbolDisplayPartKind.stringLiteral); } else { // Should never get here - writer.write("{ ... }"); + // { ... } + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.DotDotDotToken); + writeSpace(writer); + writePunctuation(writer, SyntaxKind.CloseBraceToken); } } function writeTypeList(types: Type[]) { for (var i = 0; i < types.length; i++) { if (i > 0) { - writer.write(", "); + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); } writeType(types[i], /*allowFunctionOrConstructorTypeLiteral*/ true); } @@ -1025,20 +1189,21 @@ module ts { // If we are writing array element type the arrow style signatures are not allowed as // we need to surround it by curlies, e.g. { (): T; }[]; as () => T[] would mean something different writeType(type.typeArguments[0], /*allowFunctionOrConstructorTypeLiteral*/ false); - writer.write("[]"); + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writePunctuation(writer, SyntaxKind.CloseBracketToken); } else { - writer.writeSymbol(type.target.symbol, enclosingDeclaration, SymbolFlags.Type); - writer.write("<"); + writeSymbol(type.target.symbol, writer, enclosingDeclaration, SymbolFlags.Type); + writePunctuation(writer, SyntaxKind.LessThanToken); writeTypeList(type.typeArguments); - writer.write(">"); + writePunctuation(writer, SyntaxKind.GreaterThanToken); } } function writeTupleType(type: TupleType) { - writer.write("["); + writePunctuation(writer, SyntaxKind.OpenBracketToken); writeTypeList(type.elementTypes); - writer.write("]"); + writePunctuation(writer, SyntaxKind.CloseBracketToken); } function writeAnonymousType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) { @@ -1052,7 +1217,7 @@ module ts { } else if (typeStack && contains(typeStack, type)) { // Recursive usage, use any - writer.write("any"); + writeKeyword(writer, SyntaxKind.AnyKeyword); } else { if (!typeStack) { @@ -1082,15 +1247,17 @@ module ts { } function writeTypeofSymbol(type: ObjectType) { - writer.write("typeof "); - writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Value); + writeKeyword(writer, SyntaxKind.TypeOfKeyword); + writeSpace(writer); + writeSymbol(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value); } function writeLiteralType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) { var resolved = resolveObjectTypeMembers(type); if (!resolved.properties.length && !resolved.stringIndexType && !resolved.numberIndexType) { if (!resolved.callSignatures.length && !resolved.constructSignatures.length) { - writer.write("{}"); + writePunctuation(writer, SyntaxKind.OpenBraceToken); + writePunctuation(writer, SyntaxKind.CloseBraceToken); return; } @@ -1100,37 +1267,56 @@ module ts { return; } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { - writer.write("new "); + writeKeyword(writer, SyntaxKind.NewKeyword); + writeSpace(writer); writeSignature(resolved.constructSignatures[0], /*arrowStyle*/ true); return; } } } - writer.write("{"); + writePunctuation(writer, SyntaxKind.OpenBraceToken); writer.writeLine(); writer.increaseIndent(); for (var i = 0; i < resolved.callSignatures.length; i++) { writeSignature(resolved.callSignatures[i]); - writer.write(";"); + writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } for (var i = 0; i < resolved.constructSignatures.length; i++) { - writer.write("new "); + writeKeyword(writer, SyntaxKind.NewKeyword); + writeSpace(writer); + writeSignature(resolved.constructSignatures[i]); - writer.write(";"); + writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } if (resolved.stringIndexType) { - writer.write("[x: string]: "); + // [x: string]: + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writer.writeKind("x", SymbolDisplayPartKind.parameterName); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeKeyword(writer, SyntaxKind.StringKeyword); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); writeType(resolved.stringIndexType, /*allowFunctionOrConstructorTypeLiteral*/ true); - writer.write(";"); + writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } if (resolved.numberIndexType) { - writer.write("[x: number]: "); + // [x: number]: + writePunctuation(writer, SyntaxKind.OpenBracketToken); + writer.writeKind("x", SymbolDisplayPartKind.parameterName); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeKeyword(writer, SyntaxKind.NumberKeyword); + writePunctuation(writer, SyntaxKind.CloseBracketToken); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); writeType(resolved.numberIndexType, /*allowFunctionOrConstructorTypeLiteral*/ true); - writer.write(";"); + writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } for (var i = 0; i < resolved.properties.length; i++) { @@ -1139,64 +1325,81 @@ module ts { if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfType(t).length) { var signatures = getSignaturesOfType(t, SignatureKind.Call); for (var j = 0; j < signatures.length; j++) { - writer.writeSymbol(p); + writeSymbol(p, writer); if (isOptionalProperty(p)) { - writer.write("?"); + writePunctuation(writer, SyntaxKind.QuestionToken); } writeSignature(signatures[j]); - writer.write(";"); + writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } } else { - writer.writeSymbol(p); + writeSymbol(p, writer); if (isOptionalProperty(p)) { - writer.write("?"); + writePunctuation(writer, SyntaxKind.QuestionToken); } - writer.write(": "); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); writeType(t, /*allowFunctionOrConstructorTypeLiteral*/ true); - writer.write(";"); + writePunctuation(writer, SyntaxKind.SemicolonToken); writer.writeLine(); } } writer.decreaseIndent(); - writer.write("}"); + writePunctuation(writer, SyntaxKind.CloseBraceToken); } function writeSignature(signature: Signature, arrowStyle?: boolean) { if (signature.typeParameters) { - writer.write("<"); + writePunctuation(writer, SyntaxKind.LessThanToken); for (var i = 0; i < signature.typeParameters.length; i++) { if (i > 0) { - writer.write(", "); + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); } var tp = signature.typeParameters[i]; - writer.writeSymbol(tp.symbol); + writeSymbol(tp.symbol, writer); var constraint = getConstraintOfTypeParameter(tp); if (constraint) { - writer.write(" extends "); + writeSpace(writer); + writeKeyword(writer, SyntaxKind.ExtendsKeyword); + writeSpace(writer); writeType(constraint, /*allowFunctionOrConstructorTypeLiteral*/ true); } } - writer.write(">"); + writePunctuation(writer, SyntaxKind.GreaterThanToken); } - writer.write("("); + writePunctuation(writer, SyntaxKind.OpenParenToken); for (var i = 0; i < signature.parameters.length; i++) { if (i > 0) { - writer.write(", "); + writePunctuation(writer, SyntaxKind.CommaToken); + writeSpace(writer); } var p = signature.parameters[i]; if (getDeclarationFlagsFromSymbol(p) & NodeFlags.Rest) { - writer.write("..."); + writePunctuation(writer, SyntaxKind.DotDotDotToken); } - writer.writeSymbol(p); + writeSymbol(p, writer); if (p.valueDeclaration.flags & NodeFlags.QuestionMark || (p.valueDeclaration).initializer) { - writer.write("?"); + writePunctuation(writer, SyntaxKind.QuestionToken); } - writer.write(": "); + writePunctuation(writer, SyntaxKind.ColonToken); + writeSpace(writer); + writeType(getTypeOfSymbol(p), /*allowFunctionOrConstructorTypeLiteral*/ true); } - writer.write(arrowStyle ? ") => " : "): "); + + writePunctuation(writer, SyntaxKind.CloseParenToken); + if (arrowStyle) { + writeSpace(writer); + writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken); + } + else { + writePunctuation(writer, SyntaxKind.ColonToken); + } + writeSpace(writer); + writeType(getReturnTypeOfSignature(signature), /*allowFunctionOrConstructorTypeLiteral*/ true); } } @@ -4128,55 +4331,26 @@ module ts { return unknownSignature; } - function isCandidateSignature(node: CallExpression, signature: Signature) { + function signatureHasCorrectArity(node: CallExpression, signature: Signature): boolean { var args = node.arguments || emptyArray; - return args.length >= signature.minArgumentCount && + var isCorrect = args.length >= signature.minArgumentCount && (signature.hasRestParameter || args.length <= signature.parameters.length) && (!node.typeArguments || signature.typeParameters && node.typeArguments.length === signature.typeParameters.length); - } - // The candidate list orders groups in reverse, but within a group signatures are kept in declaration order - // A nit here is that we reorder only signatures that belong to the same symbol, - // so order how inherited signatures are processed is still preserved. - // interface A { (x: string): void } - // interface B extends A { (x: 'foo'): string } - // var b: B; - // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] - function collectCandidates(node: CallExpression, signatures: Signature[]): Signature[]{ - var result: Signature[] = []; - var lastParent: Node; - var lastSymbol: Symbol; - var cutoffPos: number = 0; - var pos: number; - for (var i = 0; i < signatures.length; i++) { - var signature = signatures[i]; - if (isCandidateSignature(node, signature)) { - var symbol = signature.declaration && getSymbolOfNode(signature.declaration); - var parent = signature.declaration && signature.declaration.parent; - if (!lastSymbol || symbol === lastSymbol) { - if (lastParent && parent === lastParent) { - pos++; - } - else { - lastParent = parent; - pos = cutoffPos; - } - } - else { - // current declaration belongs to a different symbol - // set cutoffPos so re-orderings in the future won't change result set from 0 to cutoffPos - pos = cutoffPos = result.length; - lastParent = parent; - } - lastSymbol = symbol; - - for (var j = result.length; j > pos; j--) { - result[j] = result[j - 1]; - } - result[pos] = signature; + // For error recovery, since we have parsed OmittedExpressions for any extra commas + // in the argument list, if we see any OmittedExpressions, just return true. + // The reason this is ok is because omitted expressions here are syntactically + // illegal, and will cause a parse error. + // Note: It may be worth keeping the upper bound check on arity, but removing + // the lower bound check if there are omitted expressions. + if (!isCorrect) { + // Technically this type assertion is not safe because args could be initialized to emptyArray + // above. + if ((>args).hasTrailingComma || forEach(args, arg => arg.kind === SyntaxKind.OmittedExpression)) { + return true; } } - return result; + return isCorrect; } // If type has a single call signature and no other members, return that signature. Otherwise, return undefined. @@ -4207,6 +4381,9 @@ module ts { var mapper = createInferenceMapper(context); // First infer from arguments that are not context sensitive for (var i = 0; i < args.length; i++) { + if (args[i].kind === SyntaxKind.OmittedExpression) { + continue; + } if (!excludeArgument || excludeArgument[i] === undefined) { var parameterType = getTypeAtPosition(signature, i); inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType); @@ -4215,6 +4392,9 @@ module ts { // Next, infer from those context sensitive arguments that are no longer excluded if (excludeArgument) { for (var i = 0; i < args.length; i++) { + if (args[i].kind === SyntaxKind.OmittedExpression) { + continue; + } if (excludeArgument[i] === false) { var parameterType = getTypeAtPosition(signature, i); inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType); @@ -4243,6 +4423,10 @@ module ts { if (node.arguments) { for (var i = 0; i < node.arguments.length; i++) { var arg = node.arguments[i]; + if (arg.kind === SyntaxKind.OmittedExpression) { + continue; + } + var paramType = getTypeAtPosition(signature, i); // String literals get string literal types unless we're reporting errors var argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors ? @@ -4260,9 +4444,11 @@ module ts { return true; } - function resolveCall(node: CallExpression, signatures: Signature[]): Signature { + function resolveCall(node: CallExpression, signatures: Signature[], candidatesOutArray: Signature[]): Signature { forEach(node.typeArguments, checkSourceElement); - var candidates = collectCandidates(node, signatures); + var candidates = candidatesOutArray || []; + // collectCandidates fills up the candidates array directly + collectCandidates(); if (!candidates.length) { error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); return resolveErrorCall(node); @@ -4278,20 +4464,24 @@ module ts { var relation = candidates.length === 1 ? assignableRelation : subtypeRelation; while (true) { for (var i = 0; i < candidates.length; i++) { + if (!signatureHasCorrectArity(node, candidates[i])) { + continue; + } + while (true) { - var candidate = candidates[i]; - if (candidate.typeParameters) { + var candidateWithCorrectArity = candidates[i]; + if (candidateWithCorrectArity.typeParameters) { var typeArguments = node.typeArguments ? - checkTypeArguments(candidate, node.typeArguments) : - inferTypeArguments(candidate, args, excludeArgument); - candidate = getSignatureInstantiation(candidate, typeArguments); + checkTypeArguments(candidateWithCorrectArity, node.typeArguments) : + inferTypeArguments(candidateWithCorrectArity, args, excludeArgument); + candidateWithCorrectArity = getSignatureInstantiation(candidateWithCorrectArity, typeArguments); } - if (!checkApplicableSignature(node, candidate, relation, excludeArgument, /*reportErrors*/ false)) { + if (!checkApplicableSignature(node, candidateWithCorrectArity, relation, excludeArgument, /*reportErrors*/ false)) { break; } var index = excludeArgument ? indexOf(excludeArgument, true) : -1; if (index < 0) { - return candidate; + return candidateWithCorrectArity; } excludeArgument[index] = false; } @@ -4301,17 +4491,70 @@ module ts { } relation = assignableRelation; } + // No signatures were applicable. Now report errors based on the last applicable signature with // no arguments excluded from assignability checks. - checkApplicableSignature(node, candidate, relation, undefined, /*reportErrors*/ true); + // If candidate is undefined, it means that no candidates had a suitable arity. In that case, + // skip the checkApplicableSignature check. + if (candidateWithCorrectArity) { + checkApplicableSignature(node, candidateWithCorrectArity, relation, /*excludeArgument*/ undefined, /*reportErrors*/ true); + } + else { + error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target); + return resolveErrorCall(node); + } return resolveErrorCall(node); + + // The candidate list orders groups in reverse, but within a group signatures are kept in declaration order + // A nit here is that we reorder only signatures that belong to the same symbol, + // so order how inherited signatures are processed is still preserved. + // interface A { (x: string): void } + // interface B extends A { (x: 'foo'): string } + // var b: B; + // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void] + function collectCandidates(): void { + var result = candidates; + var lastParent: Node; + var lastSymbol: Symbol; + var cutoffPos: number = 0; + var pos: number; + Debug.assert(!result.length); + for (var i = 0; i < signatures.length; i++) { + var signature = signatures[i]; + if (true) { + var symbol = signature.declaration && getSymbolOfNode(signature.declaration); + var parent = signature.declaration && signature.declaration.parent; + if (!lastSymbol || symbol === lastSymbol) { + if (lastParent && parent === lastParent) { + pos++; + } + else { + lastParent = parent; + pos = cutoffPos; + } + } + else { + // current declaration belongs to a different symbol + // set cutoffPos so re-orderings in the future won't change result set from 0 to cutoffPos + pos = cutoffPos = result.length; + lastParent = parent; + } + lastSymbol = symbol; + + for (var j = result.length; j > pos; j--) { + result[j] = result[j - 1]; + } + result[pos] = signature; + } + } + } } - function resolveCallExpression(node: CallExpression): Signature { + function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature { if (node.func.kind === SyntaxKind.SuperKeyword) { var superType = checkSuperExpression(node.func); if (superType !== unknownType) { - return resolveCall(node, getSignaturesOfType(superType, SignatureKind.Construct)); + return resolveCall(node, getSignaturesOfType(superType, SignatureKind.Construct), candidatesOutArray); } return resolveUntypedCall(node); } @@ -4359,10 +4602,10 @@ module ts { } return resolveErrorCall(node); } - return resolveCall(node, callSignatures); + return resolveCall(node, callSignatures, candidatesOutArray); } - function resolveNewExpression(node: NewExpression): Signature { + function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature { var expressionType = checkExpression(node.func); if (expressionType === unknownType) { // Another error has already been reported @@ -4397,7 +4640,7 @@ module ts { // that the user will not add any. var constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct); if (constructSignatures.length) { - return resolveCall(node, constructSignatures); + return resolveCall(node, constructSignatures, candidatesOutArray); } // If ConstructExpr's apparent type is an object type with no construct signatures but @@ -4406,7 +4649,7 @@ module ts { // operation is Any. var callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); if (callSignatures.length) { - var signature = resolveCall(node, callSignatures); + var signature = resolveCall(node, callSignatures, candidatesOutArray); if (getReturnTypeOfSignature(signature) !== voidType) { error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); } @@ -4417,11 +4660,19 @@ module ts { return resolveErrorCall(node); } - function getResolvedSignature(node: CallExpression): Signature { + // candidatesOutArray is passed by signature help in the language service, and collectCandidates + // must fill it up with the appropriate candidate signatures + function getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature { var links = getNodeLinks(node); - if (!links.resolvedSignature) { + // If getResolvedSignature has already been called, we will have cached the resolvedSignature. + // However, it is possible that either candidatesOutArray was not passed in the first time, + // or that a different candidatesOutArray was passed in. Therefore, we need to redo the work + // to correctly fill the candidatesOutArray. + if (!links.resolvedSignature || candidatesOutArray) { links.resolvedSignature = anySignature; - links.resolvedSignature = node.kind === SyntaxKind.CallExpression ? resolveCallExpression(node) : resolveNewExpression(node); + links.resolvedSignature = node.kind === SyntaxKind.CallExpression + ? resolveCallExpression(node, candidatesOutArray) + : resolveNewExpression(node, candidatesOutArray); } return links.resolvedSignature; } @@ -4733,10 +4984,12 @@ module ts { // The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type, // and the right operand to be of type Any or a subtype of the 'Function' interface type. // The result is always of the Boolean primitive type. - if (!isTypeAnyTypeObjectTypeOrTypeParameter(leftType)) { + // NOTE: do not raise error if leftType is unknown as related error was already reported + if (leftType !== unknownType && !isTypeAnyTypeObjectTypeOrTypeParameter(leftType)) { error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } - if (rightType !== anyType && !isTypeSubtypeOf(rightType, globalFunctionType)) { + // NOTE: do not raise error if right is unknown as related error was already reported + if (rightType !== unknownType && rightType !== anyType && !isTypeSubtypeOf(rightType, globalFunctionType)) { error(node.right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type); } return booleanType; @@ -5064,7 +5317,7 @@ module ts { if (fullTypeCheck) { checkCollisionWithCapturedSuperVariable(node, node.name); checkCollisionWithCapturedThisVariable(node, node.name); - checkCollistionWithRequireExportsInGeneratedCode(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); checkCollisionWithArgumentsInGeneratedCode(node); if (compilerOptions.noImplicitAny && !node.type) { switch (node.kind) { @@ -5810,7 +6063,7 @@ module ts { } } - function checkCollistionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) { + function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) { if (!needCollisionCheckForIdentifier(node, name, "require") && !needCollisionCheckForIdentifier(node, name, "exports")) { return; } @@ -5855,7 +6108,7 @@ module ts { checkCollisionWithCapturedSuperVariable(node, node.name); checkCollisionWithCapturedThisVariable(node, node.name); - checkCollistionWithRequireExportsInGeneratedCode(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); if (!useTypeFromValueDeclaration) { // TypeScript 1.0 spec (April 2014): 5.1 // Multiple declarations for the same variable name in the same declaration space are permitted, @@ -6114,7 +6367,7 @@ module ts { checkTypeNameIsReserved(node.name, Diagnostics.Class_name_cannot_be_0); checkTypeParameters(node.typeParameters); checkCollisionWithCapturedThisVariable(node, node.name); - checkCollistionWithRequireExportsInGeneratedCode(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); checkExportsOnMergedDeclarations(node); var symbol = getSymbolOfNode(node); var type = getDeclaredTypeOfSymbol(symbol); @@ -6307,7 +6560,7 @@ module ts { } } - function getConstantValue(node: Expression): number { + function getConstantValueForExpression(node: Expression): number { var isNegative = false; if (node.kind === SyntaxKind.PrefixOperator) { var unaryExpression = node; @@ -6324,38 +6577,51 @@ module ts { return undefined; } + function computeEnumMemberValues(node: EnumDeclaration) { + var nodeLinks = getNodeLinks(node); + + if (!(nodeLinks.flags & NodeCheckFlags.EnumValuesComputed)) { + var enumSymbol = getSymbolOfNode(node); + var enumType = getDeclaredTypeOfSymbol(enumSymbol); + var autoValue = 0; + var ambient = isInAmbientContext(node); + + forEach(node.members, member => { + var initializer = member.initializer; + if (initializer) { + autoValue = getConstantValueForExpression(initializer); + if (autoValue === undefined && !ambient) { + // Only here do we need to check that the initializer is assignable to the enum type. + // If it is a constant value (not undefined), it is syntactically constrained to be a number. + // Also, we do not need to check this for ambients because there is already + // a syntax error if it is not a constant. + checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined); + } + } + else if (ambient) { + autoValue = undefined; + } + + if (autoValue !== undefined) { + getNodeLinks(member).enumMemberValue = autoValue++; + } + }); + + nodeLinks.flags |= NodeCheckFlags.EnumValuesComputed; + } + } + function checkEnumDeclaration(node: EnumDeclaration) { if (!fullTypeCheck) { return; } + checkTypeNameIsReserved(node.name, Diagnostics.Enum_name_cannot_be_0); checkCollisionWithCapturedThisVariable(node, node.name); - checkCollistionWithRequireExportsInGeneratedCode(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); checkExportsOnMergedDeclarations(node); - var enumSymbol = getSymbolOfNode(node); - var enumType = getDeclaredTypeOfSymbol(enumSymbol); - var autoValue = 0; - var ambient = isInAmbientContext(node); - forEach(node.members, member => { - var initializer = member.initializer; - if (initializer) { - autoValue = getConstantValue(initializer); - if (autoValue === undefined && !ambient) { - // Only here do we need to check that the initializer is assignable to the enum type. - // If it is a constant value (not undefined), it is syntactically constrained to be a number. - // Also, we do not need to check this for ambients because there is already - // a syntax error if it is not a constant. - checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined); - } - } - else if (ambient) { - autoValue = undefined; - } - if (autoValue !== undefined) { - getNodeLinks(member).enumMemberValue = autoValue++; - } - }); + computeEnumMemberValues(node); // Spec 2014 - Section 9.3: // It isn't possible for one enum declaration to continue the automatic numbering sequence of another, @@ -6363,6 +6629,7 @@ module ts { // for the first member. // // Only perform this check once per symbol + var enumSymbol = getSymbolOfNode(node); var firstDeclaration = getDeclarationOfKind(enumSymbol, node.kind); if (node === firstDeclaration) { var seenEnumMissingInitialInitializer = false; @@ -6404,7 +6671,7 @@ module ts { function checkModuleDeclaration(node: ModuleDeclaration) { if (fullTypeCheck) { checkCollisionWithCapturedThisVariable(node, node.name); - checkCollistionWithRequireExportsInGeneratedCode(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); checkExportsOnMergedDeclarations(node); var symbol = getSymbolOfNode(node); if (symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length > 1 && !isInAmbientContext(node)) { @@ -6439,7 +6706,7 @@ module ts { function checkImportDeclaration(node: ImportDeclaration) { checkCollisionWithCapturedThisVariable(node, node.name); - checkCollistionWithRequireExportsInGeneratedCode(node, node.name); + checkCollisionWithRequireExportsInGeneratedCode(node, node.name); var symbol = getSymbolOfNode(node); var target: Symbol; @@ -7262,17 +7529,6 @@ module ts { } } - function getPropertyAccessSubstitution(node: PropertyAccess): string { - var symbol = getNodeLinks(node).resolvedSymbol; - if (symbol && (symbol.flags & SymbolFlags.EnumMember)) { - var declaration = symbol.valueDeclaration; - var constantValue: number; - if (declaration.kind === SyntaxKind.EnumMember && (constantValue = getNodeLinks(declaration).enumMemberValue) !== undefined) { - return constantValue.toString() + " /* " + identifierToString(declaration.name) + " */"; - } - } - } - function getExportAssignmentName(node: SourceFile): string { var symbol = getExportAssignmentSymbol(getSymbolOfNode(node)); return symbol && symbolIsValue(symbol) ? symbolToString(symbol): undefined; @@ -7335,20 +7591,51 @@ module ts { } function getEnumMemberValue(node: EnumMember): number { + computeEnumMemberValues(node.parent); return getNodeLinks(node).enumMemberValue; } + function getConstantValue(node: PropertyAccess): number { + var symbol = getNodeLinks(node).resolvedSymbol; + if (symbol && (symbol.flags & SymbolFlags.EnumMember)) { + var declaration = symbol.valueDeclaration; + var constantValue: number; + if (declaration.kind === SyntaxKind.EnumMember && (constantValue = getNodeLinks(declaration).enumMemberValue) !== undefined) { + return constantValue; + } + } + + return undefined; + } + + // Create a single instance that we can wrap the underlying emitter TextWriter with. That + // way we don't have to allocate a new wrapper every time writeTypeAtLocation and + // writeReturnTypeOfSignatureDeclaration are called. + var emitSymbolWriter = { + writer: undefined, + + writeKind: function (text: string) { this.writer.write(text) }, + writeSymbol: function (text: string) { this.writer.write(text) }, + writeLine: function () { this.writer.writeLine() }, + increaseIndent: function () { this.writer.increaseIndent() }, + decreaseIndent: function () { this.writer.decreaseIndent() }, + clear: function () { }, + trackSymbol: function (symbol: Symbol, declaration: Node, meaning: SymbolFlags) { this.writer.trackSymbol(symbol, declaration, meaning) } + }; + function writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter) { // Get type of the symbol if this is the valid symbol otherwise get type at location var symbol = getSymbolOfNode(location); var type = symbol && !(symbol.flags & SymbolFlags.TypeLiteral) ? getTypeOfSymbol(symbol) : getTypeFromTypeNode(location); - writeTypeToTextWriter(type, enclosingDeclaration, flags, writer); + emitSymbolWriter.writer = writer; + writeType(type, emitSymbolWriter, enclosingDeclaration, flags); } function writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter) { var signature = getSignatureFromDeclaration(signatureDeclaration); - writeTypeToTextWriter(getReturnTypeOfSignature(signature), enclosingDeclaration, flags , writer); + emitSymbolWriter.writer = writer; + writeType(getReturnTypeOfSignature(signature), emitSymbolWriter, enclosingDeclaration, flags); } function invokeEmitter(targetSourceFile?: SourceFile) { @@ -7356,7 +7643,6 @@ module ts { getProgram: () => program, getLocalNameOfContainer: getLocalNameOfContainer, getExpressionNamePrefix: getExpressionNamePrefix, - getPropertyAccessSubstitution: getPropertyAccessSubstitution, getExportAssignmentName: getExportAssignmentName, isReferencedImportDeclaration: isReferencedImportDeclaration, getNodeCheckFlags: getNodeCheckFlags, @@ -7367,9 +7653,9 @@ module ts { isImplementationOfOverload: isImplementationOfOverload, writeTypeAtLocation: writeTypeAtLocation, writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration, - writeSymbol: writeSymbolToTextWriter, isSymbolAccessible: isSymbolAccessible, - isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile + isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile, + getConstantValue: getConstantValue, }; checkProgram(); return emitFiles(resolver, targetSourceFile); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6bfa537c9f2..fb2bde52453 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -11,7 +11,9 @@ module ts { var result: U; if (array) { for (var i = 0, len = array.length; i < len; i++) { - if (result = callback(array[i])) break; + if (result = callback(array[i])) { + break; + } } } return result; @@ -39,6 +41,18 @@ module ts { return -1; } + export function countWhere(array: T[], predicate: (x: T) => boolean): number { + var count = 0; + if (array) { + for (var i = 0, len = array.length; i < len; i++) { + if (predicate(array[i])) { + count++; + } + } + } + return count; + } + export function filter(array: T[], f: (x: T) => boolean): T[] { if (array) { var result: T[] = []; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0377fbf71bb..4052350cf8c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -101,7 +101,7 @@ module ts { }; } - function createTextWriter(writeSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter { + function createTextWriter(trackSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter { var output = ""; var indent = 0; var lineStart = true; @@ -149,7 +149,7 @@ module ts { return { write: write, - writeSymbol: writeSymbol, + trackSymbol: trackSymbol, rawWrite: rawWrite, writeLiteral: writeLiteral, writeLine: writeLine, @@ -182,7 +182,7 @@ module ts { }); } - function emitComments(comments: Comment[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: Comment, writer: EmitTextWriter) => void) { + function emitComments(comments: CommentRange[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: CommentRange, writer: EmitTextWriter) => void) { var emitLeadingSpace = !trailingSeparator; forEach(comments, comment => { if (emitLeadingSpace) { @@ -203,7 +203,7 @@ module ts { }); } - function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: Comment[], writer: EmitTextWriter) { + function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: CommentRange[], writer: EmitTextWriter) { // If the leading comments start on different line than the start of node, write new line if (leadingComments && leadingComments.length && node.pos !== leadingComments[0].pos && getLineOfLocalPosition(node.pos) !== getLineOfLocalPosition(leadingComments[0].pos)) { @@ -211,7 +211,7 @@ module ts { } } - function writeCommentRange(comment: Comment, writer: EmitTextWriter) { + function writeCommentRange(comment: CommentRange, writer: EmitTextWriter) { if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos); var firstCommentLineIndent: number; @@ -307,7 +307,7 @@ module ts { } function emitJavaScript(jsFilePath: string, root?: SourceFile) { - var writer = createTextWriter(writeSymbol); + var writer = createTextWriter(trackSymbol); var write = writer.write; var writeLine = writer.writeLine; var increaseIndent = writer.increaseIndent; @@ -363,7 +363,7 @@ module ts { /** Sourcemap data that will get encoded */ var sourceMapData: SourceMapData; - function writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { } + function trackSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { } function initializeEmitterWithSourceMaps() { var sourceMapDir: string; // The directory in which sourcemap will be @@ -585,7 +585,7 @@ module ts { sourceMapNameIndices.pop(); }; - function writeCommentRangeWithMap(comment: Comment, writer: EmitTextWriter) { + function writeCommentRangeWithMap(comment: CommentRange, writer: EmitTextWriter) { recordSourceMapSpan(comment.pos); writeCommentRange(comment, writer); recordSourceMapSpan(comment.end); @@ -748,23 +748,46 @@ module ts { } } - function emitCommaList(nodes: Node[], count?: number) { - if (!(count >= 0)) count = nodes.length; - if (nodes) { - for (var i = 0; i < count; i++) { - if (i) write(", "); - emit(nodes[i]); + function emitTrailingCommaIfPresent(nodeList: NodeArray, isMultiline: boolean): void { + if (nodeList.hasTrailingComma) { + write(","); + if (isMultiline) { + writeLine(); } } } - function emitMultiLineList(nodes: Node[]) { + function emitCommaList(nodes: NodeArray, includeTrailingComma: boolean, count?: number) { + if (!(count >= 0)) { + count = nodes.length; + } + if (nodes) { + for (var i = 0; i < count; i++) { + if (i) { + write(", "); + } + emit(nodes[i]); + } + + if (includeTrailingComma) { + emitTrailingCommaIfPresent(nodes, /*isMultiline*/ false); + } + } + } + + function emitMultiLineList(nodes: NodeArray, includeTrailingComma: boolean) { if (nodes) { for (var i = 0; i < nodes.length; i++) { - if (i) write(","); + if (i) { + write(","); + } writeLine(); emit(nodes[i]); } + + if (includeTrailingComma) { + emitTrailingCommaIfPresent(nodes, /*isMultiline*/ true); + } } } @@ -876,14 +899,14 @@ module ts { if (node.flags & NodeFlags.MultiLine) { write("["); increaseIndent(); - emitMultiLineList(node.elements); + emitMultiLineList(node.elements, /*includeTrailingComma*/ true); decreaseIndent(); writeLine(); write("]"); } else { write("["); - emitCommaList(node.elements); + emitCommaList(node.elements, /*includeTrailingComma*/ true); write("]"); } } @@ -895,14 +918,14 @@ module ts { else if (node.flags & NodeFlags.MultiLine) { write("{"); increaseIndent(); - emitMultiLineList(node.properties); + emitMultiLineList(node.properties, /*includeTrailingComma*/ compilerOptions.target >= ScriptTarget.ES5); decreaseIndent(); writeLine(); write("}"); } else { write("{ "); - emitCommaList(node.properties); + emitCommaList(node.properties, /*includeTrailingComma*/ compilerOptions.target >= ScriptTarget.ES5); write(" }"); } } @@ -916,14 +939,15 @@ module ts { } function emitPropertyAccess(node: PropertyAccess) { - var text = resolver.getPropertyAccessSubstitution(node); - if (text) { - write(text); - return; + var constantValue = resolver.getConstantValue(node); + if (constantValue !== undefined) { + write(constantValue.toString() + " /* " + identifierToString(node.right) + " */"); + } + else { + emit(node.left); + write("."); + emit(node.right); } - emit(node.left); - write("."); - emit(node.right); } function emitIndexedAccess(node: IndexedAccess) { @@ -948,13 +972,13 @@ module ts { emitThis(node.func); if (node.arguments.length) { write(", "); - emitCommaList(node.arguments); + emitCommaList(node.arguments, /*includeTrailingComma*/ false); } write(")"); } else { write("("); - emitCommaList(node.arguments); + emitCommaList(node.arguments, /*includeTrailingComma*/ false); write(")"); } } @@ -964,7 +988,7 @@ module ts { emit(node.func); if (node.arguments) { write("("); - emitCommaList(node.arguments); + emitCommaList(node.arguments, /*includeTrailingComma*/ false); write(")"); } } @@ -1137,7 +1161,7 @@ module ts { if (node.declarations) { emitToken(SyntaxKind.VarKeyword, endPos); write(" "); - emitCommaList(node.declarations); + emitCommaList(node.declarations, /*includeTrailingComma*/ false); } if (node.initializer) { emit(node.initializer); @@ -1285,7 +1309,7 @@ module ts { function emitVariableStatement(node: VariableStatement) { emitLeadingComments(node); if (!(node.flags & NodeFlags.Export)) write("var "); - emitCommaList(node.declarations); + emitCommaList(node.declarations, /*includeTrailingComma*/ false); write(";"); emitTrailingComments(node); } @@ -1394,7 +1418,7 @@ module ts { increaseIndent(); write("("); if (node) { - emitCommaList(node.parameters, node.parameters.length - (hasRestParameters(node) ? 1 : 0)); + emitCommaList(node.parameters, /*includeTrailingComma*/ false, node.parameters.length - (hasRestParameters(node) ? 1 : 0)); } write(")"); decreaseIndent(); @@ -2155,7 +2179,7 @@ module ts { function getLeadingCommentsWithoutDetachedComments() { // get the leading comments from detachedPos - var leadingComments = getLeadingComments(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos); + var leadingComments = getLeadingCommentRanges(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos); if (detachedCommentsInfo.length - 1) { detachedCommentsInfo.pop(); } @@ -2169,14 +2193,14 @@ module ts { function getLeadingCommentsToEmit(node: Node) { // Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) { - var leadingComments: Comment[]; + var leadingComments: CommentRange[]; if (hasDetachedComments(node.pos)) { // get comments without detached comments leadingComments = getLeadingCommentsWithoutDetachedComments(); } else { // get the leading comments from the node - leadingComments = getLeadingCommentsOfNode(node, currentSourceFile); + leadingComments = getLeadingCommentRangesOfNode(node, currentSourceFile); } return leadingComments; } @@ -2192,21 +2216,21 @@ module ts { function emitTrailingDeclarationComments(node: Node) { // Emit the trailing comments only if the parent's end doesn't match if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) { - var trailingComments = getTrailingComments(currentSourceFile.text, node.end); + var trailingComments = getTrailingCommentRanges(currentSourceFile.text, node.end); // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ emitComments(trailingComments, /*trailingSeparator*/ false, writer, writeComment); } } function emitLeadingCommentsOfLocalPosition(pos: number) { - var leadingComments: Comment[]; + var leadingComments: CommentRange[]; if (hasDetachedComments(pos)) { // get comments without detached comments leadingComments = getLeadingCommentsWithoutDetachedComments(); } else { // get the leading comments from the node - leadingComments = getLeadingComments(currentSourceFile.text, pos); + leadingComments = getLeadingCommentRanges(currentSourceFile.text, pos); } emitNewLineBeforeLeadingComments({ pos: pos, end: pos }, leadingComments, writer); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space @@ -2214,10 +2238,10 @@ module ts { } function emitDetachedCommentsAtPosition(node: TextRange) { - var leadingComments = getLeadingComments(currentSourceFile.text, node.pos); + var leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos); if (leadingComments) { - var detachedComments: Comment[] = []; - var lastComment: Comment; + var detachedComments: CommentRange[] = []; + var lastComment: CommentRange; forEach(leadingComments, comment => { if (lastComment) { @@ -2261,7 +2285,7 @@ module ts { function emitPinnedOrTripleSlashCommentsOfNode(node: Node) { var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment); - function isPinnedOrTripleSlashComment(comment: Comment) { + function isPinnedOrTripleSlashComment(comment: CommentRange) { if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation; } @@ -2300,7 +2324,7 @@ module ts { } function emitDeclarations(jsFilePath: string, root?: SourceFile) { - var writer = createTextWriter(writeSymbol); + var writer = createTextWriter(trackSymbol); var write = writer.write; var writeLine = writer.writeLine; var increaseIndent = writer.increaseIndent; @@ -2328,7 +2352,7 @@ module ts { var oldWriter = writer; forEach(importDeclarations, aliasToWrite => { var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined); - writer = createTextWriter(writeSymbol); + writer = createTextWriter(trackSymbol); for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) { writer.increaseIndent(); } @@ -2339,10 +2363,9 @@ module ts { writer = oldWriter; } - function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { + function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning); if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) { - resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer); // write the aliases if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 62898664628..af1851d6a75 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -138,25 +138,27 @@ module ts { return ((node).expression).text === "use strict"; } - export function getLeadingCommentsOfNode(node: Node, sourceFileOfNode: SourceFile) { + export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) { + sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node); + // If parameter/type parameter, the prev token trailing comments are part of this node too if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) { // e.g. (/** blah */ a, /** blah */ b); - return concatenate(getTrailingComments(sourceFileOfNode.text, node.pos), + return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos), // e.g.: ( // /** blah */ a, // /** blah */ b); - getLeadingComments(sourceFileOfNode.text, node.pos)); + getLeadingCommentRanges(sourceFileOfNode.text, node.pos)); } else { - return getLeadingComments(sourceFileOfNode.text, node.pos); + return getLeadingCommentRanges(sourceFileOfNode.text, node.pos); } } export function getJsDocComments(node: Declaration, sourceFileOfNode: SourceFile) { - return filter(getLeadingCommentsOfNode(node, sourceFileOfNode), comment => isJsDocComment(comment)); + return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), comment => isJsDocComment(comment)); - function isJsDocComment(comment: Comment) { + function isJsDocComment(comment: CommentRange) { // True if the comment starts with '/**' but not if it is '/**/' return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && @@ -626,12 +628,6 @@ module ts { Parameters, // Parameters in parameter list } - enum TrailingCommaBehavior { - Disallow, - Allow, - Preserve - } - // Tracks whether we nested (directly or indirectly) in a certain control block. // Used for validating break and continue statements. enum ControlBlockContext { @@ -1203,7 +1199,7 @@ module ts { } // Parses a comma-delimited list of elements - function parseDelimitedList(kind: ParsingContext, parseElement: () => T, trailingCommaBehavior: TrailingCommaBehavior): NodeArray { + function parseDelimitedList(kind: ParsingContext, parseElement: () => T, allowTrailingComma: boolean): NodeArray { var saveParsingContext = parsingContext; parsingContext |= 1 << kind; var result = >[]; @@ -1228,15 +1224,14 @@ module ts { else if (isListTerminator(kind)) { // Check if the last token was a comma. if (commaStart >= 0) { - if (trailingCommaBehavior === TrailingCommaBehavior.Disallow) { + if (!allowTrailingComma) { if (file.syntacticErrors.length === errorCountBeforeParsingList) { // Report a grammar error so we don't affect lookahead grammarErrorAtPos(commaStart, scanner.getStartPos() - commaStart, Diagnostics.Trailing_comma_not_allowed); } } - else if (trailingCommaBehavior === TrailingCommaBehavior.Preserve) { - result.push(createNode(SyntaxKind.OmittedExpression)); - } + // Always preserve a trailing comma by marking it on the NodeArray + result.hasTrailingComma = true; } break; @@ -1271,7 +1266,7 @@ module ts { function parseBracketedList(kind: ParsingContext, parseElement: () => T, startToken: SyntaxKind, endToken: SyntaxKind): NodeArray { if (parseExpected(startToken)) { - var result = parseDelimitedList(kind, parseElement, TrailingCommaBehavior.Disallow); + var result = parseDelimitedList(kind, parseElement, /*allowTrailingComma*/ false); parseExpected(endToken); return result; } @@ -2172,10 +2167,10 @@ module ts { // The identifier eval or arguments may not appear as the LeftHandSideExpression of an // Assignment operator(11.13) or of a PostfixExpression(11.3) or as the UnaryExpression // operated upon by a Prefix Increment(11.4.4) or a Prefix Decrement(11.4.5) operator - if ((token === SyntaxKind.PlusPlusToken || token === SyntaxKind.MinusMinusToken) && isEvalOrArgumentsIdentifier(operand)) { + if ((operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken) && isEvalOrArgumentsIdentifier(operand)) { reportInvalidUseInStrictMode(operand); } - else if (token === SyntaxKind.DeleteKeyword && operand.kind === SyntaxKind.Identifier) { + else if (operator === SyntaxKind.DeleteKeyword && operand.kind === SyntaxKind.Identifier) { // When a delete operator occurs within strict mode code, a SyntaxError is thrown if its // UnaryExpression is a direct reference to a variable, function argument, or function name grammarErrorOnNode(operand, Diagnostics.delete_cannot_be_called_on_an_identifier_in_strict_mode); @@ -2307,7 +2302,11 @@ module ts { else { parseExpected(SyntaxKind.OpenParenToken); } - callExpr.arguments = parseDelimitedList(ParsingContext.ArgumentExpressions, parseAssignmentExpression, TrailingCommaBehavior.Disallow); + // It is an error to have a trailing comma in an argument list. However, the checker + // needs evidence of a trailing comma in order to give good results for signature help. + // That is why we do not allow a trailing comma, but we "preserve" a trailing comma. + callExpr.arguments = parseDelimitedList(ParsingContext.ArgumentExpressions, + parseArgumentExpression, /*allowTrailingComma*/ false); parseExpected(SyntaxKind.CloseParenToken); expr = finishNode(callExpr); continue; @@ -2376,15 +2375,33 @@ module ts { return finishNode(node); } + function parseAssignmentExpressionOrOmittedExpression(omittedExpressionDiagnostic: DiagnosticMessage): Expression { + if (token === SyntaxKind.CommaToken) { + if (omittedExpressionDiagnostic) { + var errorStart = scanner.getTokenPos(); + var errorLength = scanner.getTextPos() - errorStart; + grammarErrorAtPos(errorStart, errorLength, omittedExpressionDiagnostic); + } + return createNode(SyntaxKind.OmittedExpression); + } + + return parseAssignmentExpression(); + } + function parseArrayLiteralElement(): Expression { - return token === SyntaxKind.CommaToken ? createNode(SyntaxKind.OmittedExpression) : parseAssignmentExpression(); + return parseAssignmentExpressionOrOmittedExpression(/*omittedExpressionDiagnostic*/ undefined); + } + + function parseArgumentExpression(): Expression { + return parseAssignmentExpressionOrOmittedExpression(Diagnostics.Argument_expression_expected); } function parseArrayLiteral(): ArrayLiteral { var node = createNode(SyntaxKind.ArrayLiteral); parseExpected(SyntaxKind.OpenBracketToken); if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine; - node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArrayLiteralElement, TrailingCommaBehavior.Preserve); + node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, + parseArrayLiteralElement, /*allowTrailingComma*/ true); parseExpected(SyntaxKind.CloseBracketToken); return finishNode(node); } @@ -2426,10 +2443,7 @@ module ts { node.flags |= NodeFlags.MultiLine; } - // ES3 itself does not accept a trailing comma in an object literal, however, we'd like to preserve it in ES5. - var trailingCommaBehavior = languageVersion === ScriptTarget.ES3 ? TrailingCommaBehavior.Allow : TrailingCommaBehavior.Preserve; - - node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, trailingCommaBehavior); + node.properties = parseDelimitedList(ParsingContext.ObjectLiteralMembers, parseObjectLiteralMember, /*allowTrailingComma*/ true); parseExpected(SyntaxKind.CloseBraceToken); var seen: Map = {}; @@ -2518,7 +2532,11 @@ module ts { parseExpected(SyntaxKind.NewKeyword); node.func = parseCallAndAccess(parsePrimaryExpression(), /* inNewExpression */ true); if (parseOptional(SyntaxKind.OpenParenToken) || token === SyntaxKind.LessThanToken && (node.typeArguments = tryParse(parseTypeArgumentsAndOpenParen))) { - node.arguments = parseDelimitedList(ParsingContext.ArgumentExpressions, parseAssignmentExpression, TrailingCommaBehavior.Disallow); + // It is an error to have a trailing comma in an argument list. However, the checker + // needs evidence of a trailing comma in order to give good results for signature help. + // That is why we do not allow a trailing comma, but we "preserve" a trailing comma. + node.arguments = parseDelimitedList(ParsingContext.ArgumentExpressions, + parseArgumentExpression, /*allowTrailingComma*/ false); parseExpected(SyntaxKind.CloseParenToken); } return finishNode(node); @@ -3087,7 +3105,8 @@ module ts { } function parseVariableDeclarationList(flags: NodeFlags, noIn?: boolean): NodeArray { - return parseDelimitedList(ParsingContext.VariableDeclarations, () => parseVariableDeclaration(flags, noIn), TrailingCommaBehavior.Disallow); + return parseDelimitedList(ParsingContext.VariableDeclarations, + () => parseVariableDeclaration(flags, noIn), /*allowTrailingComma*/ false); } function parseVariableStatement(pos?: number, flags?: NodeFlags): VariableStatement { @@ -3486,7 +3505,8 @@ module ts { var implementsKeywordLength: number; if (parseOptional(SyntaxKind.ImplementsKeyword)) { implementsKeywordLength = scanner.getStartPos() - implementsKeywordStart; - node.implementedTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, parseTypeReference, TrailingCommaBehavior.Disallow); + node.implementedTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, + parseTypeReference, /*allowTrailingComma*/ false); } var errorCountBeforeClassBody = file.syntacticErrors.length; if (parseExpected(SyntaxKind.OpenBraceToken)) { @@ -3514,7 +3534,8 @@ module ts { var extendsKeywordLength: number; if (parseOptional(SyntaxKind.ExtendsKeyword)) { extendsKeywordLength = scanner.getStartPos() - extendsKeywordStart; - node.baseTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, parseTypeReference, TrailingCommaBehavior.Disallow); + node.baseTypes = parseDelimitedList(ParsingContext.BaseTypeReferences, + parseTypeReference, /*allowTrailingComma*/ false); } var errorCountBeforeInterfaceBody = file.syntacticErrors.length; node.members = parseTypeLiteral().members; @@ -3578,7 +3599,8 @@ module ts { parseExpected(SyntaxKind.EnumKeyword); node.name = parseIdentifier(); if (parseExpected(SyntaxKind.OpenBraceToken)) { - node.members = parseDelimitedList(ParsingContext.EnumMembers, parseAndCheckEnumMember, TrailingCommaBehavior.Allow); + node.members = parseDelimitedList(ParsingContext.EnumMembers, + parseAndCheckEnumMember, /*allowTrailingComma*/ true); parseExpected(SyntaxKind.CloseBraceToken); } else { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index f627bee6c51..81d16b5f487 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -371,8 +371,8 @@ module ts { // between the given position and the next line break are returned. The return value is an array containing a TextRange for each // comment. Single-line comment ranges include the beginning '//' characters but not the ending line break. Multi-line comment // ranges include the beginning '/* and ending '*/' characters. The return value is undefined if no comments were found. - function getCommentRanges(text: string, pos: number, trailing: boolean): Comment[] { - var result: Comment[]; + function getCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] { + var result: CommentRange[]; var collecting = trailing || pos === 0; while (true) { var ch = text.charCodeAt(pos); @@ -440,11 +440,11 @@ module ts { } } - export function getLeadingComments(text: string, pos: number): Comment[] { + export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] { return getCommentRanges(text, pos, /*trailing*/ false); } - export function getTrailingComments(text: string, pos: number): Comment[] { + export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] { return getCommentRanges(text, pos, /*trailing*/ true); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d9c2a420fb6..991e3096daa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -228,7 +228,9 @@ module ts { FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken, FirstToken = EndOfFileToken, - LastToken = StringKeyword + LastToken = StringKeyword, + FirstTriviaToken = SingleLineCommentTrivia, + LastTriviaToken = WhitespaceTrivia } export enum NodeFlags { @@ -259,7 +261,9 @@ module ts { localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes) } - export interface NodeArray extends Array, TextRange { } + export interface NodeArray extends Array, TextRange { + hasTrailingComma?: boolean; + } export interface Identifier extends Node { text: string; // Text of identifier (with escapes converted to characters) @@ -529,7 +533,7 @@ module ts { filename: string; } - export interface Comment extends TextRange { + export interface CommentRange extends TextRange { hasTrailingNewLine?: boolean; } @@ -640,15 +644,22 @@ module ts { getApparentType(type: Type): ApparentType; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string; + typeToDisplayParts(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[]; + symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[]; getFullyQualifiedName(symbol: Symbol): string; getAugmentedPropertiesOfApparentType(type: Type): Symbol[]; getRootSymbol(symbol: Symbol): Symbol; getContextualType(node: Node): Type; + getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature; + + // Returns the constant value of this enum member, or 'undefined' if the enum member has a + // computed value. + getEnumMemberValue(node: EnumMember): number; } export interface TextWriter { write(s: string): void; - writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; + trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; writeLine(): void; increaseIndent(): void; decreaseIndent(): void; @@ -679,7 +690,6 @@ module ts { getProgram(): Program; getLocalNameOfContainer(container: Declaration): string; getExpressionNamePrefix(node: Identifier): string; - getPropertyAccessSubstitution(node: PropertyAccess): string; getExportAssignmentName(node: SourceFile): string; isReferencedImportDeclaration(node: ImportDeclaration): boolean; isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean; @@ -690,9 +700,12 @@ module ts { isImplementationOfOverload(node: FunctionDeclaration): boolean; writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; - writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, writer: TextWriter): void; isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult; isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult; + + // Returns the constant value this property access resolves to, or 'undefined' if it does + // resolve to a constant. + getConstantValue(node: PropertyAccess): number; } export enum SymbolFlags { @@ -794,13 +807,16 @@ module ts { } export enum NodeCheckFlags { - TypeChecked = 0x00000001, // Node has been type checked - LexicalThis = 0x00000002, // Lexical 'this' reference - CaptureThis = 0x00000004, // Lexical 'this' used in body - EmitExtends = 0x00000008, // Emit __extends - SuperInstance = 0x00000010, // Instance 'super' reference - SuperStatic = 0x00000020, // Static 'super' reference - ContextChecked = 0x00000040, // Contextual types have been assigned + TypeChecked = 0x00000001, // Node has been type checked + LexicalThis = 0x00000002, // Lexical 'this' reference + CaptureThis = 0x00000004, // Lexical 'this' used in body + EmitExtends = 0x00000008, // Emit __extends + SuperInstance = 0x00000010, // Instance 'super' reference + SuperStatic = 0x00000020, // Static 'super' reference + ContextChecked = 0x00000040, // Contextual types have been assigned + + // Values for enum members have been computed, and any errors have been reported for them. + EnumValuesComputed = 0x00000080, } export interface NodeLinks { @@ -922,7 +938,7 @@ module ts { resolvedReturnType: Type; // Resolved return type minArgumentCount: number; // Number of non-optional parameters hasRestParameter: boolean; // True if last parameter is rest parameter - hasStringLiterals: boolean; // True if instantiated + hasStringLiterals: boolean; // True if specialized target?: Signature; // Instantiation target mapper?: TypeMapper; // Instantiation mapper erasedSignatureCache?: Signature; // Erased version of signature (deferred) @@ -1171,6 +1187,48 @@ module ts { verticalTab = 0x0B, // \v } + export class SymbolDisplayPart { + constructor(public text: string, + public kind: SymbolDisplayPartKind, + public symbol: Symbol) { + } + + public toJSON() { + return { + text: this.text, + kind: SymbolDisplayPartKind[this.kind] + }; + } + } + + export enum SymbolDisplayPartKind { + aliasName, + className, + enumName, + fieldName, + interfaceName, + keyword, + labelName, + lineBreak, + numericLiteral, + stringLiteral, + localName, + methodName, + moduleName, + namespaceName, + operator, + parameterName, + propertyName, + punctuation, + space, + anonymousTypeIndicator, + text, + typeParameterName, + enumMemberName, + functionName, + regularExpressionLiteral, + } + export interface CancellationToken { isCancellationRequested(): boolean; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index ed6dc1a71f7..0dfcb4ac513 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -819,14 +819,14 @@ module FourSlash { public verifyCurrentSignatureHelpIs(expected: string) { this.taoInvalidReason = 'verifyCurrentSignatureHelpIs NYI'; - var help = this.getActiveSignatureHelp(); + var help = this.getActiveSignatureHelpItem(); assert.equal(help.prefix + help.parameters.map(p => p.display).join(help.separator) + help.suffix, expected); } public verifyCurrentParameterIsVariable(isVariable: boolean) { this.taoInvalidReason = 'verifyCurrentParameterIsVariable NYI'; - var signature = this.getActiveSignatureHelp(); + var signature = this.getActiveSignatureHelpItem(); assert.isNotNull(signature); assert.equal(isVariable, signature.isVariadic); } @@ -842,7 +842,7 @@ module FourSlash { public verifyCurrentParameterSpanIs(parameter: string) { this.taoInvalidReason = 'verifyCurrentParameterSpanIs NYI'; - var activeSignature = this.getActiveSignatureHelp(); + var activeSignature = this.getActiveSignatureHelpItem(); var activeParameter = this.getActiveParameter(); assert.equal(activeParameter.display, parameter); } @@ -858,19 +858,19 @@ module FourSlash { public verifyCurrentSignatureHelpParameterCount(expectedCount: number) { this.taoInvalidReason = 'verifyCurrentSignatureHelpParameterCount NYI'; - assert.equal(this.getActiveSignatureHelp().parameters.length, expectedCount); + assert.equal(this.getActiveSignatureHelpItem().parameters.length, expectedCount); } public verifyCurrentSignatureHelpTypeParameterCount(expectedCount: number) { this.taoInvalidReason = 'verifyCurrentSignatureHelpTypeParameterCount NYI'; - // assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount); + // assert.equal(this.getActiveSignatureHelpItem().typeParameters.length, expectedCount); } public verifyCurrentSignatureHelpDocComment(docComment: string) { this.taoInvalidReason = 'verifyCurrentSignatureHelpDocComment NYI'; - var actualDocComment = this.getActiveSignatureHelp().documentation; + var actualDocComment = this.getActiveSignatureHelpItem().documentation; assert.equal(actualDocComment, docComment); } @@ -941,7 +941,7 @@ module FourSlash { // return help.formal; //} - private getActiveSignatureHelp() { + private getActiveSignatureHelpItem() { var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); // If the signature hasn't been narrowed down yet (e.g. no parameters have yet been entered), @@ -953,14 +953,13 @@ module FourSlash { } private getActiveParameter(): ts.SignatureHelpParameter { - var currentSig = this.getActiveSignatureHelp(); var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); var item = help.items[help.selectedItemIndex]; var state = this.languageService.getSignatureHelpCurrentArgumentState(this.activeFile.fileName, this.currentCaretPosition, help.applicableSpan.start()); // Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed - var currentParam = state === null ? 0 : state.argumentIndex; + var currentParam = state === undefined ? 0 : state.argumentIndex; return item.parameters[currentParam]; } @@ -1083,7 +1082,7 @@ module FourSlash { } public printCurrentSignatureHelp() { - var sigHelp = this.getActiveSignatureHelp(); + var sigHelp = this.getActiveSignatureHelpItem(); Harness.IO.log(JSON.stringify(sigHelp)); } @@ -1661,9 +1660,9 @@ module FourSlash { } var actualMatchPosition = -1; - if (bracePosition >= actual[0].start() && bracePosition <= actual[0].end()) { + if (bracePosition === actual[0].start()) { actualMatchPosition = actual[1].start(); - } else if (bracePosition >= actual[1].start() && bracePosition <= actual[1].end()) { + } else if (bracePosition === actual[1].start()) { actualMatchPosition = actual[0].start(); } else { throw new Error('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start() + ',' + actual[0].end() + ') and (' + actual[1].start() + ',' + actual[1].end() + ')'); diff --git a/src/services/braceMatcher.ts b/src/services/braceMatcher.ts deleted file mode 100644 index 3615f677024..00000000000 --- a/src/services/braceMatcher.ts +++ /dev/null @@ -1,73 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -/// - -module TypeScript.Services { - export class BraceMatcher { - - // Given a script name and position in the script, return a pair of text range if the - // position corresponds to a "brace matchin" characters (e.g. "{" or "(", etc.) - // If the position is not on any range, return an empty set. - public static getMatchSpans(syntaxTree: TypeScript.SyntaxTree, position: number): TypeScript.TextSpan[] { - var result: TypeScript.TextSpan[] = []; - - var token = findToken(syntaxTree.sourceUnit(), position); - - if (start(token) === position) { - var matchKind = BraceMatcher.getMatchingTokenKind(token); - - if (matchKind !== null) { - var parentElement = token.parent; - - for (var i = 0, n = childCount(parentElement); i < n; i++) { - var current = childAt(parentElement, i); - - if (current !== null && fullWidth(current) > 0) { - if (current.kind() === matchKind) { - var range1 = new TypeScript.TextSpan(start(token), width(token)); - var range2 = new TypeScript.TextSpan(start(current), width(current)); - if (range1.start() < range2.start()) { - result.push(range1, range2); - } - else { - result.push(range2, range1); - } - break; - } - } - } - } - } - - return result; - } - - private static getMatchingTokenKind(token: TypeScript.ISyntaxToken): TypeScript.SyntaxKind { - switch (token.kind()) { - case TypeScript.SyntaxKind.OpenBraceToken: return TypeScript.SyntaxKind.CloseBraceToken - case TypeScript.SyntaxKind.OpenParenToken: return TypeScript.SyntaxKind.CloseParenToken; - case TypeScript.SyntaxKind.OpenBracketToken: return TypeScript.SyntaxKind.CloseBracketToken; - case TypeScript.SyntaxKind.LessThanToken: return TypeScript.SyntaxKind.GreaterThanToken; - case TypeScript.SyntaxKind.CloseBraceToken: return TypeScript.SyntaxKind.OpenBraceToken - case TypeScript.SyntaxKind.CloseParenToken: return TypeScript.SyntaxKind.OpenParenToken; - case TypeScript.SyntaxKind.CloseBracketToken: return TypeScript.SyntaxKind.OpenBracketToken; - case TypeScript.SyntaxKind.GreaterThanToken: return TypeScript.SyntaxKind.LessThanToken; - } - - return null; - } - } -} \ No newline at end of file diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index ad07f884cc5..8021a47cee7 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -2,7 +2,6 @@ module ts.formatting { export module SmartIndenter { - export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number { if (position > sourceFile.text.length) { return 0; // past EOF @@ -108,8 +107,10 @@ module ts.formatting { */ function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it - var itemInfo = findPrecedingListItem(commaToken); - return deriveActualIndentationFromList(itemInfo.list.getChildren(), itemInfo.listItemIndex, sourceFile, options); + var commaItemInfo = findListItemInfo(commaToken); + Debug.assert(commaItemInfo.listItemIndex > 0); + // The item we're interested in is right before the comma + return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options); } /* @@ -167,27 +168,6 @@ module ts.formatting { return sourceFile.getLineAndCharacterFromPosition(n.getStart(sourceFile)); } - function findPrecedingListItem(commaToken: Node): { listItemIndex: number; list: Node } { - // CommaToken node is synthetic and thus will be stored in SyntaxList, however parent of the CommaToken points to the container of the SyntaxList skipping the list. - // In order to find the preceding list item we first need to locate SyntaxList itself and then search for the position of CommaToken - var syntaxList = forEach(commaToken.parent.getChildren(), c => { - // find syntax list that covers the span of CommaToken - if (c.kind == SyntaxKind.SyntaxList && c.pos <= commaToken.end && c.end >= commaToken.end) { - return c; - } - }); - Debug.assert(syntaxList); - - var children = syntaxList.getChildren(); - var commaIndex = indexOf(children, commaToken); - Debug.assert(commaIndex !== -1 && commaIndex !== 0); - - return { - listItemIndex: commaIndex - 1, - list: syntaxList - }; - } - function positionBelongsToNode(candidate: Node, position: number, sourceFile: SourceFile): boolean { return candidate.end > position || !isCompletedNode(candidate, sourceFile); } @@ -288,112 +268,6 @@ module ts.formatting { return column; } - function findNextToken(previousToken: Node, parent: Node): Node { - return find(parent); - - function find(n: Node): Node { - if (isToken(n) && n.pos === previousToken.end) { - // this is token that starts at the end of previous token - return it - return n; - } - - var children = n.getChildren(); - for (var i = 0, len = children.length; i < len; ++i) { - var child = children[i]; - var shouldDiveInChildNode = - // previous token is enclosed somewhere in the child - (child.pos <= previousToken.pos && child.end > previousToken.end) || - // previous token ends exactly at the beginning of child - (child.pos === previousToken.end); - - if (shouldDiveInChildNode && nodeHasTokens(child)) { - return find(child); - } - } - - return undefined; - } - } - - function findPrecedingToken(position: number, sourceFile: SourceFile): Node { - return find(sourceFile); - - function findRightmostToken(n: Node): Node { - if (isToken(n)) { - return n; - } - - var children = n.getChildren(); - var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); - return candidate && findRightmostToken(candidate); - - } - - function find(n: Node): Node { - if (isToken(n)) { - return n; - } - - var children = n.getChildren(); - for (var i = 0, len = children.length; i < len; ++i) { - var child = children[i]; - if (nodeHasTokens(child)) { - if (position < child.end) { - if (child.getStart(sourceFile) >= position) { - // actual start of the node is past the position - previous token should be at the end of previous child - var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i); - return candidate && findRightmostToken(candidate) - } - else { - // candidate should be in this node - return find(child); - } - } - } - } - - Debug.assert(n.kind === SyntaxKind.SourceFile); - - // Here we know that none of child token nodes embrace the position, - // the only known case is when position is at the end of the file. - // Try to find the rightmost token in the file without filtering. - // Namely we are skipping the check: 'position < node.end' - if (children.length) { - var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); - return candidate && findRightmostToken(candidate); - } - } - - /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition' - function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node { - for (var i = exclusiveStartPosition - 1; i >= 0; --i) { - if (nodeHasTokens(children[i])) { - return children[i]; - } - } - } - } - - /* - * Checks if node is something that can contain tokens (except EOF) - filters out EOF tokens, Missing\Omitted expressions, empty SyntaxLists and expression statements that wrap any of listed nodes. - */ - function nodeHasTokens(n: Node): boolean { - if (n.kind === SyntaxKind.ExpressionStatement) { - return nodeHasTokens((n).expression); - } - - if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) { - return false; - } - - // SyntaxList is already realized so getChildCount should be fast and non-expensive - return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0; - } - - function isToken(n: Node): boolean { - return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; - } - function nodeContentIsIndented(parent: Node, child: Node): boolean { switch (parent.kind) { case SyntaxKind.ClassDeclaration: diff --git a/src/services/services.ts b/src/services/services.ts index 74e1eb6cf98..a2595473252 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -7,9 +7,10 @@ /// /// /// -/// /// /// +/// +/// /// /// @@ -46,6 +47,7 @@ module ts { getFlags(): SymbolFlags; getName(): string; getDeclarations(): Declaration[]; + getDocumentationComment(): string; } export interface Type { @@ -97,9 +99,7 @@ module ts { private _children: Node[]; public getSourceFile(): SourceFile { - var node: Node = this; - while (node.kind !== SyntaxKind.SourceFile) node = node.parent; - return node; + return getSourceFileOfNode(this); } public getStart(sourceFile?: SourceFile): number { @@ -203,7 +203,7 @@ module ts { } public getFirstToken(sourceFile?: SourceFile): Node { - var children = this.getChildren(sourceFile); + var children = this.getChildren(); for (var i = 0; i < children.length; i++) { var child = children[i]; if (child.kind < SyntaxKind.Missing) return child; @@ -225,19 +225,176 @@ module ts { flags: SymbolFlags; name: string; declarations: Declaration[]; + + // Undefined is used to indicate the value has not been computed. If, after computing, the + // symbol has no doc comment, then the empty string will be returned. + documentationComment: string; + constructor(flags: SymbolFlags, name: string) { this.flags = flags; this.name = name; } + getFlags(): SymbolFlags { return this.flags; } + getName(): string { return this.name; } + getDeclarations(): Declaration[] { return this.declarations; } + + getDocumentationComment(): string { + if (this.documentationComment === undefined) { + var lines: string[] = []; + + // Get the doc comments from all the declarations of this symbol, and merge them + // into one single doc comment. + var declarations = this.getDeclarations(); + if (declarations) { + for (var i = 0, n = declarations.length; i < n; i++) { + this.processDocumentationCommentDeclaration(lines, declarations[0]); + } + } + + // TODO: get the newline info from the host. + this.documentationComment = lines.join("\r\n"); + } + + return this.documentationComment; + } + + private processDocumentationCommentDeclaration(lines: string[], declaration: Node) { + var commentRanges = getLeadingCommentRangesOfNode(declaration); + if (commentRanges) { + var sourceFile = declaration.getSourceFile(); + + for (var i = 0, n = commentRanges.length; i < n; i++) { + this.processDocumentationCommentRange( + lines, sourceFile, commentRanges[0]); + } + } + } + + private processDocumentationCommentRange(lines: string[], sourceFile: SourceFile, commentRange: CommentRange) { + // We only care about well-formed /** */ comments + if (commentRange.end - commentRange.pos > "/**/".length && + sourceFile.text.substr(commentRange.pos, "/**".length) === "/**" && + sourceFile.text.substr(commentRange.end - "*/".length, "*/".length) === "*/") { + + // Put a newline between each converted comment we join together. + if (lines.length) { + lines.push(""); + } + + var startLineAndChar = sourceFile.getLineAndCharacterFromPosition(commentRange.pos); + var endLineAndChar = sourceFile.getLineAndCharacterFromPosition(commentRange.end); + + if (startLineAndChar.line === endLineAndChar.line) { + // A single line doc comment. Just extract the text between the + // comment markers and add that to the doc comment we're building + // up. + lines.push(sourceFile.text.substring(commentRange.pos + "/**".length, commentRange.end - "*/".length).trim()); + } + else { + this.processMultiLineDocumentationCommentRange(sourceFile, commentRange, startLineAndChar, endLineAndChar, lines); + } + } + } + + private processMultiLineDocumentationCommentRange( + sourceFile: SourceFile, commentRange: CommentRange, + startLineAndChar: { line: number; character: number }, + endLineAndChar: { line: number; character: number }, + lines: string[]) { + + // Comment spanned multiple lines. Find the leftmost character + // position in each line, and use that to determine what we should + // trim off, and what part of the line to keep. + // i.e. if the comment looks like: + // + // /** Foo + // * Bar + // * Baz + // */ + // + // Then we'll want to add: + // Foo + // Bar + // Baz + var trimLength: number = undefined; + for (var iLine = startLineAndChar.line + 1; iLine <= endLineAndChar.line; iLine++) { + var lineStart = sourceFile.getPositionFromLineAndCharacter(iLine, /*character:*/ 1); + var lineEnd = iLine === endLineAndChar.line + ? commentRange.end - "*/".length + : sourceFile.getPositionFromLineAndCharacter(iLine + 1, 1); + var docCommentTriviaLength = this.skipDocumentationCommentTrivia(sourceFile.text, lineStart, lineEnd); + + if (trimLength === undefined || (docCommentTriviaLength && docCommentTriviaLength < trimLength)) { + trimLength = docCommentTriviaLength; + } + } + + // Add the first line in. + var firstLine = sourceFile.text.substring( + commentRange.pos + "/**".length, + sourceFile.getPositionFromLineAndCharacter(startLineAndChar.line + 1, /*character:*/ 1)).trim(); + if (firstLine !== "") { + lines.push(firstLine); + } + + // For all the lines up to the last (but not including the last), add the contents + // of the line (with the length up to the + for (var iLine = startLineAndChar.line + 1; iLine < endLineAndChar.line; iLine++) { + var line = this.trimRight(sourceFile.text.substring( + sourceFile.getPositionFromLineAndCharacter(iLine, /*character*/ 1), + sourceFile.getPositionFromLineAndCharacter(iLine + 1, /*character*/ 1))).substr(trimLength); + + lines.push(line); + } + + // Add the last line if there is any actual text before the */ + var lastLine = this.trimRight(sourceFile.text.substring( + sourceFile.getPositionFromLineAndCharacter(endLineAndChar.line, /*character:*/ 1), + commentRange.end - "*/".length)).substr(trimLength); + + if (lastLine !== "") { + lines.push(lastLine); + } + } + + private trimRight(val: string) { + return val.replace(/(\n|\r|\s)+$/, ''); + } + + private skipDocumentationCommentTrivia(text: string, lineStart: number, lineEnd: number): number { + var seenAsterisk = false; + var lineLength = lineEnd - lineStart; + for (var i = 0; i < lineLength; i++) { + var char = text.charCodeAt(i + lineStart); + if (char === CharacterCodes.asterisk && !seenAsterisk) { + // Ignore the first asterisk we see. We want to trim out the line of *'s + // commonly seen at the start of a doc comment. + seenAsterisk = true; + continue; + } + else if (isLineBreak(char)) { + // This was a blank line. Just ignore it wrt computing the leading whitespace to + // trim. + break; + } + else if (!isWhiteSpace(char)) { + // Found a real doc comment character. Keep track of it so we can determine how + // much of the doc comment leading trivia to trim off. + return i; + } + } + + return undefined; + } } class TypeObject implements Type { @@ -495,6 +652,7 @@ module ts { getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; getTypeAtPosition(fileName: string, position: number): TypeInfo; + getQuickInfoAtPosition(fileName: string, position: number): QuickInfo; getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TypeScript.TextSpan; @@ -652,6 +810,15 @@ module ts { text: string; } + export class QuickInfo { + constructor(public kind: string, + public kindModifiers: string, + public textSpan: TypeScript.TextSpan, + public displayParts: SymbolDisplayPart[], + public documentation: SymbolDisplayPart[]) { + } + } + export class TypeInfo { constructor( public memberName: TypeScript.MemberName, @@ -964,7 +1131,7 @@ module ts { export class OperationCanceledException { } - class CancellationTokenObject { + export class CancellationTokenObject { public static None: CancellationTokenObject = new CancellationTokenObject(null) @@ -1468,11 +1635,14 @@ module ts { var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider; var hostCache: HostCache; // A cache of all the information about the files on the host side. var program: Program; + // this checker is used to answer all LS questions except errors var typeInfoResolver: TypeChecker; + // the sole purpose of this checker is to return semantic diagnostics // creation is deferred - use getFullTypeCheckChecker to get instance var fullTypeCheckChecker_doNotAccessDirectly: TypeChecker; + var useCaseSensitivefilenames = false; var sourceFilesByName: Map = {}; var documentRegistry = documentRegistry; @@ -1722,11 +1892,10 @@ module ts { return undefined; } - var declarations = symbol.getDeclarations(); return { name: displayName, kind: getSymbolKind(symbol), - kindModifiers: declarations ? getNodeModifiers(declarations[0]) : ScriptElementKindModifier.none + kindModifiers: getSymbolModifiers(symbol) }; } @@ -2092,40 +2261,6 @@ module ts { } } - /** Get the token whose text contains the position, or the containing node. */ - function getNodeAtPosition(sourceFile: SourceFile, position: number) { - var current: Node = sourceFile; - outer: while (true) { - // find the child that has this - for (var i = 0, n = current.getChildCount(); i < n; i++) { - var child = current.getChildAt(i); - if (child.getStart() <= position && position < child.getEnd()) { - current = child; - continue outer; - } - } - return current; - } - } - - /** Get a token that contains the position. This is guaranteed to return a token, the position can be in the - * leading trivia or within the token text. - */ - function getTokenAtPosition(sourceFile: SourceFile, position: number) { - var current: Node = sourceFile; - outer: while (true) { - // find the child that has this - for (var i = 0, n = current.getChildCount(); i < n; i++) { - var child = current.getChildAt(i); - if (child.getFullStart() <= position && position < child.getEnd()) { - current = child; - continue outer; - } - } - return current; - } - } - function getContainerNode(node: Node): Node { while (true) { node = node.parent; @@ -2207,6 +2342,12 @@ module ts { } } + function getSymbolModifiers(symbol: Symbol): string { + return symbol && symbol.declarations && symbol.declarations.length > 0 + ? getNodeModifiers(symbol.declarations[0]) + : ScriptElementKindModifier.none; + } + function getNodeModifiers(node: Node): string { var flags = node.flags; var result: string[] = []; @@ -2220,7 +2361,114 @@ module ts { return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; } - /// QuickInfo + function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo { + synchronizeHostData(); + + fileName = TypeScript.switchToForwardSlashes(fileName); + var sourceFile = getSourceFile(fileName); + var node = getNodeAtPosition(sourceFile, position); + if (!node) { + return undefined; + } + + var symbol = typeInfoResolver.getSymbolInfo(node); + if (!symbol) { + return undefined; + } + + var documentation = symbol.getDocumentationComment(); + var documentationParts = documentation === "" ? [] : [new SymbolDisplayPart(documentation, SymbolDisplayPartKind.text, /*symbol:*/ null)]; + + // Having all this logic here is pretty unclean. Consider moving to the roslyn model + // where all symbol display logic is encapsulated into visitors and options. + var totalParts: SymbolDisplayPart[] = []; + + if (symbol.flags & SymbolFlags.Class) { + totalParts.push(new SymbolDisplayPart("class", SymbolDisplayPartKind.keyword, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); + } + else if (symbol.flags & SymbolFlags.Interface) { + totalParts.push(new SymbolDisplayPart("interface", SymbolDisplayPartKind.keyword, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); + } + else if (symbol.flags & SymbolFlags.Enum) { + totalParts.push(new SymbolDisplayPart("enum", SymbolDisplayPartKind.keyword, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); + } + else if (symbol.flags & SymbolFlags.Module) { + totalParts.push(new SymbolDisplayPart("module", SymbolDisplayPartKind.keyword, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, sourceFile)); + } + else if (symbol.flags & SymbolFlags.TypeParameter) { + totalParts.push(new SymbolDisplayPart("(", SymbolDisplayPartKind.punctuation, undefined)); + totalParts.push(new SymbolDisplayPart("type parameter", SymbolDisplayPartKind.text, undefined)); + totalParts.push(new SymbolDisplayPart(")", SymbolDisplayPartKind.punctuation, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol)); + } + else { + totalParts.push(new SymbolDisplayPart("(", SymbolDisplayPartKind.punctuation, undefined)); + var text: string; + + if (symbol.flags & SymbolFlags.Property) { text = "property" } + else if (symbol.flags & SymbolFlags.EnumMember) { text = "enum member" } + else if (symbol.flags & SymbolFlags.Function) { text = "function" } + else if (symbol.flags & SymbolFlags.Variable) { text = "variable" } + else if (symbol.flags & SymbolFlags.Method) { text = "method" } + + if (!text) { + return undefined; + } + + totalParts.push(new SymbolDisplayPart(text, SymbolDisplayPartKind.text, undefined)); + totalParts.push(new SymbolDisplayPart(")", SymbolDisplayPartKind.punctuation, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + + totalParts.push.apply(totalParts, typeInfoResolver.symbolToDisplayParts(symbol, getContainerNode(node))); + + var type = typeInfoResolver.getTypeOfSymbol(symbol); + + if (symbol.flags & SymbolFlags.Property || + symbol.flags & SymbolFlags.Variable) { + + if (type) { + totalParts.push(new SymbolDisplayPart(":", SymbolDisplayPartKind.punctuation, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push.apply(totalParts, typeInfoResolver.typeToDisplayParts(type, getContainerNode(node))); + } + } + else if (symbol.flags & SymbolFlags.Function || + symbol.flags & SymbolFlags.Method) { + if (type) { + totalParts.push.apply(totalParts, typeInfoResolver.typeToDisplayParts(type, getContainerNode(node))); + } + } + else if (symbol.flags & SymbolFlags.EnumMember) { + var declaration = symbol.declarations[0]; + if (declaration.kind === SyntaxKind.EnumMember) { + var constantValue = typeInfoResolver.getEnumMemberValue(declaration); + if (constantValue !== undefined) { + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push(new SymbolDisplayPart("=", SymbolDisplayPartKind.operator, undefined)); + totalParts.push(new SymbolDisplayPart(" ", SymbolDisplayPartKind.space, undefined)); + totalParts.push(new SymbolDisplayPart(constantValue.toString(), SymbolDisplayPartKind.numericLiteral, undefined)); + } + } + } + } + + return new QuickInfo( + getSymbolKind(symbol), + getSymbolModifiers(symbol), + new TypeScript.TextSpan(node.getStart(), node.getWidth()), + totalParts, + documentationParts); + } + function getTypeAtPosition(fileName: string, position: number): TypeInfo { synchronizeHostData(); @@ -2275,7 +2523,7 @@ module ts { result.push(getDefinitionInfo(declarations[declarations.length - 1], symbolKind, symbolName, containerName)); return true; } - + return false; } @@ -2476,7 +2724,7 @@ module ts { break; } } - + if (shouldHighlightNextKeyword) { result.push(new ReferenceEntry(filename, TypeScript.TextSpan.fromBounds(elseKeyword.getStart(), ifKeyword.end), /* isWriteAccess */ false)); i++; // skip the next keyword @@ -3483,7 +3731,30 @@ module ts { // Reset writer back to undefined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput writer = undefined; - return emitOutput; + return emitOutput; + } + + // Signature help + /** + * This is a semantic operation. + */ + function getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems { + synchronizeHostData(); + + fileName = TypeScript.switchToForwardSlashes(fileName); + var sourceFile = getSourceFile(fileName); + + return SignatureHelp.getSignatureHelpItems(sourceFile, position, typeInfoResolver, cancellationToken); + } + + /** + * This is a syntactic operation + */ + function getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): SignatureHelpState { + fileName = TypeScript.switchToForwardSlashes(fileName); + var sourceFile = getCurrentSourceFile(fileName); + + return SignatureHelp.getSignatureHelpCurrentArgumentState(sourceFile, position, applicableSpanStart); } /// Syntactic features @@ -3768,14 +4039,61 @@ module ts { } function getBraceMatchingAtPosition(filename: string, position: number) { - filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = getSyntaxTree(filename); - return TypeScript.Services.BraceMatcher.getMatchSpans(syntaxTree, position); + var sourceFile = getCurrentSourceFile(filename); + var result: TypeScript.TextSpan[] = []; + + var token = getTokenAtPosition(sourceFile, position); + + if (token.getStart(sourceFile) === position) { + var matchKind = getMatchingTokenKind(token); + + // Ensure that there is a corresponding token to match ours. + if (matchKind) { + var parentElement = token.parent; + + var childNodes = parentElement.getChildren(sourceFile); + for (var i = 0, n = childNodes.length; i < n; i++) { + var current = childNodes[i]; + + if (current.kind === matchKind) { + var range1 = new TypeScript.TextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); + var range2 = new TypeScript.TextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); + + // We want to order the braces when we return the result. + if (range1.start() < range2.start()) { + result.push(range1, range2); + } + else { + result.push(range2, range1); + } + + break; + } + } + } + } + + return result; + + function getMatchingTokenKind(token: Node): ts.SyntaxKind { + switch (token.kind) { + case ts.SyntaxKind.OpenBraceToken: return ts.SyntaxKind.CloseBraceToken + case ts.SyntaxKind.OpenParenToken: return ts.SyntaxKind.CloseParenToken; + case ts.SyntaxKind.OpenBracketToken: return ts.SyntaxKind.CloseBracketToken; + case ts.SyntaxKind.LessThanToken: return ts.SyntaxKind.GreaterThanToken; + case ts.SyntaxKind.CloseBraceToken: return ts.SyntaxKind.OpenBraceToken + case ts.SyntaxKind.CloseParenToken: return ts.SyntaxKind.OpenParenToken; + case ts.SyntaxKind.CloseBracketToken: return ts.SyntaxKind.OpenBracketToken; + case ts.SyntaxKind.GreaterThanToken: return ts.SyntaxKind.LessThanToken; + } + + return undefined; + } } function getIndentationAtPosition(filename: string, position: number, editorOptions: EditorOptions) { filename = TypeScript.switchToForwardSlashes(filename); - + var sourceFile = getCurrentSourceFile(filename); var options = new TypeScript.FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter) @@ -3889,8 +4207,8 @@ module ts { } // Looks to be within the trivia. See if we can find the comment containing it. - if (!getContainingComment(getTrailingComments(fileContents, token.getFullStart()), matchPosition) && - !getContainingComment(getLeadingComments(fileContents, token.getFullStart()), matchPosition)) { + if (!getContainingComment(getTrailingCommentRanges(fileContents, token.getFullStart()), matchPosition) && + !getContainingComment(getLeadingCommentRanges(fileContents, token.getFullStart()), matchPosition)) { continue; } @@ -3977,7 +4295,7 @@ module ts { return new RegExp(regExpString, "gim"); } - function getContainingComment(comments: Comment[], position: number): Comment { + function getContainingComment(comments: CommentRange[], position: number): CommentRange { if (comments) { for (var i = 0, n = comments.length; i < n; i++) { var comment = comments[i]; @@ -4015,7 +4333,7 @@ module ts { var kind = getSymbolKind(symbol); if (kind) { return RenameInfo.Create(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind, - getNodeModifiers(symbol.getDeclarations()[0]), + getSymbolModifiers(symbol), new TypeScript.TextSpan(node.getStart(), node.getWidth())); } } @@ -4035,8 +4353,9 @@ module ts { getCompletionsAtPosition: getCompletionsAtPosition, getCompletionEntryDetails: getCompletionEntryDetails, getTypeAtPosition: getTypeAtPosition, - getSignatureHelpItems: (filename, position): SignatureHelpItems => null, - getSignatureHelpCurrentArgumentState: (fileName, position, applicableSpanStart): SignatureHelpState => null, + getSignatureHelpItems: getSignatureHelpItems, + getSignatureHelpCurrentArgumentState: getSignatureHelpCurrentArgumentState, + getQuickInfoAtPosition: getQuickInfoAtPosition, getDefinitionAtPosition: getDefinitionAtPosition, getReferencesAtPosition: getReferencesAtPosition, getOccurrencesAtPosition: getOccurrencesAtPosition, @@ -4059,13 +4378,13 @@ module ts { /// Classifier export function createClassifier(host: Logger): Classifier { - var scanner: Scanner; - var noRegexTable: boolean[]; + var scanner = createScanner(ScriptTarget.ES5, /*skipTrivia*/ false); /// We do not have a full parser support to know when we should parse a regex or not /// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where /// we have a series of divide operator. this list allows us to be more accurate by ruling out /// locations where a regexp cannot exist. + var noRegexTable: boolean[]; if (!noRegexTable) { noRegexTable = []; noRegexTable[SyntaxKind.Identifier] = true; @@ -4085,8 +4404,7 @@ module ts { function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult { var offset = 0; var lastTokenOrCommentEnd = 0; - var lastToken = SyntaxKind.Unknown; - var inUnterminatedMultiLineComment = false; + var lastNonTriviaToken = SyntaxKind.Unknown; // If we're in a string literal, then prepend: "\ // (and a newline). That way when we lex we'll think we're still in a string literal. @@ -4108,27 +4426,31 @@ module ts { break; } + scanner.setText(text); + var result: ClassificationResult = { finalLexState: EndOfLineState.Start, entries: [] }; - scanner = createScanner(ScriptTarget.ES5, /*skipTrivia*/ true, text, onError, processComment); - + var token = SyntaxKind.Unknown; do { token = scanner.scan(); - if ((token === SyntaxKind.SlashToken || token === SyntaxKind.SlashEqualsToken) && !noRegexTable[lastToken]) { + if ((token === SyntaxKind.SlashToken || token === SyntaxKind.SlashEqualsToken) && !noRegexTable[lastNonTriviaToken]) { if (scanner.reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { token = SyntaxKind.RegularExpressionLiteral; } } - else if (lastToken === SyntaxKind.DotToken) { + else if (lastNonTriviaToken === SyntaxKind.DotToken) { token = SyntaxKind.Identifier; } - lastToken = token; + // Only recall the token if it was *not* trivia. + if (!(SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken)) { + lastNonTriviaToken = token; + } processToken(); } @@ -4136,35 +4458,17 @@ module ts { return result; - - function onError(message: DiagnosticMessage): void { - inUnterminatedMultiLineComment = message.key === Diagnostics.Asterisk_Slash_expected.key; - } - - function processComment(start: number, end: number) { - // add Leading white spaces - addLeadingWhiteSpace(start, end); - - // add the comment - addResult(end - start, TokenClass.Comment); - } - function processToken(): void { var start = scanner.getTokenPos(); var end = scanner.getTextPos(); - // add Leading white spaces - addLeadingWhiteSpace(start, end); - // add the token addResult(end - start, classFromKind(token)); if (end >= text.length) { // We're at the end. - if (inUnterminatedMultiLineComment) { - result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; - } - else if (token === SyntaxKind.StringLiteral) { + if (token === SyntaxKind.StringLiteral) { + // Check to see if we finished up on a multiline string literal. var tokenText = scanner.getTokenText(); if (tokenText.length > 0 && tokenText.charCodeAt(tokenText.length - 1) === CharacterCodes.backslash) { var quoteChar = tokenText.charCodeAt(0); @@ -4173,18 +4477,18 @@ module ts { : EndOfLineState.InSingleQuoteStringLiteral; } } + else if (token === SyntaxKind.MultiLineCommentTrivia) { + // Check to see if the multiline comment was unclosed. + var tokenText = scanner.getTokenText() + if (!(tokenText.length > 3 && // need to avoid catching '/*/' + tokenText.charCodeAt(tokenText.length - 2) === CharacterCodes.asterisk && + tokenText.charCodeAt(tokenText.length - 1) === CharacterCodes.slash)) { + result.finalLexState = EndOfLineState.InMultiLineCommentTrivia; + } + } } } - function addLeadingWhiteSpace(start: number, end: number): void { - if (start > lastTokenOrCommentEnd) { - addResult(start - lastTokenOrCommentEnd, TokenClass.Whitespace); - } - - // Remember the end of the last token - lastTokenOrCommentEnd = end; - } - function addResult(length: number, classification: TokenClass): void { if (length > 0) { // If this is the first classification we're adding to the list, then remove any @@ -4277,6 +4581,11 @@ module ts { return TokenClass.StringLiteral; case SyntaxKind.RegularExpressionLiteral: return TokenClass.RegExpLiteral; + case SyntaxKind.MultiLineCommentTrivia: + case SyntaxKind.SingleLineCommentTrivia: + return TokenClass.Comment; + case SyntaxKind.WhitespaceTrivia: + return TokenClass.Whitespace; case SyntaxKind.Identifier: default: return TokenClass.Identifier; diff --git a/src/services/shims.ts b/src/services/shims.ts index 210a458b0be..0418a6da6cc 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -87,7 +87,9 @@ module ts { getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string; getCompletionEntryDetails(fileName: string, position: number, entryName: string): string; + getQuickInfoAtPosition(fileName: string, position: number): string; getTypeAtPosition(fileName: string, position: number): string; + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string; getBreakpointStatementAtPosition(fileName: string, position: number): string; @@ -540,6 +542,16 @@ module ts { /// QUICKINFO /// Computes a string representation of the type at the requested position /// in the active file. + public getQuickInfoAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getQuickInfoAtPosition('" + fileName + "', " + position + ")", + () => { + var quickInfo = this.languageService.getQuickInfoAtPosition(fileName, position); + return quickInfo; + }); + } + + public getTypeAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( "getTypeAtPosition('" + fileName + "', " + position + ")", @@ -587,8 +599,8 @@ module ts { return this.forwardJSONCall( "getSignatureHelpCurrentArgumentState('" + fileName + "', " + position + ", " + applicableSpanStart + ")", () => { - var signatureInfo = this.languageService.getSignatureHelpItems(fileName, position); - return signatureInfo; + var signatureHelpState = this.languageService.getSignatureHelpCurrentArgumentState(fileName, position, applicableSpanStart); + return signatureHelpState; }); } diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts new file mode 100644 index 00000000000..f129cabc00a --- /dev/null +++ b/src/services/signatureHelp.ts @@ -0,0 +1,349 @@ +/// + +module ts.SignatureHelp { + + // A partially written generic type expression is not guaranteed to have the correct syntax tree. the expression could be parsed as less than/greater than expression or a comma expression + // or some other combination depending on what the user has typed so far. For the purposes of signature help we need to consider any location after "<" as a possible generic type reference. + // To do this, the method will back parse the expression starting at the position required. it will try to parse the current expression as a generic type expression, if it did succeed it + // will return the generic identifier that started the expression (e.g. "foo" in "fooargumentList.parent; + var candidates = []; + var resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates); + cancellationToken.throwIfCancellationRequested(); + + if (!candidates.length) { + return undefined; + } + + return createSignatureHelpItems(candidates, resolvedSignature, argumentList); + + /** + * If node is an argument, returns its index in the argument list. + * If not, returns -1. + */ + function getImmediatelyContainingArgumentList(node: Node): Node { + if (node.parent.kind !== SyntaxKind.CallExpression && node.parent.kind !== SyntaxKind.NewExpression) { + return undefined; + } + + // There are 3 cases to handle: + // 1. The token introduces a list, and should begin a sig help session + // 2. The token is either not associated with a list, or ends a list, so the session should end + // 3. The token is buried inside a list, and should give sig help + // + // The following are examples of each: + // + // Case 1: + // foo<$T, U>($a, b) -> The token introduces a list, and should begin a sig help session + // Case 2: + // fo$o$(a, b)$ -> The token is either not associated with a list, or ends a list, so the session should end + // Case 3: + // foo(a$, $b$) -> The token is buried inside a list, and should give sig help + var parent = node.parent; + // Find out if 'node' is an argument, a type argument, or neither + if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) { + // Find the list that starts right *after* the < or ( token + var list = getChildListThatStartsWithOpenerToken(parent, node, sourceFile); + Debug.assert(list); + return list; + } + + if (node.kind === SyntaxKind.GreaterThanToken + || node.kind === SyntaxKind.CloseParenToken + || node === parent.func) { + return undefined; + } + + return findContainingList(node); + } + + function getContainingArgumentList(node: Node): Node { + for (var n = node; n.kind !== SyntaxKind.SourceFile; n = n.parent) { + if (n.kind === SyntaxKind.FunctionBlock) { + return undefined; + } + + var argumentList = getImmediatelyContainingArgumentList(n); + if (argumentList) { + return argumentList; + } + + + // TODO: Handle generic call with incomplete syntax + } + return undefined; + } + + function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentListOrTypeArgumentList: Node): SignatureHelpItems { + var items = map(candidates, candidateSignature => { + var parameters = candidateSignature.parameters; + var parameterHelpItems = parameters.length === 0 ? emptyArray : map(parameters, p => { + var display = p.name; + if (candidateSignature.hasRestParameter && parameters[parameters.length - 1] === p) { + display = "..." + display; + } + var isOptional = !!(p.valueDeclaration.flags & NodeFlags.QuestionMark); + if (isOptional) { + display += "?"; + } + display += ": " + typeInfoResolver.typeToString(typeInfoResolver.getTypeOfSymbol(p), argumentListOrTypeArgumentList); + return new SignatureHelpParameter(p.name, "", display, isOptional); + }); + var callTargetNode = (argumentListOrTypeArgumentList.parent).func; + var callTargetSymbol = typeInfoResolver.getSymbolInfo(callTargetNode); + var signatureName = callTargetSymbol ? typeInfoResolver.symbolToString(callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : ""; + var prefix = signatureName; + // TODO(jfreeman): Constraints? + if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) { + prefix += "<" + map(candidateSignature.typeParameters, tp => tp.symbol.name).join(", ") + ">"; + } + prefix += "("; + var suffix = "): " + typeInfoResolver.typeToString(candidateSignature.getReturnType(), argumentListOrTypeArgumentList); + return new SignatureHelpItem(candidateSignature.hasRestParameter, prefix, suffix, ", ", parameterHelpItems, ""); + }); + var selectedItemIndex = candidates.indexOf(bestSignature); + if (selectedItemIndex < 0) { + selectedItemIndex = 0; + } + + // We use full start and skip trivia on the end because we want to include trivia on + // both sides. For example, + // + // foo( /*comment */ a, b, c /*comment*/ ) + // | | + // + // The applicable span is from the first bar to the second bar (inclusive, + // but not including parentheses) + var applicableSpanStart = argumentListOrTypeArgumentList.getFullStart(); + var applicableSpanEnd = skipTrivia(sourceFile.text, argumentListOrTypeArgumentList.end, /*stopAfterLineBreak*/ false); + var applicableSpan = new TypeScript.TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + return new SignatureHelpItems(items, applicableSpan, selectedItemIndex); + } + } + + export function getSignatureHelpCurrentArgumentState(sourceFile: SourceFile, position: number, applicableSpanStart: number): SignatureHelpState { + var tokenPrecedingSpanStart = findPrecedingToken(applicableSpanStart, sourceFile); + if (!tokenPrecedingSpanStart) { + return undefined; + } + + if (tokenPrecedingSpanStart.kind !== SyntaxKind.OpenParenToken && tokenPrecedingSpanStart.kind !== SyntaxKind.LessThanToken) { + // The span start must have moved backward in the file (for example if the open paren was backspaced) + return undefined; + } + + var tokenPrecedingCurrentPosition = findPrecedingToken(position, sourceFile); + var call = tokenPrecedingSpanStart.parent; + Debug.assert(call.kind === SyntaxKind.CallExpression || call.kind === SyntaxKind.NewExpression, "wrong call kind " + SyntaxKind[call.kind]); + if (tokenPrecedingCurrentPosition.kind === SyntaxKind.CloseParenToken || tokenPrecedingCurrentPosition.kind === SyntaxKind.GreaterThanToken) { + if (tokenPrecedingCurrentPosition.parent === call) { + // This call expression is complete. Stop signature help. + return undefined; + } + } + + var argumentListOrTypeArgumentList = getChildListThatStartsWithOpenerToken(call, tokenPrecedingSpanStart, sourceFile); + // Debug.assert(argumentListOrTypeArgumentList.getChildCount() === 0 || argumentListOrTypeArgumentList.getChildCount() % 2 === 1, "Even number of children"); + + // The call might be finished, but incorrectly. Check if we are still within the bounds of the call + if (position > skipTrivia(sourceFile.text, argumentListOrTypeArgumentList.end, /*stopAfterLineBreak*/ false)) { + return undefined; + } + + var numberOfCommas = countWhere(argumentListOrTypeArgumentList.getChildren(), arg => arg.kind === SyntaxKind.CommaToken); + var argumentCount = numberOfCommas + 1; + if (argumentCount <= 1) { + return new SignatureHelpState(/*argumentIndex*/ 0, argumentCount); + } + + var indexOfNodeContainingPosition = findListItemIndexContainingPosition(argumentListOrTypeArgumentList, position); + + // indexOfNodeContainingPosition checks that position is between pos and end of each child, so it is + // possible that we are to the right of all children. Assume that we are still within + // the applicable span and that we are typing the last argument + // Alternatively, we could be in range of one of the arguments, in which case we need to divide + // by 2 to exclude commas. Use bit shifting in order to take the floor of the division. + var argumentIndex = indexOfNodeContainingPosition < 0 ? argumentCount - 1 : indexOfNodeContainingPosition >> 1; + return new SignatureHelpState(argumentIndex, argumentCount); + } + + function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node, sourceFile: SourceFile): Node { + var children = parent.getChildren(sourceFile); + var indexOfOpenerToken = children.indexOf(openerToken); + return children[indexOfOpenerToken + 1]; + } +} \ No newline at end of file diff --git a/src/services/signatureInfoHelpers.ts b/src/services/signatureInfoHelpers.ts deleted file mode 100644 index 8594a5dd320..00000000000 --- a/src/services/signatureInfoHelpers.ts +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0. -// See LICENSE.txt in the project root for complete license information. - -/// - -module TypeScript.Services { - - export interface IPartiallyWrittenTypeArgumentListInformation { - genericIdentifer: TypeScript.ISyntaxToken; - lessThanToken: TypeScript.ISyntaxToken; - argumentIndex: number; - } - - export interface IExpressionWithArgumentListSyntax extends IExpressionSyntax { - expression: IExpressionSyntax; - argumentList: ArgumentListSyntax; - } - - export class SignatureInfoHelpers { - - // A partially written generic type expression is not guaranteed to have the correct syntax tree. the expression could be parsed as less than/greater than expression or a comma expression - // or some other combination depending on what the user has typed so far. For the purposes of signature help we need to consider any location after "<" as a possible generic type reference. - // To do this, the method will back parse the expression starting at the position required. it will try to parse the current expression as a generic type expression, if it did succeed it - // will return the generic identifier that started the expression (e.g. "foo" in "foo 1; - - for (var i = 0, n = signatures.length; i < n; i++) { - var signature = signatures[i]; - - // filter out the definition signature if there are overloads - if (hasOverloads && signature.isDefinition()) { - continue; - } - - var signatureGroupInfo = new FormalSignatureItemInfo(); - var paramIndexInfo: number[] = []; - var functionName = signature.getScopedNameEx(enclosingScopeSymbol).toString(); - if (!functionName && (!symbol.isType() || (symbol).isNamedTypeSymbol())) { - functionName = symbol.getScopedNameEx(enclosingScopeSymbol).toString(); - } - - var signatureMemberName = signature.getSignatureTypeNameEx(functionName, /*shortform*/ false, /*brackets*/ false, enclosingScopeSymbol, /*getParamMarkerInfo*/ true, /*getTypeParameterMarkerInfo*/ true); - signatureGroupInfo.signatureInfo = TypeScript.MemberName.memberNameToString(signatureMemberName, paramIndexInfo); - signatureGroupInfo.docComment = signature.docComments(); - - var parameterMarkerIndex = 0; - - if (signature.isGeneric()) { - var typeParameters = signature.getTypeParameters(); - for (var j = 0, m = typeParameters.length; j < m; j++) { - var typeParameter = typeParameters[j]; - var signatureTypeParameterInfo = new FormalTypeParameterInfo(); - signatureTypeParameterInfo.name = typeParameter.getDisplayName(); - signatureTypeParameterInfo.docComment = typeParameter.docComments(); - signatureTypeParameterInfo.minChar = paramIndexInfo[2 * parameterMarkerIndex]; - signatureTypeParameterInfo.limChar = paramIndexInfo[2 * parameterMarkerIndex + 1]; - parameterMarkerIndex++; - signatureGroupInfo.typeParameters.push(signatureTypeParameterInfo); - } - } - - var parameters = signature.parameters; - for (var j = 0, m = parameters.length; j < m; j++) { - var parameter = parameters[j]; - var signatureParameterInfo = new FormalParameterInfo(); - signatureParameterInfo.isVariable = signature.hasVarArgs && (j === parameters.length - 1); - signatureParameterInfo.name = parameter.getDisplayName(); - signatureParameterInfo.docComment = parameter.docComments(); - signatureParameterInfo.minChar = paramIndexInfo[2 * parameterMarkerIndex]; - signatureParameterInfo.limChar = paramIndexInfo[2 * parameterMarkerIndex + 1]; - parameterMarkerIndex++; - signatureGroupInfo.parameters.push(signatureParameterInfo); - } - - signatureGroup.push(signatureGroupInfo); - } - - return signatureGroup; - } - - public static getSignatureInfoFromGenericSymbol(symbol: TypeScript.PullSymbol, enclosingScopeSymbol: TypeScript.PullSymbol, compilerState: LanguageServiceCompiler) { - var signatureGroupInfo = new FormalSignatureItemInfo(); - - var paramIndexInfo: number[] = []; - var symbolName = symbol.getScopedNameEx(enclosingScopeSymbol, /*skipTypeParametersInName*/ false, /*useConstaintInName*/ true, /*getPrettyTypeName*/ false, /*getTypeParamMarkerInfo*/ true); - - signatureGroupInfo.signatureInfo = TypeScript.MemberName.memberNameToString(symbolName, paramIndexInfo); - signatureGroupInfo.docComment = symbol.docComments(); - - var typeSymbol = symbol.type; - - var typeParameters = typeSymbol.getTypeParameters(); - for (var i = 0, n = typeParameters.length; i < n; i++) { - var typeParameter = typeParameters[i]; - var signatureTypeParameterInfo = new FormalTypeParameterInfo(); - signatureTypeParameterInfo.name = typeParameter.getDisplayName(); - signatureTypeParameterInfo.docComment = typeParameter.docComments(); - signatureTypeParameterInfo.minChar = paramIndexInfo[2 * i]; - signatureTypeParameterInfo.limChar = paramIndexInfo[2 * i + 1]; - signatureGroupInfo.typeParameters.push(signatureTypeParameterInfo); - } - - return [signatureGroupInfo]; - } - - public static getActualSignatureInfoFromCallExpression(ast: IExpressionWithArgumentListSyntax, caretPosition: number, typeParameterInformation: IPartiallyWrittenTypeArgumentListInformation): ActualSignatureInfo { - if (!ast) { - return null; - } - - var result = new ActualSignatureInfo(); - - // The expression is not guaranteed to be complete, we need to populate the min and lim with the most accurate information we have about - // type argument and argument lists - var parameterMinChar = caretPosition; - var parameterLimChar = caretPosition; - - if (ast.argumentList.typeArgumentList) { - parameterMinChar = Math.min(start(ast.argumentList.typeArgumentList)); - parameterLimChar = Math.max(Math.max(start(ast.argumentList.typeArgumentList), end(ast.argumentList.typeArgumentList) + trailingTriviaWidth(ast.argumentList.typeArgumentList))); - } - - if (ast.argumentList.arguments) { - parameterMinChar = Math.min(parameterMinChar, end(ast.argumentList.openParenToken)); - parameterLimChar = Math.max(parameterLimChar, - ast.argumentList.closeParenToken.fullWidth() > 0 ? start(ast.argumentList.closeParenToken) : fullEnd(ast.argumentList)); - } - - result.parameterMinChar = parameterMinChar; - result.parameterLimChar = parameterLimChar; - result.currentParameterIsTypeParameter = false; - result.currentParameter = -1; - - if (typeParameterInformation) { - result.currentParameterIsTypeParameter = true; - result.currentParameter = typeParameterInformation.argumentIndex; - } - else if (ast.argumentList.arguments && ast.argumentList.arguments.length > 0) { - result.currentParameter = 0; - for (var index = 0; index < ast.argumentList.arguments.length; index++) { - if (caretPosition > end(ast.argumentList.arguments[index]) + lastToken(ast.argumentList.arguments[index]).trailingTriviaWidth()) { - result.currentParameter++; - } - } - } - - return result; - } - - public static getActualSignatureInfoFromPartiallyWritenGenericExpression(caretPosition: number, typeParameterInformation: IPartiallyWrittenTypeArgumentListInformation): ActualSignatureInfo { - var result = new ActualSignatureInfo(); - - result.parameterMinChar = start(typeParameterInformation.lessThanToken); - result.parameterLimChar = Math.max(fullEnd(typeParameterInformation.lessThanToken), caretPosition); - result.currentParameterIsTypeParameter = true; - result.currentParameter = typeParameterInformation.argumentIndex; - - return result; - } - - public static isSignatureHelpBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - // We shouldn't be getting a possition that is outside the file because - // isEntirelyInsideComment can't handle when the position is out of bounds, - // callers should be fixed, however we should be resiliant to bad inputs - // so we return true (this position is a blocker for getting signature help) - if (position < 0 || position > fullWidth(sourceUnit)) { - return true; - } - - return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position); - } - - public static isTargetOfObjectCreationExpression(positionedToken: TypeScript.ISyntaxToken): boolean { - var positionedParent = TypeScript.Syntax.getAncestorOfKind(positionedToken, TypeScript.SyntaxKind.ObjectCreationExpression); - if (positionedParent) { - var objectCreationExpression = positionedParent; - var expressionRelativeStart = objectCreationExpression.newKeyword.fullWidth(); - var tokenRelativeStart = positionedToken.fullStart() - fullStart(positionedParent); - return tokenRelativeStart >= expressionRelativeStart && - tokenRelativeStart <= (expressionRelativeStart + fullWidth(objectCreationExpression.expression)); - } - - return false; - } - - private static moveBackUpTillMatchingTokenKind(token: TypeScript.ISyntaxToken, tokenKind: TypeScript.SyntaxKind, matchingTokenKind: TypeScript.SyntaxKind): TypeScript.ISyntaxToken { - if (!token || token.kind() !== tokenKind) { - throw TypeScript.Errors.invalidOperation(); - } - - // Skip the current token - token = previousToken(token, /*includeSkippedTokens*/ true); - - var stack = 0; - - while (token) { - if (token.kind() === matchingTokenKind) { - if (stack === 0) { - // Found the matching token, return - return token; - } - else if (stack < 0) { - // tokens overlapped.. bail out. - break; - } - else { - stack--; - } - } - else if (token.kind() === tokenKind) { - stack++; - } - - // Move back - token = previousToken(token, /*includeSkippedTokens*/ true); - } - - // Did not find matching token - return null; - } - } -} \ No newline at end of file diff --git a/src/services/utilities.ts b/src/services/utilities.ts new file mode 100644 index 00000000000..2824ab5d2da --- /dev/null +++ b/src/services/utilities.ts @@ -0,0 +1,204 @@ +// These utilities are common to multiple language service features. +module ts { + export interface ListItemInfo { + listItemIndex: number; + list: Node; + } + + export function findListItemInfo(node: Node): ListItemInfo { + var syntaxList = findContainingList(node); + var children = syntaxList.getChildren(); + var index = indexOf(children, node); + + return { + listItemIndex: index, + list: syntaxList + }; + } + + export function findContainingList(node: Node): Node { + // The node might be a list element (nonsynthetic) or a comma (synthetic). Either way, it will + // be parented by the container of the SyntaxList, not the SyntaxList itself. + // In order to find the list item index, we first need to locate SyntaxList itself and then search + // for the position of the relevant node (or comma). + var syntaxList = forEach(node.parent.getChildren(), c => { + // find syntax list that covers the span of the node + if (c.kind == SyntaxKind.SyntaxList && c.pos <= node.pos && c.end >= node.end) { + return c; + } + }); + + return syntaxList; + } + + /** + * Includes the start position of each child, but excludes the end. + */ + export function findListItemIndexContainingPosition(list: Node, position: number): number { + Debug.assert(list.kind === SyntaxKind.SyntaxList); + var children = list.getChildren(); + for (var i = 0; i < children.length; i++) { + if (children[i].pos <= position && children[i].end > position) { + return i; + } + } + + return -1; + } + + /** Get a token that contains the position. This is guaranteed to return a token, the position can be in the + * leading trivia or within the token text. + */ + export function getTokenAtPosition(sourceFile: SourceFile, position: number) { + var current: Node = sourceFile; + outer: while (true) { + // find the child that has this + for (var i = 0, n = current.getChildCount(); i < n; i++) { + var child = current.getChildAt(i); + if (child.getFullStart() <= position && position < child.getEnd()) { + current = child; + continue outer; + } + } + return current; + } + } + + /** Get the token whose text contains the position, or the containing node. */ + export function getNodeAtPosition(sourceFile: SourceFile, position: number) { + var current: Node = sourceFile; + outer: while (true) { + // find the child that has this + for (var i = 0, n = current.getChildCount(); i < n; i++) { + var child = current.getChildAt(i); + if (child.getStart() <= position && position < child.getEnd()) { + current = child; + continue outer; + } + } + return current; + } + } + + /** + * The token on the left of the position is the token that strictly includes the position + * or sits to the left of the cursor if it is on a boundary. For example + * + * fo|o -> will return foo + * foo |bar -> will return foo + * + */ + export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node { + // Ideally, getTokenAtPosition should return a token. However, it is currently + // broken, so we do a check to make sure the result was indeed a token. + var tokenAtPosition = getTokenAtPosition(file, position); + if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) { + return tokenAtPosition; + } + + return findPrecedingToken(position, file); + } + + export function findNextToken(previousToken: Node, parent: Node): Node { + return find(parent); + + function find(n: Node): Node { + if (isToken(n) && n.pos === previousToken.end) { + // this is token that starts at the end of previous token - return it + return n; + } + + var children = n.getChildren(); + for (var i = 0, len = children.length; i < len; ++i) { + var child = children[i]; + var shouldDiveInChildNode = + // previous token is enclosed somewhere in the child + (child.pos <= previousToken.pos && child.end > previousToken.end) || + // previous token ends exactly at the beginning of child + (child.pos === previousToken.end); + + if (shouldDiveInChildNode && nodeHasTokens(child)) { + return find(child); + } + } + + return undefined; + } + } + + export function findPrecedingToken(position: number, sourceFile: SourceFile): Node { + return find(sourceFile); + + function findRightmostToken(n: Node): Node { + if (isToken(n)) { + return n; + } + + var children = n.getChildren(); + var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); + return candidate && findRightmostToken(candidate); + + } + + function find(n: Node): Node { + if (isToken(n)) { + return n; + } + + var children = n.getChildren(); + for (var i = 0, len = children.length; i < len; ++i) { + var child = children[i]; + if (nodeHasTokens(child)) { + if (position < child.end) { + if (child.getStart(sourceFile) >= position) { + // actual start of the node is past the position - previous token should be at the end of previous child + var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i); + return candidate && findRightmostToken(candidate) + } + else { + // candidate should be in this node + return find(child); + } + } + } + } + + Debug.assert(n.kind === SyntaxKind.SourceFile); + + // Here we know that none of child token nodes embrace the position, + // the only known case is when position is at the end of the file. + // Try to find the rightmost token in the file without filtering. + // Namely we are skipping the check: 'position < node.end' + if (children.length) { + var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); + return candidate && findRightmostToken(candidate); + } + } + + /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition' + function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node { + for (var i = exclusiveStartPosition - 1; i >= 0; --i) { + if (nodeHasTokens(children[i])) { + return children[i]; + } + } + } + } + + function nodeHasTokens(n: Node): boolean { + if (n.kind === SyntaxKind.ExpressionStatement) { + return nodeHasTokens((n).expression); + } + + if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) { + return false; + } + + // SyntaxList is already realized so getChildCount should be fast and non-expensive + return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0; + } + + function isToken(n: Node): boolean { + return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; + } +} \ No newline at end of file diff --git a/tests/baselines/reference/accessibilityModifiers.errors.txt b/tests/baselines/reference/accessibilityModifiers.errors.txt new file mode 100644 index 00000000000..137da7f982c --- /dev/null +++ b/tests/baselines/reference/accessibilityModifiers.errors.txt @@ -0,0 +1,99 @@ +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(22,12): error TS1029: 'private' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(23,12): error TS1029: 'private' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(24,12): error TS1029: 'private' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(25,12): error TS1029: 'private' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(27,12): error TS1029: 'protected' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(28,12): error TS1029: 'protected' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(29,12): error TS1029: 'protected' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(30,12): error TS1029: 'protected' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(32,12): error TS1029: 'public' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(33,12): error TS1029: 'public' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(34,12): error TS1029: 'public' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(35,12): error TS1029: 'public' modifier must precede 'static' modifier. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(40,13): error TS1028: Accessibility modifier already seen. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(40,20): error TS1028: Accessibility modifier already seen. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(41,12): error TS1028: Accessibility modifier already seen. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(42,13): error TS1028: Accessibility modifier already seen. +tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts(43,12): error TS1028: Accessibility modifier already seen. + + +==== tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts (17 errors) ==== + + // No errors + class C { + private static privateProperty; + private static privateMethod() { } + private static get privateGetter() { return 0; } + private static set privateSetter(a: number) { } + + protected static protectedProperty; + protected static protectedMethod() { } + protected static get protectedGetter() { return 0; } + protected static set protectedSetter(a: number) { } + + public static publicProperty; + public static publicMethod() { } + public static get publicGetter() { return 0; } + public static set publicSetter(a: number) { } + } + + // Errors, accessibility modifiers must precede static + class D { + static private privateProperty; + ~~~~~~~ +!!! error TS1029: 'private' modifier must precede 'static' modifier. + static private privateMethod() { } + ~~~~~~~ +!!! error TS1029: 'private' modifier must precede 'static' modifier. + static private get privateGetter() { return 0; } + ~~~~~~~ +!!! error TS1029: 'private' modifier must precede 'static' modifier. + static private set privateSetter(a: number) { } + ~~~~~~~ +!!! error TS1029: 'private' modifier must precede 'static' modifier. + + static protected protectedProperty; + ~~~~~~~~~ +!!! error TS1029: 'protected' modifier must precede 'static' modifier. + static protected protectedMethod() { } + ~~~~~~~~~ +!!! error TS1029: 'protected' modifier must precede 'static' modifier. + static protected get protectedGetter() { return 0; } + ~~~~~~~~~ +!!! error TS1029: 'protected' modifier must precede 'static' modifier. + static protected set protectedSetter(a: number) { } + ~~~~~~~~~ +!!! error TS1029: 'protected' modifier must precede 'static' modifier. + + static public publicProperty; + ~~~~~~ +!!! error TS1029: 'public' modifier must precede 'static' modifier. + static public publicMethod() { } + ~~~~~~ +!!! error TS1029: 'public' modifier must precede 'static' modifier. + static public get publicGetter() { return 0; } + ~~~~~~ +!!! error TS1029: 'public' modifier must precede 'static' modifier. + static public set publicSetter(a: number) { } + ~~~~~~ +!!! error TS1029: 'public' modifier must precede 'static' modifier. + } + + // Errors, multiple accessibility modifier + class E { + private public protected property; + ~~~~~~ +!!! error TS1028: Accessibility modifier already seen. + ~~~~~~~~~ +!!! error TS1028: Accessibility modifier already seen. + public protected method() { } + ~~~~~~~~~ +!!! error TS1028: Accessibility modifier already seen. + private protected get getter() { return 0; } + ~~~~~~~~~ +!!! error TS1028: Accessibility modifier already seen. + public public set setter(a: number) { } + ~~~~~~ +!!! error TS1028: Accessibility modifier already seen. + } + \ No newline at end of file diff --git a/tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.errors.txt b/tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.errors.txt new file mode 100644 index 00000000000..6c12df93dd1 --- /dev/null +++ b/tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.errors.txt @@ -0,0 +1,59 @@ +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(3,9): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(6,17): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(11,19): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(14,17): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(19,19): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(21,9): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(27,26): error TS2379: Getter and setter accessors do not agree in visibility. +tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts(29,16): error TS2379: Getter and setter accessors do not agree in visibility. + + +==== tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts (8 errors) ==== + + class C { + get x() { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + return 1; + } + private set x(v) { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + } + } + + class D { + protected get x() { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + return 1; + } + private set x(v) { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + } + } + + class E { + protected set x(v) { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + } + get x() { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + return 1; + } + } + + class F { + protected static set x(v) { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + } + static get x() { + ~ +!!! error TS2379: Getter and setter accessors do not agree in visibility. + return 1; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.js b/tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.js new file mode 100644 index 00000000000..548d679776e --- /dev/null +++ b/tests/baselines/reference/accessorWithMismatchedAccessibilityModifiers.js @@ -0,0 +1,91 @@ +//// [accessorWithMismatchedAccessibilityModifiers.ts] + +class C { + get x() { + return 1; + } + private set x(v) { + } +} + +class D { + protected get x() { + return 1; + } + private set x(v) { + } +} + +class E { + protected set x(v) { + } + get x() { + return 1; + } +} + +class F { + protected static set x(v) { + } + static get x() { + return 1; + } +} + +//// [accessorWithMismatchedAccessibilityModifiers.js] +var C = (function () { + function C() { + } + Object.defineProperty(C.prototype, "x", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return C; +})(); +var D = (function () { + function D() { + } + Object.defineProperty(D.prototype, "x", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return D; +})(); +var E = (function () { + function E() { + } + Object.defineProperty(E.prototype, "x", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return E; +})(); +var F = (function () { + function F() { + } + Object.defineProperty(F, "x", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return F; +})(); diff --git a/tests/baselines/reference/castExpressionParentheses.js b/tests/baselines/reference/castExpressionParentheses.js index 2f62d6e9447..2b518226c60 100644 --- a/tests/baselines/reference/castExpressionParentheses.js +++ b/tests/baselines/reference/castExpressionParentheses.js @@ -43,7 +43,7 @@ new (A()); // parentheses should be omitted // literals { a: 0 }; -[1, 3, ]; +[1, 3,]; "string"; 23.0; /regexp/g; diff --git a/tests/baselines/reference/classConstructorParametersAccessibility.errors.txt b/tests/baselines/reference/classConstructorParametersAccessibility.errors.txt new file mode 100644 index 00000000000..029c3fae018 --- /dev/null +++ b/tests/baselines/reference/classConstructorParametersAccessibility.errors.txt @@ -0,0 +1,35 @@ +tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility.ts(12,1): error TS2341: Property 'p' is private and only accessible within class 'C2'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility.ts(19,1): error TS2445: Property 'p' is protected and only accessible within class 'C3' and its subclasses. + + +==== tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility.ts (2 errors) ==== + class C1 { + constructor(public x: number) { } + } + var c1: C1; + c1.x // OK + + + class C2 { + constructor(private p: number) { } + } + var c2: C2; + c2.p // private, error + ~~~~ +!!! error TS2341: Property 'p' is private and only accessible within class 'C2'. + + + class C3 { + constructor(protected p: number) { } + } + var c3: C3; + c3.p // protected, error + ~~~~ +!!! error TS2445: Property 'p' is protected and only accessible within class 'C3' and its subclasses. + class Derived extends C3 { + constructor(p: number) { + super(p); + this.p; // OK + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/classConstructorParametersAccessibility.js b/tests/baselines/reference/classConstructorParametersAccessibility.js new file mode 100644 index 00000000000..03d56d94e58 --- /dev/null +++ b/tests/baselines/reference/classConstructorParametersAccessibility.js @@ -0,0 +1,67 @@ +//// [classConstructorParametersAccessibility.ts] +class C1 { + constructor(public x: number) { } +} +var c1: C1; +c1.x // OK + + +class C2 { + constructor(private p: number) { } +} +var c2: C2; +c2.p // private, error + + +class C3 { + constructor(protected p: number) { } +} +var c3: C3; +c3.p // protected, error +class Derived extends C3 { + constructor(p: number) { + super(p); + this.p; // OK + } +} + + +//// [classConstructorParametersAccessibility.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C1 = (function () { + function C1(x) { + this.x = x; + } + return C1; +})(); +var c1; +c1.x; // OK +var C2 = (function () { + function C2(p) { + this.p = p; + } + return C2; +})(); +var c2; +c2.p; // private, error +var C3 = (function () { + function C3(p) { + this.p = p; + } + return C3; +})(); +var c3; +c3.p; // protected, error +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived(p) { + _super.call(this, p); + this.p; // OK + } + return Derived; +})(C3); diff --git a/tests/baselines/reference/classConstructorParametersAccessibility2.errors.txt b/tests/baselines/reference/classConstructorParametersAccessibility2.errors.txt new file mode 100644 index 00000000000..7c95a35e1da --- /dev/null +++ b/tests/baselines/reference/classConstructorParametersAccessibility2.errors.txt @@ -0,0 +1,35 @@ +tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility2.ts(12,1): error TS2341: Property 'p' is private and only accessible within class 'C2'. +tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility2.ts(19,1): error TS2445: Property 'p' is protected and only accessible within class 'C3' and its subclasses. + + +==== tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility2.ts (2 errors) ==== + class C1 { + constructor(public x?: number) { } + } + var c1: C1; + c1.x // OK + + + class C2 { + constructor(private p?: number) { } + } + var c2: C2; + c2.p // private, error + ~~~~ +!!! error TS2341: Property 'p' is private and only accessible within class 'C2'. + + + class C3 { + constructor(protected p?: number) { } + } + var c3: C3; + c3.p // protected, error + ~~~~ +!!! error TS2445: Property 'p' is protected and only accessible within class 'C3' and its subclasses. + class Derived extends C3 { + constructor(p: number) { + super(p); + this.p; // OK + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/classConstructorParametersAccessibility2.js b/tests/baselines/reference/classConstructorParametersAccessibility2.js new file mode 100644 index 00000000000..1b16d13c82a --- /dev/null +++ b/tests/baselines/reference/classConstructorParametersAccessibility2.js @@ -0,0 +1,67 @@ +//// [classConstructorParametersAccessibility2.ts] +class C1 { + constructor(public x?: number) { } +} +var c1: C1; +c1.x // OK + + +class C2 { + constructor(private p?: number) { } +} +var c2: C2; +c2.p // private, error + + +class C3 { + constructor(protected p?: number) { } +} +var c3: C3; +c3.p // protected, error +class Derived extends C3 { + constructor(p: number) { + super(p); + this.p; // OK + } +} + + +//// [classConstructorParametersAccessibility2.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C1 = (function () { + function C1(x) { + this.x = x; + } + return C1; +})(); +var c1; +c1.x; // OK +var C2 = (function () { + function C2(p) { + this.p = p; + } + return C2; +})(); +var c2; +c2.p; // private, error +var C3 = (function () { + function C3(p) { + this.p = p; + } + return C3; +})(); +var c3; +c3.p; // protected, error +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived(p) { + _super.call(this, p); + this.p; // OK + } + return Derived; +})(C3); diff --git a/tests/baselines/reference/classConstructorParametersAccessibility3.js b/tests/baselines/reference/classConstructorParametersAccessibility3.js new file mode 100644 index 00000000000..9bd6c4bf7f5 --- /dev/null +++ b/tests/baselines/reference/classConstructorParametersAccessibility3.js @@ -0,0 +1,39 @@ +//// [classConstructorParametersAccessibility3.ts] +class Base { + constructor(protected p: number) { } +} + +class Derived extends Base { + constructor(public p: number) { + super(p); + this.p; // OK + } +} + +var d: Derived; +d.p; // public, OK + +//// [classConstructorParametersAccessibility3.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base(p) { + this.p = p; + } + return Base; +})(); +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived(p) { + _super.call(this, p); + this.p = p; + this.p; // OK + } + return Derived; +})(Base); +var d; +d.p; // public, OK diff --git a/tests/baselines/reference/classConstructorParametersAccessibility3.types b/tests/baselines/reference/classConstructorParametersAccessibility3.types new file mode 100644 index 00000000000..3372044569c --- /dev/null +++ b/tests/baselines/reference/classConstructorParametersAccessibility3.types @@ -0,0 +1,36 @@ +=== tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility3.ts === +class Base { +>Base : Base + + constructor(protected p: number) { } +>p : number +} + +class Derived extends Base { +>Derived : Derived +>Base : Base + + constructor(public p: number) { +>p : number + + super(p); +>super(p) : void +>super : typeof Base +>p : number + + this.p; // OK +>this.p : number +>this : Derived +>p : number + } +} + +var d: Derived; +>d : Derived +>Derived : Derived + +d.p; // public, OK +>d.p : number +>d : Derived +>p : number + diff --git a/tests/baselines/reference/classWithProtectedProperty.js b/tests/baselines/reference/classWithProtectedProperty.js new file mode 100644 index 00000000000..c0dde0d3237 --- /dev/null +++ b/tests/baselines/reference/classWithProtectedProperty.js @@ -0,0 +1,71 @@ +//// [classWithProtectedProperty.ts] +// accessing any protected outside the class is an error + +class C { + protected x; + protected a = ''; + protected b: string = ''; + protected c() { return '' } + protected d = () => ''; + protected static e; + protected static f() { return '' } + protected static g = () => ''; +} + +class D extends C { + method() { + // No errors + var d = new D(); + var r1: string = d.x; + var r2: string = d.a; + var r3: string = d.b; + var r4: string = d.c(); + var r5: string = d.d(); + var r6: string = C.e; + var r7: string = C.f(); + var r8: string = C.g(); + } +} + +//// [classWithProtectedProperty.js] +// accessing any protected outside the class is an error +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C = (function () { + function C() { + this.a = ''; + this.b = ''; + this.d = function () { return ''; }; + } + C.prototype.c = function () { + return ''; + }; + C.f = function () { + return ''; + }; + C.g = function () { return ''; }; + return C; +})(); +var D = (function (_super) { + __extends(D, _super); + function D() { + _super.apply(this, arguments); + } + D.prototype.method = function () { + // No errors + var d = new D(); + var r1 = d.x; + var r2 = d.a; + var r3 = d.b; + var r4 = d.c(); + var r5 = d.d(); + var r6 = C.e; + var r7 = C.f(); + var r8 = C.g(); + }; + return D; +})(C); diff --git a/tests/baselines/reference/classWithProtectedProperty.types b/tests/baselines/reference/classWithProtectedProperty.types new file mode 100644 index 00000000000..a091206cde0 --- /dev/null +++ b/tests/baselines/reference/classWithProtectedProperty.types @@ -0,0 +1,99 @@ +=== tests/cases/conformance/types/members/classWithProtectedProperty.ts === +// accessing any protected outside the class is an error + +class C { +>C : C + + protected x; +>x : any + + protected a = ''; +>a : string + + protected b: string = ''; +>b : string + + protected c() { return '' } +>c : () => string + + protected d = () => ''; +>d : () => string +>() => '' : () => string + + protected static e; +>e : any + + protected static f() { return '' } +>f : () => string + + protected static g = () => ''; +>g : () => string +>() => '' : () => string +} + +class D extends C { +>D : D +>C : C + + method() { +>method : () => void + + // No errors + var d = new D(); +>d : D +>new D() : D +>D : typeof D + + var r1: string = d.x; +>r1 : string +>d.x : any +>d : D +>x : any + + var r2: string = d.a; +>r2 : string +>d.a : string +>d : D +>a : string + + var r3: string = d.b; +>r3 : string +>d.b : string +>d : D +>b : string + + var r4: string = d.c(); +>r4 : string +>d.c() : string +>d.c : () => string +>d : D +>c : () => string + + var r5: string = d.d(); +>r5 : string +>d.d() : string +>d.d : () => string +>d : D +>d : () => string + + var r6: string = C.e; +>r6 : string +>C.e : any +>C : typeof C +>e : any + + var r7: string = C.f(); +>r7 : string +>C.f() : string +>C.f : () => string +>C : typeof C +>f : () => string + + var r8: string = C.g(); +>r8 : string +>C.g() : string +>C.g : () => string +>C : typeof C +>g : () => string + } +} diff --git a/tests/baselines/reference/constructorWithIncompleteTypeAnnotation.errors.txt b/tests/baselines/reference/constructorWithIncompleteTypeAnnotation.errors.txt index 003e5acd73a..17b5398475a 100644 --- a/tests/baselines/reference/constructorWithIncompleteTypeAnnotation.errors.txt +++ b/tests/baselines/reference/constructorWithIncompleteTypeAnnotation.errors.txt @@ -68,8 +68,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(40,28): error TS tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(41,21): error TS2304: Cannot find name 'retValue'. tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(47,17): error TS2304: Cannot find name 'console'. tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(53,13): error TS2304: Cannot find name 'console'. -tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(76,26): error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. -tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(76,44): error TS2359: The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type. tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(89,23): error TS2364: Invalid left-hand side of assignment expression. tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(108,24): error TS2365: Operator '+' cannot be applied to types 'number' and 'boolean'. tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(159,31): error TS2304: Cannot find name 'Property'. @@ -98,7 +96,7 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,29): error T tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error TS2304: Cannot find name 'string'. -==== tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts (98 errors) ==== +==== tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts (96 errors) ==== declare module "fs" { export class File { constructor(filename: string); @@ -242,10 +240,6 @@ tests/cases/compiler/constructorWithIncompleteTypeAnnotation.ts(259,37): error T var local5 = null; var local6 = local5 instanceof fs.File; - ~~~~~~ -!!! error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. - ~~~~~~~ -!!! error TS2359: The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type. var hex = 0xBADC0DE, Hex = 0XDEADBEEF; var float = 6.02e23, float2 = 6.02E-23 diff --git a/tests/baselines/reference/declarationEmit_protectedMembers.js b/tests/baselines/reference/declarationEmit_protectedMembers.js new file mode 100644 index 00000000000..dc8506b220b --- /dev/null +++ b/tests/baselines/reference/declarationEmit_protectedMembers.js @@ -0,0 +1,164 @@ +//// [declarationEmit_protectedMembers.ts] + +// Class with protected members +class C1 { + protected x: number; + + protected f() { + return this.x; + } + + protected set accessor(a: number) { } + protected get accessor() { return 0; } + + protected static sx: number; + + protected static sf() { + return this.sx; + } + + protected static set staticSetter(a: number) { } + protected static get staticGetter() { return 0; } +} + +// Derived class overriding protected members +class C2 extends C1 { + protected f() { + return super.f() + this.x; + } + protected static sf() { + return super.sf() + this.sx; + } +} + +// Derived class making protected members public +class C3 extends C2 { + x: number; + static sx: number; + f() { + return super.f(); + } + static sf() { + return super.sf(); + } + + static get staticGetter() { return 1; } +} + +// Protected properties in constructors +class C4 { + constructor(protected a: number, protected b) { } +} + +//// [declarationEmit_protectedMembers.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +// Class with protected members +var C1 = (function () { + function C1() { + } + C1.prototype.f = function () { + return this.x; + }; + Object.defineProperty(C1.prototype, "accessor", { + get: function () { + return 0; + }, + set: function (a) { + }, + enumerable: true, + configurable: true + }); + C1.sf = function () { + return this.sx; + }; + Object.defineProperty(C1, "staticSetter", { + set: function (a) { + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(C1, "staticGetter", { + get: function () { + return 0; + }, + enumerable: true, + configurable: true + }); + return C1; +})(); +// Derived class overriding protected members +var C2 = (function (_super) { + __extends(C2, _super); + function C2() { + _super.apply(this, arguments); + } + C2.prototype.f = function () { + return _super.prototype.f.call(this) + this.x; + }; + C2.sf = function () { + return _super.sf.call(this) + this.sx; + }; + return C2; +})(C1); +// Derived class making protected members public +var C3 = (function (_super) { + __extends(C3, _super); + function C3() { + _super.apply(this, arguments); + } + C3.prototype.f = function () { + return _super.prototype.f.call(this); + }; + C3.sf = function () { + return _super.sf.call(this); + }; + Object.defineProperty(C3, "staticGetter", { + get: function () { + return 1; + }, + enumerable: true, + configurable: true + }); + return C3; +})(C2); +// Protected properties in constructors +var C4 = (function () { + function C4(a, b) { + this.a = a; + this.b = b; + } + return C4; +})(); + + +//// [declarationEmit_protectedMembers.d.ts] +declare class C1 { + protected x: number; + protected f(): number; + protected accessor: number; + protected static sx: number; + protected static sf(): number; + protected static staticSetter: number; + protected static staticGetter: number; +} +declare class C2 extends C1 { + protected f(): number; + protected static sf(): number; +} +declare class C3 extends C2 { + x: number; + static sx: number; + f(): number; + static sf(): number; + static staticGetter: number; +} +declare class C4 { + protected a: number; + protected b: any; + constructor(a: number, b: any); +} diff --git a/tests/baselines/reference/declarationEmit_protectedMembers.types b/tests/baselines/reference/declarationEmit_protectedMembers.types new file mode 100644 index 00000000000..28217b0c070 --- /dev/null +++ b/tests/baselines/reference/declarationEmit_protectedMembers.types @@ -0,0 +1,120 @@ +=== tests/cases/compiler/declarationEmit_protectedMembers.ts === + +// Class with protected members +class C1 { +>C1 : C1 + + protected x: number; +>x : number + + protected f() { +>f : () => number + + return this.x; +>this.x : number +>this : C1 +>x : number + } + + protected set accessor(a: number) { } +>accessor : number +>a : number + + protected get accessor() { return 0; } +>accessor : number + + protected static sx: number; +>sx : number + + protected static sf() { +>sf : () => number + + return this.sx; +>this.sx : number +>this : typeof C1 +>sx : number + } + + protected static set staticSetter(a: number) { } +>staticSetter : number +>a : number + + protected static get staticGetter() { return 0; } +>staticGetter : number +} + +// Derived class overriding protected members +class C2 extends C1 { +>C2 : C2 +>C1 : C1 + + protected f() { +>f : () => number + + return super.f() + this.x; +>super.f() + this.x : number +>super.f() : number +>super.f : () => number +>super : C1 +>f : () => number +>this.x : number +>this : C2 +>x : number + } + protected static sf() { +>sf : () => number + + return super.sf() + this.sx; +>super.sf() + this.sx : number +>super.sf() : number +>super.sf : () => number +>super : typeof C1 +>sf : () => number +>this.sx : number +>this : typeof C2 +>sx : number + } +} + +// Derived class making protected members public +class C3 extends C2 { +>C3 : C3 +>C2 : C2 + + x: number; +>x : number + + static sx: number; +>sx : number + + f() { +>f : () => number + + return super.f(); +>super.f() : number +>super.f : () => number +>super : C2 +>f : () => number + } + static sf() { +>sf : () => number + + return super.sf(); +>super.sf() : number +>super.sf : () => number +>super : typeof C2 +>sf : () => number + } + + static get staticGetter() { return 1; } +>staticGetter : number +} + +// Protected properties in constructors +class C4 { +>C4 : C4 + + constructor(protected a: number, protected b) { } +>a : number +>b : any +} diff --git a/tests/baselines/reference/deleteOperatorInStrictMode.errors.txt b/tests/baselines/reference/deleteOperatorInStrictMode.errors.txt new file mode 100644 index 00000000000..5952d8b8296 --- /dev/null +++ b/tests/baselines/reference/deleteOperatorInStrictMode.errors.txt @@ -0,0 +1,9 @@ +tests/cases/compiler/deleteOperatorInStrictMode.ts(3,8): error TS1102: 'delete' cannot be called on an identifier in strict mode. + + +==== tests/cases/compiler/deleteOperatorInStrictMode.ts (1 errors) ==== + "use strict" + var a; + delete a; + ~ +!!! error TS1102: 'delete' cannot be called on an identifier in strict mode. \ No newline at end of file diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers.js b/tests/baselines/reference/derivedClassOverridesProtectedMembers.js new file mode 100644 index 00000000000..8c8b6a13c7e --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers.js @@ -0,0 +1,103 @@ +//// [derivedClassOverridesProtectedMembers.ts] + +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + protected a: typeof x; + protected b(a: typeof x) { } + protected get c() { return x; } + protected set c(v: typeof x) { } + protected d: (a: typeof x) => void; + + protected static r: typeof x; + protected static s(a: typeof x) { } + protected static get t() { return x; } + protected static set t(v: typeof x) { } + protected static u: (a: typeof x) => void; + + constructor(a: typeof x) { } +} + +class Derived extends Base { + protected a: typeof y; + protected b(a: typeof y) { } + protected get c() { return y; } + protected set c(v: typeof y) { } + protected d: (a: typeof y) => void; + + protected static r: typeof y; + protected static s(a: typeof y) { } + protected static get t() { return y; } + protected static set t(a: typeof y) { } + protected static u: (a: typeof y) => void; + + constructor(a: typeof y) { super(x) } +} + + +//// [derivedClassOverridesProtectedMembers.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var x; +var y; +var Base = (function () { + function Base(a) { + } + Base.prototype.b = function (a) { + }; + Object.defineProperty(Base.prototype, "c", { + get: function () { + return x; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + Base.s = function (a) { + }; + Object.defineProperty(Base, "t", { + get: function () { + return x; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Base; +})(); +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived(a) { + _super.call(this, x); + } + Derived.prototype.b = function (a) { + }; + Object.defineProperty(Derived.prototype, "c", { + get: function () { + return y; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + Derived.s = function (a) { + }; + Object.defineProperty(Derived, "t", { + get: function () { + return y; + }, + set: function (a) { + }, + enumerable: true, + configurable: true + }); + return Derived; +})(Base); diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers.types b/tests/baselines/reference/derivedClassOverridesProtectedMembers.types new file mode 100644 index 00000000000..2695cbabe34 --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers.types @@ -0,0 +1,123 @@ +=== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers.ts === + +var x: { foo: string; } +>x : { foo: string; } +>foo : string + +var y: { foo: string; bar: string; } +>y : { foo: string; bar: string; } +>foo : string +>bar : string + +class Base { +>Base : Base + + protected a: typeof x; +>a : { foo: string; } +>x : { foo: string; } + + protected b(a: typeof x) { } +>b : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + protected get c() { return x; } +>c : { foo: string; } +>x : { foo: string; } + + protected set c(v: typeof x) { } +>c : { foo: string; } +>v : { foo: string; } +>x : { foo: string; } + + protected d: (a: typeof x) => void; +>d : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + protected static r: typeof x; +>r : { foo: string; } +>x : { foo: string; } + + protected static s(a: typeof x) { } +>s : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + protected static get t() { return x; } +>t : { foo: string; } +>x : { foo: string; } + + protected static set t(v: typeof x) { } +>t : { foo: string; } +>v : { foo: string; } +>x : { foo: string; } + + protected static u: (a: typeof x) => void; +>u : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + constructor(a: typeof x) { } +>a : { foo: string; } +>x : { foo: string; } +} + +class Derived extends Base { +>Derived : Derived +>Base : Base + + protected a: typeof y; +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected b(a: typeof y) { } +>b : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected get c() { return y; } +>c : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected set c(v: typeof y) { } +>c : { foo: string; bar: string; } +>v : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected d: (a: typeof y) => void; +>d : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected static r: typeof y; +>r : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected static s(a: typeof y) { } +>s : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected static get t() { return y; } +>t : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected static set t(a: typeof y) { } +>t : { foo: string; bar: string; } +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + protected static u: (a: typeof y) => void; +>u : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + constructor(a: typeof y) { super(x) } +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } +>super(x) : void +>super : typeof Base +>x : { foo: string; } +} + diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers2.js b/tests/baselines/reference/derivedClassOverridesProtectedMembers2.js new file mode 100644 index 00000000000..55bfd0e924d --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers2.js @@ -0,0 +1,157 @@ +//// [derivedClassOverridesProtectedMembers2.ts] +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + protected a: typeof x; + protected b(a: typeof x) { } + protected get c() { return x; } + protected set c(v: typeof x) { } + protected d: (a: typeof x) => void ; + + protected static r: typeof x; + protected static s(a: typeof x) { } + protected static get t() { return x; } + protected static set t(v: typeof x) { } + protected static u: (a: typeof x) => void ; + +constructor(a: typeof x) { } +} + +// Increase visibility of all protected members to public +class Derived extends Base { + a: typeof y; + b(a: typeof y) { } + get c() { return y; } + set c(v: typeof y) { } + d: (a: typeof y) => void; + + static r: typeof y; + static s(a: typeof y) { } + static get t() { return y; } + static set t(a: typeof y) { } + static u: (a: typeof y) => void; + + constructor(a: typeof y) { super(a); } +} + +var d: Derived = new Derived(y); +var r1 = d.a; +var r2 = d.b(y); +var r3 = d.c; +var r3a = d.d; +d.c = y; +var r4 = Derived.r; +var r5 = Derived.s(y); +var r6 = Derived.t; +var r6a = Derived.u; +Derived.t = y; + +class Base2 { + [i: string]: Object; + [i: number]: typeof x; +} + +class Derived2 extends Base2 { + [i: string]: typeof x; + [i: number]: typeof y; +} + +var d2: Derived2; +var r7 = d2['']; +var r8 = d2[1]; + + + +//// [derivedClassOverridesProtectedMembers2.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var x; +var y; +var Base = (function () { + function Base(a) { + } + Base.prototype.b = function (a) { + }; + Object.defineProperty(Base.prototype, "c", { + get: function () { + return x; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + Base.s = function (a) { + }; + Object.defineProperty(Base, "t", { + get: function () { + return x; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Base; +})(); +// Increase visibility of all protected members to public +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived(a) { + _super.call(this, a); + } + Derived.prototype.b = function (a) { + }; + Object.defineProperty(Derived.prototype, "c", { + get: function () { + return y; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + Derived.s = function (a) { + }; + Object.defineProperty(Derived, "t", { + get: function () { + return y; + }, + set: function (a) { + }, + enumerable: true, + configurable: true + }); + return Derived; +})(Base); +var d = new Derived(y); +var r1 = d.a; +var r2 = d.b(y); +var r3 = d.c; +var r3a = d.d; +d.c = y; +var r4 = Derived.r; +var r5 = Derived.s(y); +var r6 = Derived.t; +var r6a = Derived.u; +Derived.t = y; +var Base2 = (function () { + function Base2() { + } + return Base2; +})(); +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2() { + _super.apply(this, arguments); + } + return Derived2; +})(Base2); +var d2; +var r7 = d2['']; +var r8 = d2[1]; diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers2.types b/tests/baselines/reference/derivedClassOverridesProtectedMembers2.types new file mode 100644 index 00000000000..3b6eb55256e --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers2.types @@ -0,0 +1,236 @@ +=== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers2.ts === +var x: { foo: string; } +>x : { foo: string; } +>foo : string + +var y: { foo: string; bar: string; } +>y : { foo: string; bar: string; } +>foo : string +>bar : string + +class Base { +>Base : Base + + protected a: typeof x; +>a : { foo: string; } +>x : { foo: string; } + + protected b(a: typeof x) { } +>b : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + protected get c() { return x; } +>c : { foo: string; } +>x : { foo: string; } + + protected set c(v: typeof x) { } +>c : { foo: string; } +>v : { foo: string; } +>x : { foo: string; } + + protected d: (a: typeof x) => void ; +>d : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + protected static r: typeof x; +>r : { foo: string; } +>x : { foo: string; } + + protected static s(a: typeof x) { } +>s : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + + protected static get t() { return x; } +>t : { foo: string; } +>x : { foo: string; } + + protected static set t(v: typeof x) { } +>t : { foo: string; } +>v : { foo: string; } +>x : { foo: string; } + + protected static u: (a: typeof x) => void ; +>u : (a: { foo: string; }) => void +>a : { foo: string; } +>x : { foo: string; } + +constructor(a: typeof x) { } +>a : { foo: string; } +>x : { foo: string; } +} + +// Increase visibility of all protected members to public +class Derived extends Base { +>Derived : Derived +>Base : Base + + a: typeof y; +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + b(a: typeof y) { } +>b : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + get c() { return y; } +>c : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + set c(v: typeof y) { } +>c : { foo: string; bar: string; } +>v : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + d: (a: typeof y) => void; +>d : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + static r: typeof y; +>r : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + static s(a: typeof y) { } +>s : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + static get t() { return y; } +>t : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + static set t(a: typeof y) { } +>t : { foo: string; bar: string; } +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + static u: (a: typeof y) => void; +>u : (a: { foo: string; bar: string; }) => void +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + + constructor(a: typeof y) { super(a); } +>a : { foo: string; bar: string; } +>y : { foo: string; bar: string; } +>super(a) : void +>super : typeof Base +>a : { foo: string; bar: string; } +} + +var d: Derived = new Derived(y); +>d : Derived +>Derived : Derived +>new Derived(y) : Derived +>Derived : typeof Derived +>y : { foo: string; bar: string; } + +var r1 = d.a; +>r1 : { foo: string; bar: string; } +>d.a : { foo: string; bar: string; } +>d : Derived +>a : { foo: string; bar: string; } + +var r2 = d.b(y); +>r2 : void +>d.b(y) : void +>d.b : (a: { foo: string; bar: string; }) => void +>d : Derived +>b : (a: { foo: string; bar: string; }) => void +>y : { foo: string; bar: string; } + +var r3 = d.c; +>r3 : { foo: string; bar: string; } +>d.c : { foo: string; bar: string; } +>d : Derived +>c : { foo: string; bar: string; } + +var r3a = d.d; +>r3a : (a: { foo: string; bar: string; }) => void +>d.d : (a: { foo: string; bar: string; }) => void +>d : Derived +>d : (a: { foo: string; bar: string; }) => void + +d.c = y; +>d.c = y : { foo: string; bar: string; } +>d.c : { foo: string; bar: string; } +>d : Derived +>c : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + +var r4 = Derived.r; +>r4 : { foo: string; bar: string; } +>Derived.r : { foo: string; bar: string; } +>Derived : typeof Derived +>r : { foo: string; bar: string; } + +var r5 = Derived.s(y); +>r5 : void +>Derived.s(y) : void +>Derived.s : (a: { foo: string; bar: string; }) => void +>Derived : typeof Derived +>s : (a: { foo: string; bar: string; }) => void +>y : { foo: string; bar: string; } + +var r6 = Derived.t; +>r6 : { foo: string; bar: string; } +>Derived.t : { foo: string; bar: string; } +>Derived : typeof Derived +>t : { foo: string; bar: string; } + +var r6a = Derived.u; +>r6a : (a: { foo: string; bar: string; }) => void +>Derived.u : (a: { foo: string; bar: string; }) => void +>Derived : typeof Derived +>u : (a: { foo: string; bar: string; }) => void + +Derived.t = y; +>Derived.t = y : { foo: string; bar: string; } +>Derived.t : { foo: string; bar: string; } +>Derived : typeof Derived +>t : { foo: string; bar: string; } +>y : { foo: string; bar: string; } + +class Base2 { +>Base2 : Base2 + + [i: string]: Object; +>i : string +>Object : Object + + [i: number]: typeof x; +>i : number +>x : { foo: string; } +} + +class Derived2 extends Base2 { +>Derived2 : Derived2 +>Base2 : Base2 + + [i: string]: typeof x; +>i : string +>x : { foo: string; } + + [i: number]: typeof y; +>i : number +>y : { foo: string; bar: string; } +} + +var d2: Derived2; +>d2 : Derived2 +>Derived2 : Derived2 + +var r7 = d2['']; +>r7 : { foo: string; } +>d2[''] : { foo: string; } +>d2 : Derived2 + +var r8 = d2[1]; +>r8 : { foo: string; bar: string; } +>d2[1] : { foo: string; bar: string; } +>d2 : Derived2 + + diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers3.errors.txt b/tests/baselines/reference/derivedClassOverridesProtectedMembers3.errors.txt new file mode 100644 index 00000000000..7dddd4d76f8 --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers3.errors.txt @@ -0,0 +1,124 @@ +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(23,7): error TS2416: Class 'Derived1' incorrectly extends base class 'Base': + Property 'a' is protected in type 'Derived1' but public in type 'Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(28,7): error TS2416: Class 'Derived2' incorrectly extends base class 'Base': + Property 'b' is protected in type 'Derived2' but public in type 'Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(33,7): error TS2416: Class 'Derived3' incorrectly extends base class 'Base': + Property 'c' is protected in type 'Derived3' but public in type 'Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(38,7): error TS2416: Class 'Derived4' incorrectly extends base class 'Base': + Property 'c' is protected in type 'Derived4' but public in type 'Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(43,7): error TS2416: Class 'Derived5' incorrectly extends base class 'Base': + Property 'd' is protected in type 'Derived5' but public in type 'Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(48,7): error TS2418: Class static side 'typeof Derived6' incorrectly extends base class static side 'typeof Base': + Property 'r' is protected in type 'typeof Derived6' but public in type 'typeof Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(53,7): error TS2418: Class static side 'typeof Derived7' incorrectly extends base class static side 'typeof Base': + Property 's' is protected in type 'typeof Derived7' but public in type 'typeof Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(58,7): error TS2418: Class static side 'typeof Derived8' incorrectly extends base class static side 'typeof Base': + Property 't' is protected in type 'typeof Derived8' but public in type 'typeof Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(63,7): error TS2418: Class static side 'typeof Derived9' incorrectly extends base class static side 'typeof Base': + Property 't' is protected in type 'typeof Derived9' but public in type 'typeof Base'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts(68,7): error TS2418: Class static side 'typeof Derived10' incorrectly extends base class static side 'typeof Base': + Property 'u' is protected in type 'typeof Derived10' but public in type 'typeof Base'. + + +==== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts (10 errors) ==== + + var x: { foo: string; } + var y: { foo: string; bar: string; } + + class Base { + a: typeof x; + b(a: typeof x) { } + get c() { return x; } + set c(v: typeof x) { } + d: (a: typeof x) => void; + + static r: typeof x; + static s(a: typeof x) { } + static get t() { return x; } + static set t(v: typeof x) { } + static u: (a: typeof x) => void; + + constructor(a: typeof x) {} + } + + // Errors + // decrease visibility of all public members to protected + class Derived1 extends Base { + ~~~~~~~~ +!!! error TS2416: Class 'Derived1' incorrectly extends base class 'Base': +!!! error TS2416: Property 'a' is protected in type 'Derived1' but public in type 'Base'. + protected a: typeof x; + constructor(a: typeof x) { super(a); } + } + + class Derived2 extends Base { + ~~~~~~~~ +!!! error TS2416: Class 'Derived2' incorrectly extends base class 'Base': +!!! error TS2416: Property 'b' is protected in type 'Derived2' but public in type 'Base'. + protected b(a: typeof x) { } + constructor(a: typeof x) { super(a); } + } + + class Derived3 extends Base { + ~~~~~~~~ +!!! error TS2416: Class 'Derived3' incorrectly extends base class 'Base': +!!! error TS2416: Property 'c' is protected in type 'Derived3' but public in type 'Base'. + protected get c() { return x; } + constructor(a: typeof x) { super(a); } + } + + class Derived4 extends Base { + ~~~~~~~~ +!!! error TS2416: Class 'Derived4' incorrectly extends base class 'Base': +!!! error TS2416: Property 'c' is protected in type 'Derived4' but public in type 'Base'. + protected set c(v: typeof x) { } + constructor(a: typeof x) { super(a); } + } + + class Derived5 extends Base { + ~~~~~~~~ +!!! error TS2416: Class 'Derived5' incorrectly extends base class 'Base': +!!! error TS2416: Property 'd' is protected in type 'Derived5' but public in type 'Base'. + protected d: (a: typeof x) => void ; + constructor(a: typeof x) { super(a); } + } + + class Derived6 extends Base { + ~~~~~~~~ +!!! error TS2418: Class static side 'typeof Derived6' incorrectly extends base class static side 'typeof Base': +!!! error TS2418: Property 'r' is protected in type 'typeof Derived6' but public in type 'typeof Base'. + protected static r: typeof x; + constructor(a: typeof x) { super(a); } + } + + class Derived7 extends Base { + ~~~~~~~~ +!!! error TS2418: Class static side 'typeof Derived7' incorrectly extends base class static side 'typeof Base': +!!! error TS2418: Property 's' is protected in type 'typeof Derived7' but public in type 'typeof Base'. + protected static s(a: typeof x) { } + constructor(a: typeof x) { super(a); } + } + + class Derived8 extends Base { + ~~~~~~~~ +!!! error TS2418: Class static side 'typeof Derived8' incorrectly extends base class static side 'typeof Base': +!!! error TS2418: Property 't' is protected in type 'typeof Derived8' but public in type 'typeof Base'. + protected static get t() { return x; } + constructor(a: typeof x) { super(a); } + } + + class Derived9 extends Base { + ~~~~~~~~ +!!! error TS2418: Class static side 'typeof Derived9' incorrectly extends base class static side 'typeof Base': +!!! error TS2418: Property 't' is protected in type 'typeof Derived9' but public in type 'typeof Base'. + protected static set t(v: typeof x) { } + constructor(a: typeof x) { super(a); } + } + + class Derived10 extends Base { + ~~~~~~~~~ +!!! error TS2418: Class static side 'typeof Derived10' incorrectly extends base class static side 'typeof Base': +!!! error TS2418: Property 'u' is protected in type 'typeof Derived10' but public in type 'typeof Base'. + protected static u: (a: typeof x) => void ; + constructor(a: typeof x) { super(a); } + } \ No newline at end of file diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers3.js b/tests/baselines/reference/derivedClassOverridesProtectedMembers3.js new file mode 100644 index 00000000000..0a228a04f71 --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers3.js @@ -0,0 +1,211 @@ +//// [derivedClassOverridesProtectedMembers3.ts] + +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + a: typeof x; + b(a: typeof x) { } + get c() { return x; } + set c(v: typeof x) { } + d: (a: typeof x) => void; + + static r: typeof x; + static s(a: typeof x) { } + static get t() { return x; } + static set t(v: typeof x) { } + static u: (a: typeof x) => void; + + constructor(a: typeof x) {} +} + +// Errors +// decrease visibility of all public members to protected +class Derived1 extends Base { + protected a: typeof x; + constructor(a: typeof x) { super(a); } +} + +class Derived2 extends Base { + protected b(a: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived3 extends Base { + protected get c() { return x; } + constructor(a: typeof x) { super(a); } +} + +class Derived4 extends Base { + protected set c(v: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived5 extends Base { + protected d: (a: typeof x) => void ; + constructor(a: typeof x) { super(a); } +} + +class Derived6 extends Base { + protected static r: typeof x; + constructor(a: typeof x) { super(a); } +} + +class Derived7 extends Base { + protected static s(a: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived8 extends Base { + protected static get t() { return x; } + constructor(a: typeof x) { super(a); } +} + +class Derived9 extends Base { + protected static set t(v: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived10 extends Base { + protected static u: (a: typeof x) => void ; + constructor(a: typeof x) { super(a); } +} + +//// [derivedClassOverridesProtectedMembers3.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var x; +var y; +var Base = (function () { + function Base(a) { + } + Base.prototype.b = function (a) { + }; + Object.defineProperty(Base.prototype, "c", { + get: function () { + return x; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + Base.s = function (a) { + }; + Object.defineProperty(Base, "t", { + get: function () { + return x; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Base; +})(); +// Errors +// decrease visibility of all public members to protected +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1(a) { + _super.call(this, a); + } + return Derived1; +})(Base); +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2(a) { + _super.call(this, a); + } + Derived2.prototype.b = function (a) { + }; + return Derived2; +})(Base); +var Derived3 = (function (_super) { + __extends(Derived3, _super); + function Derived3(a) { + _super.call(this, a); + } + Object.defineProperty(Derived3.prototype, "c", { + get: function () { + return x; + }, + enumerable: true, + configurable: true + }); + return Derived3; +})(Base); +var Derived4 = (function (_super) { + __extends(Derived4, _super); + function Derived4(a) { + _super.call(this, a); + } + Object.defineProperty(Derived4.prototype, "c", { + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Derived4; +})(Base); +var Derived5 = (function (_super) { + __extends(Derived5, _super); + function Derived5(a) { + _super.call(this, a); + } + return Derived5; +})(Base); +var Derived6 = (function (_super) { + __extends(Derived6, _super); + function Derived6(a) { + _super.call(this, a); + } + return Derived6; +})(Base); +var Derived7 = (function (_super) { + __extends(Derived7, _super); + function Derived7(a) { + _super.call(this, a); + } + Derived7.s = function (a) { + }; + return Derived7; +})(Base); +var Derived8 = (function (_super) { + __extends(Derived8, _super); + function Derived8(a) { + _super.call(this, a); + } + Object.defineProperty(Derived8, "t", { + get: function () { + return x; + }, + enumerable: true, + configurable: true + }); + return Derived8; +})(Base); +var Derived9 = (function (_super) { + __extends(Derived9, _super); + function Derived9(a) { + _super.call(this, a); + } + Object.defineProperty(Derived9, "t", { + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Derived9; +})(Base); +var Derived10 = (function (_super) { + __extends(Derived10, _super); + function Derived10(a) { + _super.call(this, a); + } + return Derived10; +})(Base); diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers4.errors.txt b/tests/baselines/reference/derivedClassOverridesProtectedMembers4.errors.txt new file mode 100644 index 00000000000..f22c656f3c7 --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers4.errors.txt @@ -0,0 +1,22 @@ +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers4.ts(12,7): error TS2416: Class 'Derived2' incorrectly extends base class 'Derived1': + Property 'a' is protected in type 'Derived2' but public in type 'Derived1'. + + +==== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers4.ts (1 errors) ==== + var x: { foo: string; } + var y: { foo: string; bar: string; } + + class Base { + protected a: typeof x; + } + + class Derived1 extends Base { + public a: typeof x; + } + + class Derived2 extends Derived1 { + ~~~~~~~~ +!!! error TS2416: Class 'Derived2' incorrectly extends base class 'Derived1': +!!! error TS2416: Property 'a' is protected in type 'Derived2' but public in type 'Derived1'. + protected a: typeof x; // Error, parent was public + } \ No newline at end of file diff --git a/tests/baselines/reference/derivedClassOverridesProtectedMembers4.js b/tests/baselines/reference/derivedClassOverridesProtectedMembers4.js new file mode 100644 index 00000000000..e1d5b766b82 --- /dev/null +++ b/tests/baselines/reference/derivedClassOverridesProtectedMembers4.js @@ -0,0 +1,44 @@ +//// [derivedClassOverridesProtectedMembers4.ts] +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + protected a: typeof x; +} + +class Derived1 extends Base { + public a: typeof x; +} + +class Derived2 extends Derived1 { + protected a: typeof x; // Error, parent was public +} + +//// [derivedClassOverridesProtectedMembers4.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var x; +var y; +var Base = (function () { + function Base() { + } + return Base; +})(); +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1() { + _super.apply(this, arguments); + } + return Derived1; +})(Base); +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2() { + _super.apply(this, arguments); + } + return Derived2; +})(Derived1); diff --git a/tests/baselines/reference/derivedClassTransitivity4.errors.txt b/tests/baselines/reference/derivedClassTransitivity4.errors.txt new file mode 100644 index 00000000000..5950eddf6be --- /dev/null +++ b/tests/baselines/reference/derivedClassTransitivity4.errors.txt @@ -0,0 +1,37 @@ +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassTransitivity4.ts(18,1): error TS2322: Type 'E' is not assignable to type 'C': + Types of property 'foo' are incompatible: + Type '(x?: string) => void' is not assignable to type '(x: number) => void': + Types of parameters 'x' and 'x' are incompatible: + Type 'string' is not assignable to type 'number'. +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassTransitivity4.ts(19,9): error TS2445: Property 'foo' is protected and only accessible within class 'C' and its subclasses. + + +==== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassTransitivity4.ts (2 errors) ==== + // subclassing is not transitive when you can remove required parameters and add optional parameters on protected members + + class C { + protected foo(x: number) { } + } + + class D extends C { + protected foo() { } // ok to drop parameters + } + + class E extends D { + public foo(x?: string) { } // ok to add optional parameters + } + + var c: C; + var d: D; + var e: E; + c = e; + ~ +!!! error TS2322: Type 'E' is not assignable to type 'C': +!!! error TS2322: Types of property 'foo' are incompatible: +!!! error TS2322: Type '(x?: string) => void' is not assignable to type '(x: number) => void': +!!! error TS2322: Types of parameters 'x' and 'x' are incompatible: +!!! error TS2322: Type 'string' is not assignable to type 'number'. + var r = c.foo(1); + ~~~~~ +!!! error TS2445: Property 'foo' is protected and only accessible within class 'C' and its subclasses. + var r2 = e.foo(''); \ No newline at end of file diff --git a/tests/baselines/reference/derivedClassTransitivity4.js b/tests/baselines/reference/derivedClassTransitivity4.js new file mode 100644 index 00000000000..5249c6aad2e --- /dev/null +++ b/tests/baselines/reference/derivedClassTransitivity4.js @@ -0,0 +1,61 @@ +//// [derivedClassTransitivity4.ts] +// subclassing is not transitive when you can remove required parameters and add optional parameters on protected members + +class C { + protected foo(x: number) { } +} + +class D extends C { + protected foo() { } // ok to drop parameters +} + +class E extends D { + public foo(x?: string) { } // ok to add optional parameters +} + +var c: C; +var d: D; +var e: E; +c = e; +var r = c.foo(1); +var r2 = e.foo(''); + +//// [derivedClassTransitivity4.js] +// subclassing is not transitive when you can remove required parameters and add optional parameters on protected members +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var C = (function () { + function C() { + } + C.prototype.foo = function (x) { + }; + return C; +})(); +var D = (function (_super) { + __extends(D, _super); + function D() { + _super.apply(this, arguments); + } + D.prototype.foo = function () { + }; // ok to drop parameters + return D; +})(C); +var E = (function (_super) { + __extends(E, _super); + function E() { + _super.apply(this, arguments); + } + E.prototype.foo = function (x) { + }; // ok to add optional parameters + return E; +})(D); +var c; +var d; +var e; +c = e; +var r = c.foo(1); +var r2 = e.foo(''); diff --git a/tests/baselines/reference/derivedClassWithPrivateInstanceShadowingProtectedInstance.errors.txt b/tests/baselines/reference/derivedClassWithPrivateInstanceShadowingProtectedInstance.errors.txt new file mode 100644 index 00000000000..aebe32f7fbf --- /dev/null +++ b/tests/baselines/reference/derivedClassWithPrivateInstanceShadowingProtectedInstance.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateInstanceShadowingProtectedInstance.ts(13,7): error TS2416: Class 'Derived' incorrectly extends base class 'Base': + Property 'x' is private in type 'Derived' but not in type 'Base'. + + +==== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateInstanceShadowingProtectedInstance.ts (1 errors) ==== + + class Base { + protected x: string; + protected fn(): string { + return ''; + } + + protected get a() { return 1; } + protected set a(v) { } + } + + // error, not a subtype + class Derived extends Base { + ~~~~~~~ +!!! error TS2416: Class 'Derived' incorrectly extends base class 'Base': +!!! error TS2416: Property 'x' is private in type 'Derived' but not in type 'Base'. + private x: string; + private fn(): string { + return ''; + } + + private get a() { return 1; } + private set a(v) { } + } + \ No newline at end of file diff --git a/tests/baselines/reference/derivedClassWithPrivateInstanceShadowingProtectedInstance.js b/tests/baselines/reference/derivedClassWithPrivateInstanceShadowingProtectedInstance.js new file mode 100644 index 00000000000..f802a225088 --- /dev/null +++ b/tests/baselines/reference/derivedClassWithPrivateInstanceShadowingProtectedInstance.js @@ -0,0 +1,68 @@ +//// [derivedClassWithPrivateInstanceShadowingProtectedInstance.ts] + +class Base { + protected x: string; + protected fn(): string { + return ''; + } + + protected get a() { return 1; } + protected set a(v) { } +} + +// error, not a subtype +class Derived extends Base { + private x: string; + private fn(): string { + return ''; + } + + private get a() { return 1; } + private set a(v) { } +} + + +//// [derivedClassWithPrivateInstanceShadowingProtectedInstance.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base() { + } + Base.prototype.fn = function () { + return ''; + }; + Object.defineProperty(Base.prototype, "a", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Base; +})(); +// error, not a subtype +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + _super.apply(this, arguments); + } + Derived.prototype.fn = function () { + return ''; + }; + Object.defineProperty(Derived.prototype, "a", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Derived; +})(Base); diff --git a/tests/baselines/reference/derivedClassWithPrivateStaticShadowingProtectedStatic.errors.txt b/tests/baselines/reference/derivedClassWithPrivateStaticShadowingProtectedStatic.errors.txt new file mode 100644 index 00000000000..a6aa878e54c --- /dev/null +++ b/tests/baselines/reference/derivedClassWithPrivateStaticShadowingProtectedStatic.errors.txt @@ -0,0 +1,29 @@ +tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateStaticShadowingProtectedStatic.ts(13,7): error TS2418: Class static side 'typeof Derived' incorrectly extends base class static side 'typeof Base': + Property 'x' is private in type 'typeof Derived' but not in type 'typeof Base'. + + +==== tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateStaticShadowingProtectedStatic.ts (1 errors) ==== + + class Base { + protected static x: string; + protected static fn(): string { + return ''; + } + + protected static get a() { return 1; } + protected static set a(v) { } + } + + // should be error + class Derived extends Base { + ~~~~~~~ +!!! error TS2418: Class static side 'typeof Derived' incorrectly extends base class static side 'typeof Base': +!!! error TS2418: Property 'x' is private in type 'typeof Derived' but not in type 'typeof Base'. + private static x: string; + private static fn(): string { + return ''; + } + + private static get a() { return 1; } + private static set a(v) { } + } \ No newline at end of file diff --git a/tests/baselines/reference/derivedClassWithPrivateStaticShadowingProtectedStatic.js b/tests/baselines/reference/derivedClassWithPrivateStaticShadowingProtectedStatic.js new file mode 100644 index 00000000000..558e2309757 --- /dev/null +++ b/tests/baselines/reference/derivedClassWithPrivateStaticShadowingProtectedStatic.js @@ -0,0 +1,67 @@ +//// [derivedClassWithPrivateStaticShadowingProtectedStatic.ts] + +class Base { + protected static x: string; + protected static fn(): string { + return ''; + } + + protected static get a() { return 1; } + protected static set a(v) { } +} + +// should be error +class Derived extends Base { + private static x: string; + private static fn(): string { + return ''; + } + + private static get a() { return 1; } + private static set a(v) { } +} + +//// [derivedClassWithPrivateStaticShadowingProtectedStatic.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base() { + } + Base.fn = function () { + return ''; + }; + Object.defineProperty(Base, "a", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Base; +})(); +// should be error +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + _super.apply(this, arguments); + } + Derived.fn = function () { + return ''; + }; + Object.defineProperty(Derived, "a", { + get: function () { + return 1; + }, + set: function (v) { + }, + enumerable: true, + configurable: true + }); + return Derived; +})(Base); diff --git a/tests/baselines/reference/emptyExpr.js b/tests/baselines/reference/emptyExpr.js index 36fd5ccee19..de3bddeba1e 100644 --- a/tests/baselines/reference/emptyExpr.js +++ b/tests/baselines/reference/emptyExpr.js @@ -2,4 +2,4 @@ [{},] //// [emptyExpr.js] -[{}, ]; +[{},]; diff --git a/tests/baselines/reference/errorHandlingInInstanceOf.errors.txt b/tests/baselines/reference/errorHandlingInInstanceOf.errors.txt new file mode 100644 index 00000000000..e4db287fcdd --- /dev/null +++ b/tests/baselines/reference/errorHandlingInInstanceOf.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/errorHandlingInInstanceOf.ts(1,5): error TS2304: Cannot find name 'x'. +tests/cases/compiler/errorHandlingInInstanceOf.ts(5,18): error TS2304: Cannot find name 'UnknownType'. + + +==== tests/cases/compiler/errorHandlingInInstanceOf.ts (2 errors) ==== + if (x instanceof String) { + ~ +!!! error TS2304: Cannot find name 'x'. + } + + var y: any; + if (y instanceof UnknownType) { + ~~~~~~~~~~~ +!!! error TS2304: Cannot find name 'UnknownType'. + } \ No newline at end of file diff --git a/tests/baselines/reference/errorHandlingInInstanceOf.js b/tests/baselines/reference/errorHandlingInInstanceOf.js new file mode 100644 index 00000000000..b98e2bf8a77 --- /dev/null +++ b/tests/baselines/reference/errorHandlingInInstanceOf.js @@ -0,0 +1,14 @@ +//// [errorHandlingInInstanceOf.ts] +if (x instanceof String) { +} + +var y: any; +if (y instanceof UnknownType) { +} + +//// [errorHandlingInInstanceOf.js] +if (x instanceof String) { +} +var y; +if (y instanceof UnknownType) { +} diff --git a/tests/baselines/reference/interfaceWithAccessibilityModifiers.errors.txt b/tests/baselines/reference/interfaceWithAccessibilityModifiers.errors.txt new file mode 100644 index 00000000000..ecf803d522b --- /dev/null +++ b/tests/baselines/reference/interfaceWithAccessibilityModifiers.errors.txt @@ -0,0 +1,18 @@ +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts(3,5): error TS1131: Property or signature expected. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts(4,5): error TS1131: Property or signature expected. +tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts(5,5): error TS1131: Property or signature expected. + + +==== tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts (3 errors) ==== + // Errors + interface Foo { + public a: any; + ~~~~~~ +!!! error TS1131: Property or signature expected. + private b: any; + ~~~~~~~ +!!! error TS1131: Property or signature expected. + protected c: any; + ~~~~~~~~~ +!!! error TS1131: Property or signature expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.errors.txt b/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.errors.txt index 95c12e4db04..64d2f3d3059 100644 --- a/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.errors.txt +++ b/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.errors.txt @@ -1,16 +1,21 @@ tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(3,12): error TS2385: Overload signatures must all be public, private or protected. tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(7,12): error TS2385: Overload signatures must all be public, private or protected. tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(12,19): error TS2385: Overload signatures must all be public, private or protected. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(16,19): error TS2385: Overload signatures must all be public, private or protected. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(23,12): error TS2385: Overload signatures must all be public, private or protected. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(27,12): error TS2385: Overload signatures must all be public, private or protected. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(32,19): error TS2385: Overload signatures must all be public, private or protected. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(36,19): error TS2385: Overload signatures must all be public, private or protected. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(42,9): error TS2341: Property 'foo' is private and only accessible within class 'C'. -tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(45,10): error TS2341: Property 'foo' is private and only accessible within class 'D'. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(15,15): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(16,15): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(20,19): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(25,19): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(32,12): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(36,12): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(41,15): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(45,19): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(49,19): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(53,19): error TS2385: Overload signatures must all be public, private or protected. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(59,9): error TS2341: Property 'foo' is private and only accessible within class 'C'. +tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts(62,10): error TS2341: Property 'foo' is private and only accessible within class 'D'. -==== tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts (10 errors) ==== +==== tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts (15 errors) ==== class C { private foo(x: number); public foo(x: number, y: string); // error @@ -31,12 +36,27 @@ tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclara !!! error TS2385: Overload signatures must all be public, private or protected. private static foo(x: any, y?: any) { } + protected baz(x: string); // error + ~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + protected baz(x: number, y: string); // error + ~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + private baz(x: any, y?: any) { } + private static bar(x: 'hi'); public static bar(x: string); // error ~~~ !!! error TS2385: Overload signatures must all be public, private or protected. private static bar(x: number, y: string); private static bar(x: any, y?: any) { } + + protected static baz(x: 'hi'); + public static baz(x: string); // error + ~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + protected static baz(x: number, y: string); + protected static baz(x: any, y?: any) { } } class D { @@ -53,6 +73,12 @@ tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclara private bar(x: T, y: T); private bar(x: any, y?: any) { } + private baz(x: string); + protected baz(x: number, y: string); // error + ~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + private baz(x: any, y?: any) { } + private static foo(x: number); public static foo(x: number, y: string); // error ~~~ @@ -65,6 +91,12 @@ tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclara !!! error TS2385: Overload signatures must all be public, private or protected. private static bar(x: number, y: string); private static bar(x: any, y?: any) { } + + public static baz(x: string); // error + ~~~ +!!! error TS2385: Overload signatures must all be public, private or protected. + protected static baz(x: number, y: string); + protected static baz(x: any, y?: any) { } } var c: C; diff --git a/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.js b/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.js index 27e3bb5e85d..2726756c803 100644 --- a/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.js +++ b/tests/baselines/reference/memberFunctionsWithPublicPrivateOverloads.js @@ -13,10 +13,19 @@ class C { public static foo(x: number, y: string); // error private static foo(x: any, y?: any) { } + protected baz(x: string); // error + protected baz(x: number, y: string); // error + private baz(x: any, y?: any) { } + private static bar(x: 'hi'); public static bar(x: string); // error private static bar(x: number, y: string); private static bar(x: any, y?: any) { } + + protected static baz(x: 'hi'); + public static baz(x: string); // error + protected static baz(x: number, y: string); + protected static baz(x: any, y?: any) { } } class D { @@ -29,6 +38,10 @@ class D { private bar(x: T, y: T); private bar(x: any, y?: any) { } + private baz(x: string); + protected baz(x: number, y: string); // error + private baz(x: any, y?: any) { } + private static foo(x: number); public static foo(x: number, y: string); // error private static foo(x: any, y?: any) { } @@ -37,6 +50,10 @@ class D { public static bar(x: string); // error private static bar(x: number, y: string); private static bar(x: any, y?: any) { } + + public static baz(x: string); // error + protected static baz(x: number, y: string); + protected static baz(x: any, y?: any) { } } var c: C; @@ -55,8 +72,12 @@ var C = (function () { }; C.foo = function (x, y) { }; + C.prototype.baz = function (x, y) { + }; C.bar = function (x, y) { }; + C.baz = function (x, y) { + }; return C; })(); var D = (function () { @@ -66,10 +87,14 @@ var D = (function () { }; D.prototype.bar = function (x, y) { }; + D.prototype.baz = function (x, y) { + }; D.foo = function (x, y) { }; D.bar = function (x, y) { }; + D.baz = function (x, y) { + }; return D; })(); var c; diff --git a/tests/baselines/reference/parserArrayLiteralExpression10.js b/tests/baselines/reference/parserArrayLiteralExpression10.js index 8cbbff49c9f..986d3045dc0 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression10.js +++ b/tests/baselines/reference/parserArrayLiteralExpression10.js @@ -2,4 +2,4 @@ var v = [1,1,]; //// [parserArrayLiteralExpression10.js] -var v = [1, 1, ]; +var v = [1, 1,]; diff --git a/tests/baselines/reference/parserArrayLiteralExpression15.js b/tests/baselines/reference/parserArrayLiteralExpression15.js index f31617a998b..84ab9dac240 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression15.js +++ b/tests/baselines/reference/parserArrayLiteralExpression15.js @@ -2,4 +2,4 @@ var v = [,,1,1,,1,,1,1,,1,]; //// [parserArrayLiteralExpression15.js] -var v = [, , 1, 1, , 1, , 1, 1, , 1, ]; +var v = [, , 1, 1, , 1, , 1, 1, , 1,]; diff --git a/tests/baselines/reference/parserArrayLiteralExpression2.js b/tests/baselines/reference/parserArrayLiteralExpression2.js index f6984016054..1fb26155eb5 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression2.js +++ b/tests/baselines/reference/parserArrayLiteralExpression2.js @@ -2,4 +2,4 @@ var v = [,]; //// [parserArrayLiteralExpression2.js] -var v = [, ]; +var v = [,]; diff --git a/tests/baselines/reference/parserArrayLiteralExpression3.js b/tests/baselines/reference/parserArrayLiteralExpression3.js index 6d70ebdb37f..2d7d19fc2c3 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression3.js +++ b/tests/baselines/reference/parserArrayLiteralExpression3.js @@ -2,4 +2,4 @@ var v = [,,]; //// [parserArrayLiteralExpression3.js] -var v = [, , ]; +var v = [, ,]; diff --git a/tests/baselines/reference/parserArrayLiteralExpression4.js b/tests/baselines/reference/parserArrayLiteralExpression4.js index dd75cb14fd6..2287897338e 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression4.js +++ b/tests/baselines/reference/parserArrayLiteralExpression4.js @@ -2,4 +2,4 @@ var v = [,,,]; //// [parserArrayLiteralExpression4.js] -var v = [, , , ]; +var v = [, , ,]; diff --git a/tests/baselines/reference/parserArrayLiteralExpression7.js b/tests/baselines/reference/parserArrayLiteralExpression7.js index 2ea0b298b4e..b302e87e352 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression7.js +++ b/tests/baselines/reference/parserArrayLiteralExpression7.js @@ -2,4 +2,4 @@ var v = [1,]; //// [parserArrayLiteralExpression7.js] -var v = [1, ]; +var v = [1,]; diff --git a/tests/baselines/reference/parserArrayLiteralExpression8.js b/tests/baselines/reference/parserArrayLiteralExpression8.js index 7ef65a8cc0d..223a86db229 100644 --- a/tests/baselines/reference/parserArrayLiteralExpression8.js +++ b/tests/baselines/reference/parserArrayLiteralExpression8.js @@ -2,4 +2,4 @@ var v = [,1,]; //// [parserArrayLiteralExpression8.js] -var v = [, 1, ]; +var v = [, 1,]; diff --git a/tests/baselines/reference/parserStrictMode15.errors.txt b/tests/baselines/reference/parserStrictMode15.errors.txt index 6b650cf1aae..0bcaaf33786 100644 --- a/tests/baselines/reference/parserStrictMode15.errors.txt +++ b/tests/baselines/reference/parserStrictMode15.errors.txt @@ -1,8 +1,11 @@ +tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode15.ts(2,8): error TS1102: 'delete' cannot be called on an identifier in strict mode. tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode15.ts(2,8): error TS2304: Cannot find name 'a'. -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode15.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode15.ts (2 errors) ==== "use strict"; delete a; ~ +!!! error TS1102: 'delete' cannot be called on an identifier in strict mode. + ~ !!! error TS2304: Cannot find name 'a'. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode15.js b/tests/baselines/reference/parserStrictMode15.js deleted file mode 100644 index 5fcf91bbddf..00000000000 --- a/tests/baselines/reference/parserStrictMode15.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode15.ts] -"use strict"; -delete a; - -//// [parserStrictMode15.js] -"use strict"; -delete a; diff --git a/tests/baselines/reference/parserStrictMode7.errors.txt b/tests/baselines/reference/parserStrictMode7.errors.txt index fa4bd066599..6ee6ca43042 100644 --- a/tests/baselines/reference/parserStrictMode7.errors.txt +++ b/tests/baselines/reference/parserStrictMode7.errors.txt @@ -1,8 +1,11 @@ +tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode7.ts(2,3): error TS1100: Invalid use of 'eval' in strict mode. tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode7.ts(2,3): error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. -==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode7.ts (1 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/StrictMode/parserStrictMode7.ts (2 errors) ==== "use strict"; ++eval; ~~~~ +!!! error TS1100: Invalid use of 'eval' in strict mode. + ~~~~ !!! error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. \ No newline at end of file diff --git a/tests/baselines/reference/parserStrictMode7.js b/tests/baselines/reference/parserStrictMode7.js deleted file mode 100644 index fafd603da65..00000000000 --- a/tests/baselines/reference/parserStrictMode7.js +++ /dev/null @@ -1,7 +0,0 @@ -//// [parserStrictMode7.ts] -"use strict"; -++eval; - -//// [parserStrictMode7.js] -"use strict"; -++eval; diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass2.errors.txt b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass2.errors.txt new file mode 100644 index 00000000000..289ecdcb9fe --- /dev/null +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass2.errors.txt @@ -0,0 +1,160 @@ +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(13,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(26,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived1'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(28,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived1'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(29,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(30,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived1'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(42,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived2'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(43,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived2'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(45,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(59,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(60,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(61,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(63,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(75,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived4'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(76,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived4'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(77,9): error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived4'. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(78,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(90,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(91,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(92,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(93,1): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts(94,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + + +==== tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts (21 errors) ==== + class Base { + protected x: string; + method() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // OK, accessed within their declaring class + d1.x; // OK, accessed within their declaring class + d2.x; // OK, accessed within their declaring class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + d4.x; // OK, accessed within their declaring class + } + } + + class Derived1 extends Base { + method1() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + ~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived1'. + d1.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived1'. + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + d4.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived1'. + } + } + + class Derived2 extends Base { + method2() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + ~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived2'. + d1.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived2'. + d2.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class or one of its subclasses + } + } + + class Derived3 extends Derived1 { + protected x: string; + method3() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + ~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. + d1.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. + d2.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. + d3.x; // OK, accessed within their declaring class + d4.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived3'. + } + } + + class Derived4 extends Derived2 { + method4() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + ~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived4'. + d1.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived4'. + d2.x; // Error, isn't accessed through an instance of the enclosing class + ~~~~ +!!! error TS2446: Property 'x' is protected and only accessible through an instance of class 'Derived4'. + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + } + } + + + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + d1.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + d2.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + d3.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + d4.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. \ No newline at end of file diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass2.js b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass2.js new file mode 100644 index 00000000000..73abc96cc43 --- /dev/null +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass2.js @@ -0,0 +1,206 @@ +//// [protectedClassPropertyAccessibleWithinSubclass2.ts] +class Base { + protected x: string; + method() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // OK, accessed within their declaring class + d1.x; // OK, accessed within their declaring class + d2.x; // OK, accessed within their declaring class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within their declaring class + } +} + +class Derived1 extends Base { + method1() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // Error, isn't accessed through an instance of the enclosing class + } +} + +class Derived2 extends Base { + method2() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class or one of its subclasses + } +} + +class Derived3 extends Derived1 { + protected x: string; + method3() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // OK, accessed within their declaring class + d4.x; // Error, isn't accessed through an instance of the enclosing class + } +} + +class Derived4 extends Derived2 { + method4() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + } +} + + +var b: Base; +var d1: Derived1; +var d2: Derived2; +var d3: Derived3; +var d4: Derived4; + +b.x; // Error, neither within their declaring class nor classes derived from their declaring class +d1.x; // Error, neither within their declaring class nor classes derived from their declaring class +d2.x; // Error, neither within their declaring class nor classes derived from their declaring class +d3.x; // Error, neither within their declaring class nor classes derived from their declaring class +d4.x; // Error, neither within their declaring class nor classes derived from their declaring class + +//// [protectedClassPropertyAccessibleWithinSubclass2.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base() { + } + Base.prototype.method = function () { + var b; + var d1; + var d2; + var d3; + var d4; + b.x; // OK, accessed within their declaring class + d1.x; // OK, accessed within their declaring class + d2.x; // OK, accessed within their declaring class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within their declaring class + }; + return Base; +})(); +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1() { + _super.apply(this, arguments); + } + Derived1.prototype.method1 = function () { + var b; + var d1; + var d2; + var d3; + var d4; + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // Error, isn't accessed through an instance of the enclosing class + }; + return Derived1; +})(Base); +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2() { + _super.apply(this, arguments); + } + Derived2.prototype.method2 = function () { + var b; + var d1; + var d2; + var d3; + var d4; + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class or one of its subclasses + }; + return Derived2; +})(Base); +var Derived3 = (function (_super) { + __extends(Derived3, _super); + function Derived3() { + _super.apply(this, arguments); + } + Derived3.prototype.method3 = function () { + var b; + var d1; + var d2; + var d3; + var d4; + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // OK, accessed within their declaring class + d4.x; // Error, isn't accessed through an instance of the enclosing class + }; + return Derived3; +})(Derived1); +var Derived4 = (function (_super) { + __extends(Derived4, _super); + function Derived4() { + _super.apply(this, arguments); + } + Derived4.prototype.method4 = function () { + var b; + var d1; + var d2; + var d3; + var d4; + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + }; + return Derived4; +})(Derived2); +var b; +var d1; +var d2; +var d3; +var d4; +b.x; // Error, neither within their declaring class nor classes derived from their declaring class +d1.x; // Error, neither within their declaring class nor classes derived from their declaring class +d2.x; // Error, neither within their declaring class nor classes derived from their declaring class +d3.x; // Error, neither within their declaring class nor classes derived from their declaring class +d4.x; // Error, neither within their declaring class nor classes derived from their declaring class diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass3.errors.txt b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass3.errors.txt new file mode 100644 index 00000000000..f2b19d043c2 --- /dev/null +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass3.errors.txt @@ -0,0 +1,19 @@ +tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass3.ts(11,15): error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword + + +==== tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass3.ts (1 errors) ==== + class Base { + protected x: string; + method() { + this.x; // OK, accessed within their declaring class + } + } + + class Derived extends Base { + method1() { + this.x; // OK, accessed within a subclass of the declaring class + super.x; // Error, x is not public + ~ +!!! error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword + } + } \ No newline at end of file diff --git a/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass3.js b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass3.js new file mode 100644 index 00000000000..8085112d994 --- /dev/null +++ b/tests/baselines/reference/protectedClassPropertyAccessibleWithinSubclass3.js @@ -0,0 +1,41 @@ +//// [protectedClassPropertyAccessibleWithinSubclass3.ts] +class Base { + protected x: string; + method() { + this.x; // OK, accessed within their declaring class + } +} + +class Derived extends Base { + method1() { + this.x; // OK, accessed within a subclass of the declaring class + super.x; // Error, x is not public + } +} + +//// [protectedClassPropertyAccessibleWithinSubclass3.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base() { + } + Base.prototype.method = function () { + this.x; // OK, accessed within their declaring class + }; + return Base; +})(); +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + _super.apply(this, arguments); + } + Derived.prototype.method1 = function () { + this.x; // OK, accessed within a subclass of the declaring class + _super.prototype.x; // Error, x is not public + }; + return Derived; +})(Base); diff --git a/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass.errors.txt b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass.errors.txt new file mode 100644 index 00000000000..911633cb98f --- /dev/null +++ b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass.errors.txt @@ -0,0 +1,67 @@ +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(7,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(16,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(25,9): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(40,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(41,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(42,1): error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts(43,1): error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + + +==== tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts (7 errors) ==== + class Base { + protected static x: string; + static staticMethod() { + Base.x; // OK, accessed within their declaring class + Derived1.x; // OK, accessed within their declaring class + Derived2.x; // OK, accessed within their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + } + } + + class Derived1 extends Base { + static staticMethod1() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + } + } + + class Derived2 extends Base { + static staticMethod2() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + ~~~~~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. + } + } + + class Derived3 extends Derived1 { + protected static x: string; + static staticMethod3() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // OK, accessed within their declaring class + } + } + + + Base.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + Derived1.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + Derived2.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Base' and its subclasses. + Derived3.x; // Error, neither within their declaring class nor classes derived from their declaring class + ~~~~~~~~~~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Derived3' and its subclasses. \ No newline at end of file diff --git a/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass.js b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass.js new file mode 100644 index 00000000000..81c11369ee8 --- /dev/null +++ b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass.js @@ -0,0 +1,106 @@ +//// [protectedStaticClassPropertyAccessibleWithinSubclass.ts] +class Base { + protected static x: string; + static staticMethod() { + Base.x; // OK, accessed within their declaring class + Derived1.x; // OK, accessed within their declaring class + Derived2.x; // OK, accessed within their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + } +} + +class Derived1 extends Base { + static staticMethod1() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + } +} + +class Derived2 extends Base { + static staticMethod2() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + } +} + +class Derived3 extends Derived1 { + protected static x: string; + static staticMethod3() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // OK, accessed within their declaring class + } +} + + +Base.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived1.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived2.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived3.x; // Error, neither within their declaring class nor classes derived from their declaring class + +//// [protectedStaticClassPropertyAccessibleWithinSubclass.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base() { + } + Base.staticMethod = function () { + Base.x; // OK, accessed within their declaring class + Derived1.x; // OK, accessed within their declaring class + Derived2.x; // OK, accessed within their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + }; + return Base; +})(); +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1() { + _super.apply(this, arguments); + } + Derived1.staticMethod1 = function () { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + }; + return Derived1; +})(Base); +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2() { + _super.apply(this, arguments); + } + Derived2.staticMethod2 = function () { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + }; + return Derived2; +})(Base); +var Derived3 = (function (_super) { + __extends(Derived3, _super); + function Derived3() { + _super.apply(this, arguments); + } + Derived3.staticMethod3 = function () { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // OK, accessed within their declaring class + }; + return Derived3; +})(Derived1); +Base.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived1.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived2.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived3.x; // Error, neither within their declaring class nor classes derived from their declaring class diff --git a/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass2.errors.txt b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass2.errors.txt new file mode 100644 index 00000000000..1f1bd72617c --- /dev/null +++ b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass2.errors.txt @@ -0,0 +1,30 @@ +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass2.ts(11,15): error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword +tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass2.ts(19,15): error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword + + +==== tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass2.ts (2 errors) ==== + class Base { + protected static x: string; + static staticMethod() { + this.x; // OK, accessed within their declaring class + } + } + + class Derived1 extends Base { + static staticMethod1() { + this.x; // OK, accessed within a class derived from their declaring class + super.x; // Error, x is not public + ~ +!!! error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword + } + } + + class Derived2 extends Derived1 { + protected static x: string; + static staticMethod3() { + this.x; // OK, accessed within a class derived from their declaring class + super.x; // Error, x is not public + ~ +!!! error TS2340: Only public and protected methods of the base class are accessible via the 'super' keyword + } + } \ No newline at end of file diff --git a/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass2.js b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass2.js new file mode 100644 index 00000000000..520851f5e95 --- /dev/null +++ b/tests/baselines/reference/protectedStaticClassPropertyAccessibleWithinSubclass2.js @@ -0,0 +1,60 @@ +//// [protectedStaticClassPropertyAccessibleWithinSubclass2.ts] +class Base { + protected static x: string; + static staticMethod() { + this.x; // OK, accessed within their declaring class + } +} + +class Derived1 extends Base { + static staticMethod1() { + this.x; // OK, accessed within a class derived from their declaring class + super.x; // Error, x is not public + } +} + +class Derived2 extends Derived1 { + protected static x: string; + static staticMethod3() { + this.x; // OK, accessed within a class derived from their declaring class + super.x; // Error, x is not public + } +} + +//// [protectedStaticClassPropertyAccessibleWithinSubclass2.js] +var __extends = this.__extends || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + __.prototype = b.prototype; + d.prototype = new __(); +}; +var Base = (function () { + function Base() { + } + Base.staticMethod = function () { + this.x; // OK, accessed within their declaring class + }; + return Base; +})(); +var Derived1 = (function (_super) { + __extends(Derived1, _super); + function Derived1() { + _super.apply(this, arguments); + } + Derived1.staticMethod1 = function () { + this.x; // OK, accessed within a class derived from their declaring class + _super.x; // Error, x is not public + }; + return Derived1; +})(Base); +var Derived2 = (function (_super) { + __extends(Derived2, _super); + function Derived2() { + _super.apply(this, arguments); + } + Derived2.staticMethod3 = function () { + this.x; // OK, accessed within a class derived from their declaring class + _super.x; // Error, x is not public + }; + return Derived2; +})(Derived1); diff --git a/tests/baselines/reference/protectedStaticNotAccessibleInClodule.errors.txt b/tests/baselines/reference/protectedStaticNotAccessibleInClodule.errors.txt new file mode 100644 index 00000000000..059e5d6cb12 --- /dev/null +++ b/tests/baselines/reference/protectedStaticNotAccessibleInClodule.errors.txt @@ -0,0 +1,17 @@ +tests/cases/conformance/classes/members/accessibility/protectedStaticNotAccessibleInClodule.ts(10,20): error TS2445: Property 'bar' is protected and only accessible within class 'C' and its subclasses. + + +==== tests/cases/conformance/classes/members/accessibility/protectedStaticNotAccessibleInClodule.ts (1 errors) ==== + // Any attempt to access a private property member outside the class body that contains its declaration results in a compile-time error. + + class C { + public static foo: string; + protected static bar: string; + } + + module C { + export var f = C.foo; // OK + export var b = C.bar; // error + ~~~~~ +!!! error TS2445: Property 'bar' is protected and only accessible within class 'C' and its subclasses. + } \ No newline at end of file diff --git a/tests/baselines/reference/protectedStaticNotAccessibleInClodule.js b/tests/baselines/reference/protectedStaticNotAccessibleInClodule.js new file mode 100644 index 00000000000..7534850b34f --- /dev/null +++ b/tests/baselines/reference/protectedStaticNotAccessibleInClodule.js @@ -0,0 +1,25 @@ +//// [protectedStaticNotAccessibleInClodule.ts] +// Any attempt to access a private property member outside the class body that contains its declaration results in a compile-time error. + +class C { + public static foo: string; + protected static bar: string; +} + +module C { + export var f = C.foo; // OK + export var b = C.bar; // error +} + +//// [protectedStaticNotAccessibleInClodule.js] +// Any attempt to access a private property member outside the class body that contains its declaration results in a compile-time error. +var C = (function () { + function C() { + } + return C; +})(); +var C; +(function (C) { + C.f = C.foo; // OK + C.b = C.bar; // error +})(C || (C = {})); diff --git a/tests/baselines/reference/trailingCommaInHeterogenousArrayLiteral1.js b/tests/baselines/reference/trailingCommaInHeterogenousArrayLiteral1.js index 26dc61d189c..478c05f5e73 100644 --- a/tests/baselines/reference/trailingCommaInHeterogenousArrayLiteral1.js +++ b/tests/baselines/reference/trailingCommaInHeterogenousArrayLiteral1.js @@ -17,7 +17,7 @@ var arrTest = (function () { }; arrTest.prototype.callTest = function () { // these two should give the same error - this.test([1, 2, "hi", 5, ]); + this.test([1, 2, "hi", 5,]); this.test([1, 2, "hi", 5]); }; return arrTest; diff --git a/tests/baselines/reference/trailingCommasES3.js b/tests/baselines/reference/trailingCommasES3.js index 56e30fe5c17..554390a83ea 100644 --- a/tests/baselines/reference/trailingCommasES3.js +++ b/tests/baselines/reference/trailingCommasES3.js @@ -18,8 +18,8 @@ var o2 = { a: 1, b: 2 }; var o3 = { a: 1 }; var o4 = {}; var a1 = [1, 2]; -var a2 = [1, 2, ]; -var a3 = [1, ]; +var a2 = [1, 2,]; +var a3 = [1,]; var a4 = []; -var a5 = [1, , ]; -var a6 = [, , ]; +var a5 = [1, ,]; +var a6 = [, ,]; diff --git a/tests/baselines/reference/trailingCommasES5.js b/tests/baselines/reference/trailingCommasES5.js index f342d9ac2d7..e54e911189a 100644 --- a/tests/baselines/reference/trailingCommasES5.js +++ b/tests/baselines/reference/trailingCommasES5.js @@ -14,12 +14,12 @@ var a6 = [, , ]; //// [trailingCommasES5.js] var o1 = { a: 1, b: 2 }; -var o2 = { a: 1, b: 2, }; -var o3 = { a: 1, }; +var o2 = { a: 1, b: 2, }; +var o3 = { a: 1, }; var o4 = {}; var a1 = [1, 2]; -var a2 = [1, 2, ]; -var a3 = [1, ]; +var a2 = [1, 2,]; +var a3 = [1,]; var a4 = []; -var a5 = [1, , ]; -var a6 = [, , ]; +var a5 = [1, ,]; +var a6 = [, ,]; diff --git a/tests/baselines/reference/unaryOperatorsInStrictMode.errors.txt b/tests/baselines/reference/unaryOperatorsInStrictMode.errors.txt new file mode 100644 index 00000000000..34fb760e320 --- /dev/null +++ b/tests/baselines/reference/unaryOperatorsInStrictMode.errors.txt @@ -0,0 +1,62 @@ +tests/cases/compiler/unaryOperatorsInStrictMode.ts(3,3): error TS1100: Invalid use of 'eval' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(4,3): error TS1100: Invalid use of 'eval' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(5,3): error TS1100: Invalid use of 'arguments' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(6,3): error TS1100: Invalid use of 'arguments' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(7,1): error TS1100: Invalid use of 'eval' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(8,1): error TS1100: Invalid use of 'eval' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(9,1): error TS1100: Invalid use of 'arguments' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(10,1): error TS1100: Invalid use of 'arguments' in strict mode. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(3,3): error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(4,3): error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(5,3): error TS2304: Cannot find name 'arguments'. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(6,3): error TS2304: Cannot find name 'arguments'. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(7,1): error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(8,1): error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(9,1): error TS2304: Cannot find name 'arguments'. +tests/cases/compiler/unaryOperatorsInStrictMode.ts(10,1): error TS2304: Cannot find name 'arguments'. + + +==== tests/cases/compiler/unaryOperatorsInStrictMode.ts (16 errors) ==== + "use strict" + + ++eval; + ~~~~ +!!! error TS1100: Invalid use of 'eval' in strict mode. + ~~~~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. + --eval; + ~~~~ +!!! error TS1100: Invalid use of 'eval' in strict mode. + ~~~~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. + ++arguments; + ~~~~~~~~~ +!!! error TS1100: Invalid use of 'arguments' in strict mode. + ~~~~~~~~~ +!!! error TS2304: Cannot find name 'arguments'. + --arguments; + ~~~~~~~~~ +!!! error TS1100: Invalid use of 'arguments' in strict mode. + ~~~~~~~~~ +!!! error TS2304: Cannot find name 'arguments'. + eval++; + ~~~~ +!!! error TS1100: Invalid use of 'eval' in strict mode. + ~~~~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. + eval--; + ~~~~ +!!! error TS1100: Invalid use of 'eval' in strict mode. + ~~~~ +!!! error TS2356: An arithmetic operand must be of type 'any', 'number' or an enum type. + arguments++; + ~~~~~~~~~ +!!! error TS1100: Invalid use of 'arguments' in strict mode. + ~~~~~~~~~ +!!! error TS2304: Cannot find name 'arguments'. + arguments--; + ~~~~~~~~~ +!!! error TS1100: Invalid use of 'arguments' in strict mode. + ~~~~~~~~~ +!!! error TS2304: Cannot find name 'arguments'. + \ No newline at end of file diff --git a/tests/cases/compiler/declarationEmit_protectedMembers.ts b/tests/cases/compiler/declarationEmit_protectedMembers.ts new file mode 100644 index 00000000000..8d40ecbe218 --- /dev/null +++ b/tests/cases/compiler/declarationEmit_protectedMembers.ts @@ -0,0 +1,52 @@ +// @declaration: true +// @target: es5 + +// Class with protected members +class C1 { + protected x: number; + + protected f() { + return this.x; + } + + protected set accessor(a: number) { } + protected get accessor() { return 0; } + + protected static sx: number; + + protected static sf() { + return this.sx; + } + + protected static set staticSetter(a: number) { } + protected static get staticGetter() { return 0; } +} + +// Derived class overriding protected members +class C2 extends C1 { + protected f() { + return super.f() + this.x; + } + protected static sf() { + return super.sf() + this.sx; + } +} + +// Derived class making protected members public +class C3 extends C2 { + x: number; + static sx: number; + f() { + return super.f(); + } + static sf() { + return super.sf(); + } + + static get staticGetter() { return 1; } +} + +// Protected properties in constructors +class C4 { + constructor(protected a: number, protected b) { } +} \ No newline at end of file diff --git a/tests/cases/compiler/deleteOperatorInStrictMode.ts b/tests/cases/compiler/deleteOperatorInStrictMode.ts new file mode 100644 index 00000000000..48fcd6535be --- /dev/null +++ b/tests/cases/compiler/deleteOperatorInStrictMode.ts @@ -0,0 +1,3 @@ +"use strict" +var a; +delete a; \ No newline at end of file diff --git a/tests/cases/compiler/errorHandlingInInstanceOf.ts b/tests/cases/compiler/errorHandlingInInstanceOf.ts new file mode 100644 index 00000000000..081a19837a7 --- /dev/null +++ b/tests/cases/compiler/errorHandlingInInstanceOf.ts @@ -0,0 +1,6 @@ +if (x instanceof String) { +} + +var y: any; +if (y instanceof UnknownType) { +} \ No newline at end of file diff --git a/tests/cases/compiler/unaryOperatorsInStrictMode.ts b/tests/cases/compiler/unaryOperatorsInStrictMode.ts new file mode 100644 index 00000000000..1114fd7b7a1 --- /dev/null +++ b/tests/cases/compiler/unaryOperatorsInStrictMode.ts @@ -0,0 +1,10 @@ +"use strict" + +++eval; +--eval; +++arguments; +--arguments; +eval++; +eval--; +arguments++; +arguments--; diff --git a/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility.ts b/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility.ts new file mode 100644 index 00000000000..91d235b06fd --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility.ts @@ -0,0 +1,25 @@ +class C1 { + constructor(public x: number) { } +} +var c1: C1; +c1.x // OK + + +class C2 { + constructor(private p: number) { } +} +var c2: C2; +c2.p // private, error + + +class C3 { + constructor(protected p: number) { } +} +var c3: C3; +c3.p // protected, error +class Derived extends C3 { + constructor(p: number) { + super(p); + this.p; // OK + } +} diff --git a/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility2.ts b/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility2.ts new file mode 100644 index 00000000000..2f5adca95b3 --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility2.ts @@ -0,0 +1,25 @@ +class C1 { + constructor(public x?: number) { } +} +var c1: C1; +c1.x // OK + + +class C2 { + constructor(private p?: number) { } +} +var c2: C2; +c2.p // private, error + + +class C3 { + constructor(protected p?: number) { } +} +var c3: C3; +c3.p // protected, error +class Derived extends C3 { + constructor(p: number) { + super(p); + this.p; // OK + } +} diff --git a/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility3.ts b/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility3.ts new file mode 100644 index 00000000000..427e3296d8c --- /dev/null +++ b/tests/cases/conformance/classes/constructorDeclarations/classConstructorParametersAccessibility3.ts @@ -0,0 +1,13 @@ +class Base { + constructor(protected p: number) { } +} + +class Derived extends Base { + constructor(public p: number) { + super(p); + this.p; // OK + } +} + +var d: Derived; +d.p; // public, OK \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts b/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts new file mode 100644 index 00000000000..0bc89667aba --- /dev/null +++ b/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass2.ts @@ -0,0 +1,94 @@ +class Base { + protected x: string; + method() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // OK, accessed within their declaring class + d1.x; // OK, accessed within their declaring class + d2.x; // OK, accessed within their declaring class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within their declaring class + } +} + +class Derived1 extends Base { + method1() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // Error, isn't accessed through an instance of the enclosing class + } +} + +class Derived2 extends Base { + method2() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class or one of its subclasses + } +} + +class Derived3 extends Derived1 { + protected x: string; + method3() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // OK, accessed within their declaring class + d4.x; // Error, isn't accessed through an instance of the enclosing class + } +} + +class Derived4 extends Derived2 { + method4() { + var b: Base; + var d1: Derived1; + var d2: Derived2; + var d3: Derived3; + var d4: Derived4; + + b.x; // Error, isn't accessed through an instance of the enclosing class + d1.x; // Error, isn't accessed through an instance of the enclosing class + d2.x; // Error, isn't accessed through an instance of the enclosing class + d3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + d4.x; // OK, accessed within a class derived from their declaring class, and through an instance of the enclosing class + } +} + + +var b: Base; +var d1: Derived1; +var d2: Derived2; +var d3: Derived3; +var d4: Derived4; + +b.x; // Error, neither within their declaring class nor classes derived from their declaring class +d1.x; // Error, neither within their declaring class nor classes derived from their declaring class +d2.x; // Error, neither within their declaring class nor classes derived from their declaring class +d3.x; // Error, neither within their declaring class nor classes derived from their declaring class +d4.x; // Error, neither within their declaring class nor classes derived from their declaring class \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass3.ts b/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass3.ts new file mode 100644 index 00000000000..36e97fe2dd3 --- /dev/null +++ b/tests/cases/conformance/classes/members/accessibility/protectedClassPropertyAccessibleWithinSubclass3.ts @@ -0,0 +1,13 @@ +class Base { + protected x: string; + method() { + this.x; // OK, accessed within their declaring class + } +} + +class Derived extends Base { + method1() { + this.x; // OK, accessed within a subclass of the declaring class + super.x; // Error, x is not public + } +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts b/tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts new file mode 100644 index 00000000000..a8fb3d7b63e --- /dev/null +++ b/tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass.ts @@ -0,0 +1,43 @@ +class Base { + protected static x: string; + static staticMethod() { + Base.x; // OK, accessed within their declaring class + Derived1.x; // OK, accessed within their declaring class + Derived2.x; // OK, accessed within their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + } +} + +class Derived1 extends Base { + static staticMethod1() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + } +} + +class Derived2 extends Base { + static staticMethod2() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // Error, redefined in a subclass, can only be accessed in the declaring class or one of its subclasses + } +} + +class Derived3 extends Derived1 { + protected static x: string; + static staticMethod3() { + Base.x; // OK, accessed within a class derived from their declaring class + Derived1.x; // OK, accessed within a class derived from their declaring class + Derived2.x; // OK, accessed within a class derived from their declaring class + Derived3.x; // OK, accessed within their declaring class + } +} + + +Base.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived1.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived2.x; // Error, neither within their declaring class nor classes derived from their declaring class +Derived3.x; // Error, neither within their declaring class nor classes derived from their declaring class \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass2.ts b/tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass2.ts new file mode 100644 index 00000000000..6de747ca1c4 --- /dev/null +++ b/tests/cases/conformance/classes/members/accessibility/protectedStaticClassPropertyAccessibleWithinSubclass2.ts @@ -0,0 +1,21 @@ +class Base { + protected static x: string; + static staticMethod() { + this.x; // OK, accessed within their declaring class + } +} + +class Derived1 extends Base { + static staticMethod1() { + this.x; // OK, accessed within a class derived from their declaring class + super.x; // Error, x is not public + } +} + +class Derived2 extends Derived1 { + protected static x: string; + static staticMethod3() { + this.x; // OK, accessed within a class derived from their declaring class + super.x; // Error, x is not public + } +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/accessibility/protectedStaticNotAccessibleInClodule.ts b/tests/cases/conformance/classes/members/accessibility/protectedStaticNotAccessibleInClodule.ts new file mode 100644 index 00000000000..10b1e586996 --- /dev/null +++ b/tests/cases/conformance/classes/members/accessibility/protectedStaticNotAccessibleInClodule.ts @@ -0,0 +1,11 @@ +// Any attempt to access a private property member outside the class body that contains its declaration results in a compile-time error. + +class C { + public static foo: string; + protected static bar: string; +} + +module C { + export var f = C.foo; // OK + export var b = C.bar; // error +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers.ts new file mode 100644 index 00000000000..76c03c73d63 --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers.ts @@ -0,0 +1,36 @@ +// @target: ES5 + +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + protected a: typeof x; + protected b(a: typeof x) { } + protected get c() { return x; } + protected set c(v: typeof x) { } + protected d: (a: typeof x) => void; + + protected static r: typeof x; + protected static s(a: typeof x) { } + protected static get t() { return x; } + protected static set t(v: typeof x) { } + protected static u: (a: typeof x) => void; + + constructor(a: typeof x) { } +} + +class Derived extends Base { + protected a: typeof y; + protected b(a: typeof y) { } + protected get c() { return y; } + protected set c(v: typeof y) { } + protected d: (a: typeof y) => void; + + protected static r: typeof y; + protected static s(a: typeof y) { } + protected static get t() { return y; } + protected static set t(a: typeof y) { } + protected static u: (a: typeof y) => void; + + constructor(a: typeof y) { super(x) } +} diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers2.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers2.ts new file mode 100644 index 00000000000..fb1955f1d95 --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers2.ts @@ -0,0 +1,63 @@ +// @target: ES5 +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + protected a: typeof x; + protected b(a: typeof x) { } + protected get c() { return x; } + protected set c(v: typeof x) { } + protected d: (a: typeof x) => void ; + + protected static r: typeof x; + protected static s(a: typeof x) { } + protected static get t() { return x; } + protected static set t(v: typeof x) { } + protected static u: (a: typeof x) => void ; + +constructor(a: typeof x) { } +} + +// Increase visibility of all protected members to public +class Derived extends Base { + a: typeof y; + b(a: typeof y) { } + get c() { return y; } + set c(v: typeof y) { } + d: (a: typeof y) => void; + + static r: typeof y; + static s(a: typeof y) { } + static get t() { return y; } + static set t(a: typeof y) { } + static u: (a: typeof y) => void; + + constructor(a: typeof y) { super(a); } +} + +var d: Derived = new Derived(y); +var r1 = d.a; +var r2 = d.b(y); +var r3 = d.c; +var r3a = d.d; +d.c = y; +var r4 = Derived.r; +var r5 = Derived.s(y); +var r6 = Derived.t; +var r6a = Derived.u; +Derived.t = y; + +class Base2 { + [i: string]: Object; + [i: number]: typeof x; +} + +class Derived2 extends Base2 { + [i: string]: typeof x; + [i: number]: typeof y; +} + +var d2: Derived2; +var r7 = d2['']; +var r8 = d2[1]; + diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts new file mode 100644 index 00000000000..d24e313c240 --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers3.ts @@ -0,0 +1,72 @@ +// @target: ES5 + +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + a: typeof x; + b(a: typeof x) { } + get c() { return x; } + set c(v: typeof x) { } + d: (a: typeof x) => void; + + static r: typeof x; + static s(a: typeof x) { } + static get t() { return x; } + static set t(v: typeof x) { } + static u: (a: typeof x) => void; + + constructor(a: typeof x) {} +} + +// Errors +// decrease visibility of all public members to protected +class Derived1 extends Base { + protected a: typeof x; + constructor(a: typeof x) { super(a); } +} + +class Derived2 extends Base { + protected b(a: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived3 extends Base { + protected get c() { return x; } + constructor(a: typeof x) { super(a); } +} + +class Derived4 extends Base { + protected set c(v: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived5 extends Base { + protected d: (a: typeof x) => void ; + constructor(a: typeof x) { super(a); } +} + +class Derived6 extends Base { + protected static r: typeof x; + constructor(a: typeof x) { super(a); } +} + +class Derived7 extends Base { + protected static s(a: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived8 extends Base { + protected static get t() { return x; } + constructor(a: typeof x) { super(a); } +} + +class Derived9 extends Base { + protected static set t(v: typeof x) { } + constructor(a: typeof x) { super(a); } +} + +class Derived10 extends Base { + protected static u: (a: typeof x) => void ; + constructor(a: typeof x) { super(a); } +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers4.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers4.ts new file mode 100644 index 00000000000..04061d8bcaa --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassOverridesProtectedMembers4.ts @@ -0,0 +1,14 @@ +var x: { foo: string; } +var y: { foo: string; bar: string; } + +class Base { + protected a: typeof x; +} + +class Derived1 extends Base { + public a: typeof x; +} + +class Derived2 extends Derived1 { + protected a: typeof x; // Error, parent was public +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassTransitivity4.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassTransitivity4.ts new file mode 100644 index 00000000000..3fa0cec4318 --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassTransitivity4.ts @@ -0,0 +1,20 @@ +// subclassing is not transitive when you can remove required parameters and add optional parameters on protected members + +class C { + protected foo(x: number) { } +} + +class D extends C { + protected foo() { } // ok to drop parameters +} + +class E extends D { + public foo(x?: string) { } // ok to add optional parameters +} + +var c: C; +var d: D; +var e: E; +c = e; +var r = c.foo(1); +var r2 = e.foo(''); \ No newline at end of file diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateInstanceShadowingProtectedInstance.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateInstanceShadowingProtectedInstance.ts new file mode 100644 index 00000000000..0ccee01875e --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateInstanceShadowingProtectedInstance.ts @@ -0,0 +1,22 @@ +// @target: ES5 + +class Base { + protected x: string; + protected fn(): string { + return ''; + } + + protected get a() { return 1; } + protected set a(v) { } +} + +// error, not a subtype +class Derived extends Base { + private x: string; + private fn(): string { + return ''; + } + + private get a() { return 1; } + private set a(v) { } +} diff --git a/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateStaticShadowingProtectedStatic.ts b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateStaticShadowingProtectedStatic.ts new file mode 100644 index 00000000000..a9ee037315f --- /dev/null +++ b/tests/cases/conformance/classes/members/inheritanceAndOverriding/derivedClassWithPrivateStaticShadowingProtectedStatic.ts @@ -0,0 +1,22 @@ +// @target: ES5 + +class Base { + protected static x: string; + protected static fn(): string { + return ''; + } + + protected static get a() { return 1; } + protected static set a(v) { } +} + +// should be error +class Derived extends Base { + private static x: string; + private static fn(): string { + return ''; + } + + private static get a() { return 1; } + private static set a(v) { } +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts new file mode 100644 index 00000000000..43d061f9cf6 --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/accessibilityModifiers.ts @@ -0,0 +1,45 @@ +// @target: ES5 + +// No errors +class C { + private static privateProperty; + private static privateMethod() { } + private static get privateGetter() { return 0; } + private static set privateSetter(a: number) { } + + protected static protectedProperty; + protected static protectedMethod() { } + protected static get protectedGetter() { return 0; } + protected static set protectedSetter(a: number) { } + + public static publicProperty; + public static publicMethod() { } + public static get publicGetter() { return 0; } + public static set publicSetter(a: number) { } +} + +// Errors, accessibility modifiers must precede static +class D { + static private privateProperty; + static private privateMethod() { } + static private get privateGetter() { return 0; } + static private set privateSetter(a: number) { } + + static protected protectedProperty; + static protected protectedMethod() { } + static protected get protectedGetter() { return 0; } + static protected set protectedSetter(a: number) { } + + static public publicProperty; + static public publicMethod() { } + static public get publicGetter() { return 0; } + static public set publicSetter(a: number) { } +} + +// Errors, multiple accessibility modifier +class E { + private public protected property; + public protected method() { } + private protected get getter() { return 0; } + public public set setter(a: number) { } +} diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts new file mode 100644 index 00000000000..53474743ab6 --- /dev/null +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/memberAccessorDeclarations/accessorWithMismatchedAccessibilityModifiers.ts @@ -0,0 +1,33 @@ +// @target: ES5 + +class C { + get x() { + return 1; + } + private set x(v) { + } +} + +class D { + protected get x() { + return 1; + } + private set x(v) { + } +} + +class E { + protected set x(v) { + } + get x() { + return 1; + } +} + +class F { + protected static set x(v) { + } + static get x() { + return 1; + } +} \ No newline at end of file diff --git a/tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts b/tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts index f7d41586546..293db09be14 100644 --- a/tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts +++ b/tests/cases/conformance/classes/propertyMemberDeclarations/memberFunctionDeclarations/memberFunctionsWithPublicPrivateOverloads.ts @@ -12,10 +12,19 @@ class C { public static foo(x: number, y: string); // error private static foo(x: any, y?: any) { } + protected baz(x: string); // error + protected baz(x: number, y: string); // error + private baz(x: any, y?: any) { } + private static bar(x: 'hi'); public static bar(x: string); // error private static bar(x: number, y: string); private static bar(x: any, y?: any) { } + + protected static baz(x: 'hi'); + public static baz(x: string); // error + protected static baz(x: number, y: string); + protected static baz(x: any, y?: any) { } } class D { @@ -28,6 +37,10 @@ class D { private bar(x: T, y: T); private bar(x: any, y?: any) { } + private baz(x: string); + protected baz(x: number, y: string); // error + private baz(x: any, y?: any) { } + private static foo(x: number); public static foo(x: number, y: string); // error private static foo(x: any, y?: any) { } @@ -36,6 +49,10 @@ class D { public static bar(x: string); // error private static bar(x: number, y: string); private static bar(x: any, y?: any) { } + + public static baz(x: string); // error + protected static baz(x: number, y: string); + protected static baz(x: any, y?: any) { } } var c: C; diff --git a/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts new file mode 100644 index 00000000000..87ae1739df3 --- /dev/null +++ b/tests/cases/conformance/interfaces/interfaceDeclarations/interfaceWithAccessibilityModifiers.ts @@ -0,0 +1,6 @@ +// Errors +interface Foo { + public a: any; + private b: any; + protected c: any; +} \ No newline at end of file diff --git a/tests/cases/conformance/types/members/classWithProtectedProperty.ts b/tests/cases/conformance/types/members/classWithProtectedProperty.ts new file mode 100644 index 00000000000..96bc615c020 --- /dev/null +++ b/tests/cases/conformance/types/members/classWithProtectedProperty.ts @@ -0,0 +1,27 @@ +// accessing any protected outside the class is an error + +class C { + protected x; + protected a = ''; + protected b: string = ''; + protected c() { return '' } + protected d = () => ''; + protected static e; + protected static f() { return '' } + protected static g = () => ''; +} + +class D extends C { + method() { + // No errors + var d = new D(); + var r1: string = d.x; + var r2: string = d.a; + var r3: string = d.b; + var r4: string = d.c(); + var r5: string = d.d(); + var r6: string = C.e; + var r7: string = C.f(); + var r8: string = C.g(); + } +} \ No newline at end of file diff --git a/tests/cases/fourslash/augmentedTypesModule2.ts b/tests/cases/fourslash/augmentedTypesModule2.ts new file mode 100644 index 00000000000..ca4d2db1423 --- /dev/null +++ b/tests/cases/fourslash/augmentedTypesModule2.ts @@ -0,0 +1,23 @@ +/// + +////function /*11*/m2f(x: number) { }; +////module m2f { export interface I { foo(): void } } +////var x: m2f./*1*/ +////var r/*2*/ = m2f/*3*/; + +//goTo.marker('11'); +//verify.quickInfoIs('(x: number): void'); + +//goTo.marker('1'); +//verify.completionListContains('I'); + +//edit.insert('I.'); +//verify.not.completionListContains('foo'); +//edit.backspace(1); + +//goTo.marker('2'); +//verify.quickInfoIs('typeof m2f'); + +goTo.marker('3'); +edit.insert('('); +verify.currentSignatureHelpIs('m2f(x: number): void'); diff --git a/tests/cases/fourslash/augmentedTypesModule3.ts b/tests/cases/fourslash/augmentedTypesModule3.ts new file mode 100644 index 00000000000..08d0b241ef1 --- /dev/null +++ b/tests/cases/fourslash/augmentedTypesModule3.ts @@ -0,0 +1,20 @@ +/// + +////function m2g() { }; +////module m2g { export class C { foo(x: number) { } } } +////var x: m2g./*1*/; +////var r/*2*/ = m2g/*3*/; + +//goTo.marker('1'); +//verify.completionListContains('C'); + +//edit.insert('C.'); +//verify.not.completionListContains('foo'); +//edit.backspace(1); + +//goTo.marker('2'); +//verify.quickInfoIs("typeof m2g", undefined, "r", "var"); + +goTo.marker('3'); +edit.insert('('); +verify.currentSignatureHelpIs('m2g(): void'); \ No newline at end of file diff --git a/tests/cases/fourslash/augmentedTypesModule6.ts b/tests/cases/fourslash/augmentedTypesModule6.ts new file mode 100644 index 00000000000..f7e71c4a685 --- /dev/null +++ b/tests/cases/fourslash/augmentedTypesModule6.ts @@ -0,0 +1,34 @@ +/// + +////declare class m3f { foo(x: number): void } +////module m3f { export interface I { foo(): void } } +////var x: m3f./*1*/ +////var r/*4*/ = new /*2*/m3f(/*3*/); +////r./*5*/ +////var r2: m3f.I = r; +////r2./*6*/ + +//goTo.marker('1'); +//verify.completionListContains('I'); + +//verify.not.completionListContains('foo'); +//edit.insert('I;'); + +//goTo.marker('2'); +//verify.completionListContains('m3f'); + +goTo.marker('3'); +verify.currentSignatureHelpIs('m3f(): m3f'); + +//goTo.marker('4'); +//verify.quickInfoIs('m3f'); + +//goTo.marker('5'); +//verify.completionListContains('foo'); +//edit.insert('foo(1)'); + +goTo.marker('6'); +//verify.completionListContains('foo'); +edit.insert('foo('); +// verify.currentSignatureHelpIs('foo(): void'); + diff --git a/tests/cases/fourslash/callSignatureHelp.ts b/tests/cases/fourslash/callSignatureHelp.ts new file mode 100644 index 00000000000..4e813dd17c4 --- /dev/null +++ b/tests/cases/fourslash/callSignatureHelp.ts @@ -0,0 +1,10 @@ +/// + +////interface C { +//// (): number; +////} +////var c: C; +////c(/**/ + +goTo.marker(); +verify.currentSignatureHelpIs('c(): number'); \ No newline at end of file diff --git a/tests/cases/fourslash/classExtendsInterfaceSigHelp1.ts b/tests/cases/fourslash/classExtendsInterfaceSigHelp1.ts new file mode 100644 index 00000000000..ebdccef485f --- /dev/null +++ b/tests/cases/fourslash/classExtendsInterfaceSigHelp1.ts @@ -0,0 +1,18 @@ +/// + +////class C { +//// public foo(x: string); +//// public foo(x: number); +//// public foo(x: any) { return x; } +////} + +////interface I extends C { +//// other(x: any): any; +////} + +////var i: I; +////i.foo(/**/ + +goTo.marker(); +verify.signatureHelpCountIs(2); +verify.currentParameterSpanIs('x: string'); \ No newline at end of file diff --git a/tests/cases/fourslash/externalModuleWithExportAssignment.ts b/tests/cases/fourslash/externalModuleWithExportAssignment.ts new file mode 100644 index 00000000000..0a5da79aad6 --- /dev/null +++ b/tests/cases/fourslash/externalModuleWithExportAssignment.ts @@ -0,0 +1,87 @@ +/// + +// @Filename: externalModuleWithExportAssignment_file0.ts +////module m2 { +//// export interface connectModule { +//// (res, req, next): void; +//// } +//// export interface connectExport { +//// use: (mod: connectModule) => connectExport; +//// listen: (port: number) => void; +//// } +////} +////var m2: { +//// (): m2.connectExport; +//// test1: m2.connectModule; +//// test2(): m2.connectModule; +////}; +////export = m2; + +// @Filename: externalModuleWithExportAssignment_file1.ts +////import /*1*/a1 = require("externalModuleWithExportAssignment_file0"); +////export var /*2*/a = a1; +////a./*3*/test1(/*4*/null, null, null); +////var /*6*/r1 = a.test2(/*5*/); +////var /*8*/r2 = a(/*7*/); +////a1./*9*/test1(/*10*/null, null, null); +////var /*12*/r3 = a1.test2(/*11*/); +////var /*14*/r4 = a1(/*13*/); +////var v1: a1./*15*/connectExport; + +//goTo.file("externalModuleWithExportAssignment_file1.ts"); +//goTo.marker('1'); +//verify.quickInfoIs("a1"); + +//goTo.marker('2'); +//verify.quickInfoIs("{ test1: a1.connectModule; test2(): a1.connectModule; (): a1.connectExport; }", undefined, "a", "var"); + +//goTo.marker('3'); +//verify.quickInfoIs("(res: any, req: any, next: any): void", undefined, "a1.connectModule", "function"); +//verify.completionListContains("test1", "a1.connectModule", undefined, "test1", "property"); +//verify.completionListContains("test2", "(): a1.connectModule", undefined, "test2", "method"); +//verify.not.completionListContains("connectModule"); +//verify.not.completionListContains("connectExport"); + +goTo.marker('4'); +verify.currentSignatureHelpIs("test1(res: any, req: any, next: any): void"); + +goTo.marker('5'); +verify.currentSignatureHelpIs("test2(): a1.connectModule"); + +//goTo.marker('6'); +//verify.quickInfoIs("a1.connectModule", undefined, "r1", "var"); + +goTo.marker('7'); +verify.currentSignatureHelpIs("a(): a1.connectExport"); + +//goTo.marker('8'); +//verify.quickInfoIs("a1.connectExport", undefined, "r2", "var"); + +//goTo.marker('9'); +//verify.quickInfoIs("(res: any, req: any, next: any): void", undefined, "a1.connectModule", "function"); +//verify.completionListContains("test1", "a1.connectModule", undefined, "test1", "property"); +//verify.completionListContains("test2", "(): a1.connectModule", undefined, "test2", "method"); +//verify.not.completionListContains("connectModule"); +//verify.not.completionListContains("connectExport"); + +goTo.marker('10'); +verify.currentSignatureHelpIs("test1(res: any, req: any, next: any): void"); + +goTo.marker('11'); +verify.currentSignatureHelpIs("test2(): a1.connectModule"); + +//goTo.marker('12'); +//verify.quickInfoIs("a1.connectModule", undefined, "r3", "var"); + +goTo.marker('13'); +verify.currentSignatureHelpIs("a1(): a1.connectExport"); + +//goTo.marker('14'); +//verify.quickInfoIs("a1.connectExport", undefined, "r4", "var"); + +//goTo.marker('15'); +//verify.not.completionListContains("test1", "a1.connectModule", undefined, "test1", "property"); +//verify.not.completionListContains("test2", "(): a1.connectModule", undefined, "test2", "method"); +//verify.completionListContains("connectModule", "a1.connectModule", undefined, "a1.connectModule", "interface"); +//verify.completionListContains("connectExport", "a1.connectExport", undefined, "a1.connectExport", "interface"); + diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index f9476ee4d92..35b6894b1ce 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -201,6 +201,7 @@ module FourSlashInterface { FourSlash.currentTestState.verifyImplementorsCountIs(count); } + // Add tests for this. public currentParameterIsVariable() { FourSlash.currentTestState.verifyCurrentParameterIsVariable(!this.negative); } @@ -282,11 +283,11 @@ module FourSlashInterface { } public currentParameterHelpArgumentDocCommentIs(docComment: string) { - FourSlash.currentTestState.verifyCurrentParameterHelpDocComment(docComment); + // FourSlash.currentTestState.verifyCurrentParameterHelpDocComment(docComment); } public currentSignatureHelpDocCommentIs(docComment: string) { - FourSlash.currentTestState.verifyCurrentSignatureHelpDocComment(docComment); + // FourSlash.currentTestState.verifyCurrentSignatureHelpDocComment(docComment); } public signatureHelpCountIs(expected: number) { diff --git a/tests/cases/fourslash/functionOverloadCount.ts b/tests/cases/fourslash/functionOverloadCount.ts new file mode 100644 index 00000000000..00856dcb24a --- /dev/null +++ b/tests/cases/fourslash/functionOverloadCount.ts @@ -0,0 +1,15 @@ +/// + +////class C1 { +//// public attr(): string; +//// public attr(i: number): string; +//// public attr(i: number, x: boolean): string; +//// public attr(i?: any, x?: any) { +//// return "hi"; +//// } +////} +////var i = new C1; +////i.attr(/*1*/ + +goTo.marker('1'); +verify.signatureHelpCountIs(3); \ No newline at end of file diff --git a/tests/cases/fourslash/functionProperty.ts b/tests/cases/fourslash/functionProperty.ts new file mode 100644 index 00000000000..4f089d95cf3 --- /dev/null +++ b/tests/cases/fourslash/functionProperty.ts @@ -0,0 +1,49 @@ +/// + +////var a = { +//// x(a: number) { } +////}; +//// +////var b = { +//// x: function (a: number) { } +////}; +//// +////var c = { +//// x: (a: number) => { } +////}; +////a.x(/*signatureA*/1); +////b.x(/*signatureB*/1); +////c.x(/*signatureC*/1); +////a./*completionA*/; +////b./*completionB*/; +////c./*completionC*/; +////a./*quickInfoA*/x; +////b./*quickInfoB*/x; +////c./*quickInfoC*/x; + +goTo.marker('signatureA'); +verify.currentSignatureHelpIs('x(a: number): void'); + +goTo.marker('signatureB'); +verify.currentSignatureHelpIs('x(a: number): void'); + +goTo.marker('signatureC'); +verify.currentSignatureHelpIs('x(a: number): void'); + +//goTo.marker('completionA'); +//verify.completionListContains("x", "(a: number): void"); + +//goTo.marker('completionB'); +//verify.completionListContains("x", "(a: number) => void"); + +//goTo.marker('completionC'); +//verify.completionListContains("x", "(a: number) => void"); + +//goTo.marker('quickInfoA'); +//verify.quickInfoIs("(a: number): void", undefined, "x", "local function"); + +//goTo.marker('quickInfoB'); +//verify.quickInfoIs("(a: number) => void", undefined, "x", "property"); + +//goTo.marker('quickInfoC'); +//verify.quickInfoIs("(a: number) => void", undefined, "x", "property"); \ No newline at end of file diff --git a/tests/cases/fourslash/genericFunctionReturnType.ts b/tests/cases/fourslash/genericFunctionReturnType.ts new file mode 100644 index 00000000000..3be60777b1f --- /dev/null +++ b/tests/cases/fourslash/genericFunctionReturnType.ts @@ -0,0 +1,21 @@ +/// + +////function foo(x: T, y: U): (a: U) => T { +//// var z = y; +//// return (z) => x; +////} + +////var r/*2*/ = foo(/*1*/1, ""); +////var r2/*4*/ = r(/*3*/""); + +// goTo.marker('1'); +// verify.currentSignatureHelpIs('foo(x: number, y: string): (a: string) => number'); + +//goTo.marker('2'); +//verify.quickInfoIs('(a: string) => number'); + +goTo.marker('3'); +verify.currentSignatureHelpIs('r(a: string): number'); + +//goTo.marker('4'); +//verify.quickInfoIs('number'); \ No newline at end of file diff --git a/tests/cases/fourslash/genericFunctionReturnType2.ts b/tests/cases/fourslash/genericFunctionReturnType2.ts new file mode 100644 index 00000000000..35b4b0af32d --- /dev/null +++ b/tests/cases/fourslash/genericFunctionReturnType2.ts @@ -0,0 +1,24 @@ +/// + +////class C { +//// constructor(x: T) { } +//// foo(x: T) { +//// return (a: T) => x; +//// } +////} + +////var x = new C(1); +////var r/*2*/ = x.foo(/*1*/3); +////var r2/*4*/ = r(/*3*/4); + +goTo.marker('1'); +verify.currentSignatureHelpIs('foo(x: number): (a: number) => number'); + +//goTo.marker('2'); +//verify.quickInfoIs('(a: number) => number'); + +goTo.marker('3'); +verify.currentSignatureHelpIs('r(a: number): number'); + +//goTo.marker('4'); +//verify.quickInfoIs('number'); \ No newline at end of file diff --git a/tests/cases/fourslash/genericFunctionSignatureHelp1.ts b/tests/cases/fourslash/genericFunctionSignatureHelp1.ts new file mode 100644 index 00000000000..fc1e45d7e6b --- /dev/null +++ b/tests/cases/fourslash/genericFunctionSignatureHelp1.ts @@ -0,0 +1,7 @@ +/// + +////function f(a: T): T { return null; } +////f(/**/ + +goTo.marker(); +verify.currentSignatureHelpIs('f(a: T): T'); diff --git a/tests/cases/fourslash/genericFunctionSignatureHelp2.ts b/tests/cases/fourslash/genericFunctionSignatureHelp2.ts new file mode 100644 index 00000000000..77511677588 --- /dev/null +++ b/tests/cases/fourslash/genericFunctionSignatureHelp2.ts @@ -0,0 +1,7 @@ +/// + +////var f = (a: T) => a; +////f(/**/ + +goTo.marker(); +verify.currentSignatureHelpIs('f(a: T): T'); diff --git a/tests/cases/fourslash/genericFunctionSignatureHelp3.ts b/tests/cases/fourslash/genericFunctionSignatureHelp3.ts new file mode 100644 index 00000000000..c5a5f62a0a9 --- /dev/null +++ b/tests/cases/fourslash/genericFunctionSignatureHelp3.ts @@ -0,0 +1,39 @@ +/// + +////function foo1(x: number, callback: (y1: T) => number) { } +////function foo2(x: number, callback: (y2: T) => number) { } +////function foo3(x: number, callback: (y3: T) => number) { } +////function foo4(x: number, callback: (y4: T) => number) { } +////function foo5(x: number, callback: (y5: T) => number) { } +////function foo6(x: number, callback: (y6: T) => number) { } +////function foo7(x: number, callback: (y7: T) => number) { } +//// IDE shows the results on the right of each line, fourslash says different +////foo1(/*1*/ // signature help shows y as T +////foo2(1,/*2*/ // signature help shows y as {} +////foo3(1, (/*3*/ // signature help shows y as T +////foo4(1,/*4*/ // signature help shows y as string +////foo5(1, (/*5*/ // signature help shows y as T +////foo6(1, (/*7*/ // signature help shows y as T + +goTo.marker('1'); +verify.currentSignatureHelpIs('foo1(x: number, callback: (y1: T) => number): void'); + +// goTo.marker('2'); +// verify.currentSignatureHelpIs('foo2(x: number, callback: (y2: {}) => number): void'); + +goTo.marker('3'); +verify.currentSignatureHelpIs('foo3(x: number, callback: (y3: T) => number): void'); + +// goTo.marker('4'); +// verify.currentSignatureHelpIs('foo4(x: number, callback: (y4: string) => number): void'); + +goTo.marker('5'); +verify.currentSignatureHelpIs('foo5(x: number, callback: (y5: T) => number): void'); + +goTo.marker('6'); +// verify.currentSignatureHelpIs('foo6(x: number, callback: (y6: {}) => number): void'); +edit.insert('string>(null,null);'); // need to make this line parse so we can get reasonable LS answers to later tests + +goTo.marker('7'); +verify.currentSignatureHelpIs('foo7(x: number, callback: (y7: T) => number): void'); diff --git a/tests/cases/fourslash/genericFunctionSignatureHelp3MultiFile.ts b/tests/cases/fourslash/genericFunctionSignatureHelp3MultiFile.ts new file mode 100644 index 00000000000..6eadb92f47d --- /dev/null +++ b/tests/cases/fourslash/genericFunctionSignatureHelp3MultiFile.ts @@ -0,0 +1,46 @@ +/// + +// @Filename: genericFunctionSignatureHelp_0.ts +////function foo1(x: number, callback: (y1: T) => number) { } +// @Filename: genericFunctionSignatureHelp_1.ts +////function foo2(x: number, callback: (y2: T) => number) { } +// @Filename: genericFunctionSignatureHelp_2.ts +////function foo3(x: number, callback: (y3: T) => number) { } +// @Filename: genericFunctionSignatureHelp_3.ts +////function foo4(x: number, callback: (y4: T) => number) { } +// @Filename: genericFunctionSignatureHelp_4.ts +////function foo5(x: number, callback: (y5: T) => number) { } +// @Filename: genericFunctionSignatureHelp_5.ts +////function foo6(x: number, callback: (y6: T) => number) { } +// @Filename: genericFunctionSignatureHelp_6.ts +////function foo7(x: number, callback: (y7: T) => number) { } +// @Filename: genericFunctionSignatureHelp_7.ts +////foo1(/*1*/ // signature help shows y as T +////foo2(1,/*2*/ // signature help shows y as {} +////foo3(1, (/*3*/ // signature help shows y as T +////foo4(1,/*4*/ // signature help shows y as string +////foo5(1, (/*5*/ // signature help shows y as T +////foo6(1, (/*7*/ // signature help shows y as T + +goTo.marker('1'); +verify.currentSignatureHelpIs('foo1(x: number, callback: (y1: T) => number): void'); + +// goTo.marker('2'); +// verify.currentSignatureHelpIs('foo2(x: number, callback: (y2: {}) => number): void'); + +goTo.marker('3'); +verify.currentSignatureHelpIs('foo3(x: number, callback: (y3: T) => number): void'); + +// goTo.marker('4'); +// verify.currentSignatureHelpIs('foo4(x: number, callback: (y4: string) => number): void'); + +goTo.marker('5'); +verify.currentSignatureHelpIs('foo5(x: number, callback: (y5: T) => number): void'); + +goTo.marker('6'); +// verify.currentSignatureHelpIs('foo6(x: number, callback: (y6: {}) => number): void'); +edit.insert('string>(null,null);'); // need to make this line parse so we can get reasonable LS answers to later tests + +goTo.marker('7'); +verify.currentSignatureHelpIs('foo7(x: number, callback: (y7: T) => number): void'); diff --git a/tests/cases/fourslash/genericParameterHelp.ts b/tests/cases/fourslash/genericParameterHelp.ts index e5a6385c179..a1df1cc2f32 100644 --- a/tests/cases/fourslash/genericParameterHelp.ts +++ b/tests/cases/fourslash/genericParameterHelp.ts @@ -27,67 +27,67 @@ ////class Bar extends testClass; -goTo.marker("1"); -// verify.currentSignatureParamterCountIs(3); -// verify.currentSignatureHelpIs("testFunction(a: T, b: U, c: M): M"); +// goTo.marker("1"); +// verify.currentSignatureParamterCountIs(3); +// verify.currentSignatureHelpIs("testFunction(a: T, b: U, c: M): M"); -// verify.currentParameterHelpArgumentNameIs("T"); -// verify.currentParameterSpanIs("T extends IFoo"); +// verify.currentParameterHelpArgumentNameIs("T"); +// verify.currentParameterSpanIs("T extends IFoo"); -// goTo.marker("2"); -// verify.currentParameterHelpArgumentNameIs("U"); -// verify.currentParameterSpanIs("U"); +// goTo.marker("2"); +// verify.currentParameterHelpArgumentNameIs("U"); +// verify.currentParameterSpanIs("U"); -// goTo.marker("3"); -// verify.currentParameterHelpArgumentNameIs("a"); -// verify.currentParameterSpanIs("a: T"); + goTo.marker("3"); + verify.currentParameterHelpArgumentNameIs("a"); + verify.currentParameterSpanIs("a: T"); -// goTo.marker("4"); -// verify.currentParameterHelpArgumentNameIs("M"); -// verify.currentParameterSpanIs("M extends IFoo"); + // goTo.marker("4"); + // verify.currentParameterHelpArgumentNameIs("M"); + // verify.currentParameterSpanIs("M extends IFoo"); -// goTo.marker("5"); -// verify.currentParameterHelpArgumentNameIs("M"); -// verify.currentParameterSpanIs("M extends IFoo"); + // goTo.marker("5"); + // verify.currentParameterHelpArgumentNameIs("M"); + // verify.currentParameterSpanIs("M extends IFoo"); -// goTo.marker("construcor1"); -// verify.currentSignatureHelpIs("testClass(a: T, b: U, c: M): testClass"); -// verify.currentParameterHelpArgumentNameIs("T"); -// verify.currentParameterSpanIs("T extends IFoo"); + // goTo.marker("construcor1"); + // verify.currentSignatureHelpIs("testClass(a: T, b: U, c: M): testClass"); + // verify.currentParameterHelpArgumentNameIs("T"); + // verify.currentParameterSpanIs("T extends IFoo"); -// goTo.marker("construcor2"); -// verify.currentParameterHelpArgumentNameIs("U"); -// verify.currentParameterSpanIs("U"); + // goTo.marker("construcor2"); + // verify.currentParameterHelpArgumentNameIs("U"); + // verify.currentParameterSpanIs("U"); -// goTo.marker("construcor3"); -// verify.currentParameterHelpArgumentNameIs("T"); -// verify.currentParameterSpanIs("T extends IFoo"); + //goTo.marker("construcor3"); + //verify.currentParameterHelpArgumentNameIs("T"); + //verify.currentParameterSpanIs("T extends IFoo"); -// goTo.marker("construcor4"); -// verify.currentParameterHelpArgumentNameIs("M"); -// verify.currentParameterSpanIs("M extends IFoo"); + // goTo.marker("construcor4"); + // verify.currentParameterHelpArgumentNameIs("M"); + // verify.currentParameterSpanIs("M extends IFoo"); -// goTo.marker("construcor5"); -// verify.currentParameterHelpArgumentNameIs("U"); -// verify.currentParameterSpanIs("U"); + // goTo.marker("construcor5"); + // verify.currentParameterHelpArgumentNameIs("U"); + // verify.currentParameterSpanIs("U"); -// goTo.marker("type1"); -// verify.signatureHelpCountIs(1); -// verify.currentSignatureHelpIs("testClass"); -// verify.currentParameterHelpArgumentNameIs("T"); -// verify.currentParameterSpanIs("T extends IFoo"); + // goTo.marker("type1"); + // verify.signatureHelpCountIs(1); + // verify.currentSignatureHelpIs("testClass"); + // verify.currentParameterHelpArgumentNameIs("T"); + // verify.currentParameterSpanIs("T extends IFoo"); -// goTo.marker("type2"); -// verify.signatureHelpCountIs(1); -// verify.currentParameterHelpArgumentNameIs("T"); -// verify.currentParameterSpanIs("T extends IFoo"); + // goTo.marker("type2"); + // verify.signatureHelpCountIs(1); + // verify.currentParameterHelpArgumentNameIs("T"); + // verify.currentParameterSpanIs("T extends IFoo"); -// goTo.marker("type3"); -// verify.signatureHelpCountIs(1); -// verify.currentParameterHelpArgumentNameIs("T"); -// verify.currentParameterSpanIs("T extends IFoo"); + // goTo.marker("type3"); + // verify.signatureHelpCountIs(1); + // verify.currentParameterHelpArgumentNameIs("T"); + // verify.currentParameterSpanIs("T extends IFoo"); -// goTo.marker("type4"); -// verify.signatureHelpCountIs(1); -// verify.currentParameterHelpArgumentNameIs("M"); -// verify.currentParameterSpanIs("M extends IFoo"); \ No newline at end of file + // goTo.marker("type4"); + // verify.signatureHelpCountIs(1); + // verify.currentParameterHelpArgumentNameIs("M"); + // verify.currentParameterSpanIs("M extends IFoo"); \ No newline at end of file diff --git a/tests/cases/fourslash_old/getMatchingBraces.ts b/tests/cases/fourslash/getMatchingBraces.ts similarity index 79% rename from tests/cases/fourslash_old/getMatchingBraces.ts rename to tests/cases/fourslash/getMatchingBraces.ts index 13d5effa15f..fc8a71197db 100644 --- a/tests/cases/fourslash_old/getMatchingBraces.ts +++ b/tests/cases/fourslash/getMatchingBraces.ts @@ -38,6 +38,6 @@ ////} test.ranges().forEach((range) => { - verify.matchingBracePositionInCurrentFile(range.start, range.end - 1); - verify.matchingBracePositionInCurrentFile(range.end - 1, range.start); - }); \ No newline at end of file + verify.matchingBracePositionInCurrentFile(range.start, range.end - 1); + verify.matchingBracePositionInCurrentFile(range.end - 1, range.start); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getMatchingBracesAdjacentBraces.ts b/tests/cases/fourslash/getMatchingBracesAdjacentBraces.ts new file mode 100644 index 00000000000..8dd997ebe73 --- /dev/null +++ b/tests/cases/fourslash/getMatchingBracesAdjacentBraces.ts @@ -0,0 +1,9 @@ +////function f[||][|(x: T)|][|{ +//// return x; +////}|] + +// If there is an adjacent opening and closing brace, +// then only the opening brace should get highlighted. +test.ranges().forEach(range => { + verify.matchingBracePositionInCurrentFile(range.start, range.end - 1); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/incrementalEditInvocationExpressionAboveInterfaceDeclaration.ts b/tests/cases/fourslash/incrementalEditInvocationExpressionAboveInterfaceDeclaration.ts new file mode 100644 index 00000000000..8a06efbaa44 --- /dev/null +++ b/tests/cases/fourslash/incrementalEditInvocationExpressionAboveInterfaceDeclaration.ts @@ -0,0 +1,17 @@ +/// + +////declare function alert(message?: any): void; +/////*1*/ +////interface Foo { +//// setISO8601(dString): Date; +////} + +diagnostics.setEditValidation(IncrementalEditValidation.None); + +// Do resolve without typeCheck +goTo.marker('1'); +edit.insert("alert("); +verify.currentSignatureHelpIs("alert(message?: any): void"); + +// TypeCheck +verify.errorExistsAfterMarker('1'); diff --git a/tests/cases/fourslash/overloadOnConstCallSignature.ts b/tests/cases/fourslash/overloadOnConstCallSignature.ts new file mode 100644 index 00000000000..757e96f162b --- /dev/null +++ b/tests/cases/fourslash/overloadOnConstCallSignature.ts @@ -0,0 +1,18 @@ +/// + +////var foo: { +//// (name: string): string; +//// (name: 'order'): string; +//// (name: 'content'): string; +//// (name: 'done'): string; +////} + +////var x/*2*/ = foo(/*1*/ + +goTo.marker('1'); +verify.signatureHelpCountIs(4); +verify.currentSignatureHelpIs('foo(name: string): string'); +edit.insert('"hi"'); + +//goTo.marker('2'); +//verify.quickInfoIs('string'); \ No newline at end of file diff --git a/tests/cases/fourslash/paramHelpOnCommaInString.ts b/tests/cases/fourslash/paramHelpOnCommaInString.ts new file mode 100644 index 00000000000..00271781582 --- /dev/null +++ b/tests/cases/fourslash/paramHelpOnCommaInString.ts @@ -0,0 +1,11 @@ +/// + +////function blah(foo: string, bar: number) { +////} +////blah('hola/*1*/,/*2*/') + +// making sure the comma in a string literal doesn't trigger param help on the second function param +goTo.marker('1'); +verify.currentParameterHelpArgumentNameIs('foo'); +goTo.marker('2'); +verify.currentParameterHelpArgumentNameIs('foo'); \ No newline at end of file diff --git a/tests/cases/fourslash/parameterInfoOnParameterType.ts b/tests/cases/fourslash/parameterInfoOnParameterType.ts new file mode 100644 index 00000000000..d28e675e24f --- /dev/null +++ b/tests/cases/fourslash/parameterInfoOnParameterType.ts @@ -0,0 +1,11 @@ +/// + +////function foo(a: string) { }; +////var b = "test"; +////foo("test"/*1*/); +////foo(b/*2*/); + +goTo.marker("1"); +verify.currentParameterHelpArgumentNameIs("a"); +goTo.marker("2"); +verify.currentParameterHelpArgumentNameIs("a"); \ No newline at end of file diff --git a/tests/cases/fourslash/qualifyModuleTypeNames.ts b/tests/cases/fourslash/qualifyModuleTypeNames.ts new file mode 100644 index 00000000000..50a9f6c85f0 --- /dev/null +++ b/tests/cases/fourslash/qualifyModuleTypeNames.ts @@ -0,0 +1,8 @@ +/// + +////module m { export class c { } }; +////function x(arg: m.c) { return arg; } +////x(/**/ + +goTo.marker(); +verify.currentSignatureHelpIs('x(arg: m.c): m.c'); diff --git a/tests/cases/fourslash/quickInfoInFunctionTypeReference2.ts b/tests/cases/fourslash/quickInfoInFunctionTypeReference2.ts new file mode 100644 index 00000000000..608dbba56c3 --- /dev/null +++ b/tests/cases/fourslash/quickInfoInFunctionTypeReference2.ts @@ -0,0 +1,18 @@ +/// + +////class C { +//// map(fn: (k/*1*/: string, value/*2*/: T, context: any) => void, context: any) { +//// } +////} + +////var c: C; +////c.map(/*3*/ + +//goTo.marker('1'); +//verify.quickInfoIs('string'); + +//goTo.marker('2'); +//verify.quickInfoIs('T'); + +goTo.marker('3'); +verify.currentSignatureHelpIs('map(fn: (k: string, value: number, context: any) => void, context: any): void'); \ No newline at end of file diff --git a/tests/cases/fourslash/quickInfoOnConstructorWithGenericParameter.ts b/tests/cases/fourslash/quickInfoOnConstructorWithGenericParameter.ts new file mode 100644 index 00000000000..056ba5300c7 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOnConstructorWithGenericParameter.ts @@ -0,0 +1,29 @@ +/// + +////interface I { +//// x: number; +////} +////class Foo { +//// y: T; +////} +////class A { +//// foo() { } +////} +////class B extends A { +//// constructor(a: Foo, b: number) { +//// super(); +//// } +////} +////var x = new /*2*/B(/*1*/ + +// this line triggers a semantic/syntactic error check, remove line when 788570 is fixed +edit.insert(''); + +goTo.marker("1"); +verify.currentSignatureHelpIs("B(a: Foo, b: number): B"); +edit.insert("null,"); +verify.currentSignatureHelpIs("B(a: Foo, b: number): B"); +edit.insert("10);"); + +//goTo.marker("2"); +//verify.quickInfoIs("(a: Foo, b: number): B", undefined, "B", "constructor"); \ No newline at end of file diff --git a/tests/cases/fourslash/restArgSignatureHelp.ts b/tests/cases/fourslash/restArgSignatureHelp.ts new file mode 100644 index 00000000000..baa8702a5f6 --- /dev/null +++ b/tests/cases/fourslash/restArgSignatureHelp.ts @@ -0,0 +1,7 @@ +/// + +////function f(...x: any[]) { } +////f(/**/); + +goTo.marker(); +verify.currentParameterHelpArgumentNameIs('x'); diff --git a/tests/cases/fourslash/signatureHelpAnonymousFunction.ts b/tests/cases/fourslash/signatureHelpAnonymousFunction.ts new file mode 100644 index 00000000000..cc723c713d6 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpAnonymousFunction.ts @@ -0,0 +1,17 @@ +/// + +////var anonymousFunctionTest = function(n: number, s: string): (a: number, b: string) => string { +//// return null; +////} +////anonymousFunctionTest(5, "")(/*anonymousFunction1*/1, /*anonymousFunction2*/""); + +goTo.marker('anonymousFunction1'); +verify.signatureHelpCountIs(1); +verify.currentSignatureParamterCountIs(2); +verify.currentSignatureHelpIs('(a: number, b: string): string'); +verify.currentParameterHelpArgumentNameIs("a"); +verify.currentParameterSpanIs("a: number"); + +goTo.marker('anonymousFunction2'); +verify.currentParameterHelpArgumentNameIs("b"); +verify.currentParameterSpanIs("b: string"); diff --git a/tests/cases/fourslash/signatureHelpAtEOF.ts b/tests/cases/fourslash/signatureHelpAtEOF.ts new file mode 100644 index 00000000000..64c4aaeeb2c --- /dev/null +++ b/tests/cases/fourslash/signatureHelpAtEOF.ts @@ -0,0 +1,15 @@ +/// + +////function Foo(arg1: string, arg2: string) { +////} +//// +////Foo(/**/ + +goTo.marker(); +verify.signatureHelpPresent(); +verify.signatureHelpCountIs(1); + +verify.currentSignatureHelpIs("Foo(arg1: string, arg2: string): void"); +verify.currentSignatureParamterCountIs(2); +verify.currentParameterHelpArgumentNameIs("arg1"); +verify.currentParameterSpanIs("arg1: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpBeforeSemicolon1.ts b/tests/cases/fourslash/signatureHelpBeforeSemicolon1.ts new file mode 100644 index 00000000000..2b0b07056bf --- /dev/null +++ b/tests/cases/fourslash/signatureHelpBeforeSemicolon1.ts @@ -0,0 +1,15 @@ +/// + +////function Foo(arg1: string, arg2: string) { +////} +//// +////Foo(/**/; + +goTo.marker(); +verify.signatureHelpPresent(); +verify.signatureHelpCountIs(1); + +verify.currentSignatureHelpIs("Foo(arg1: string, arg2: string): void"); +verify.currentSignatureParamterCountIs(2); +verify.currentParameterHelpArgumentNameIs("arg1"); +verify.currentParameterSpanIs("arg1: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpCallExpression.ts b/tests/cases/fourslash/signatureHelpCallExpression.ts new file mode 100644 index 00000000000..50d89aaae4e --- /dev/null +++ b/tests/cases/fourslash/signatureHelpCallExpression.ts @@ -0,0 +1,16 @@ +/// + +////function fnTest(str: string, num: number) { } +////fnTest(/*1*/'', /*2*/5); + +goTo.marker('1'); +verify.signatureHelpCountIs(1); +verify.currentSignatureParamterCountIs(2); +verify.currentSignatureHelpIs('fnTest(str: string, num: number): void'); + +verify.currentParameterHelpArgumentNameIs('str'); +verify.currentParameterSpanIs("str: string"); + +goTo.marker('2'); +verify.currentParameterHelpArgumentNameIs('num'); +verify.currentParameterSpanIs("num: number"); diff --git a/tests/cases/fourslash/signatureHelpConstructExpression.ts b/tests/cases/fourslash/signatureHelpConstructExpression.ts new file mode 100644 index 00000000000..a88cb3fce68 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpConstructExpression.ts @@ -0,0 +1,17 @@ +/// + +////class sampleCls { constructor(str: string, num: number) { } } +////var x = new sampleCls(/*1*/"", /*2*/5); + +goTo.marker('1'); +verify.signatureHelpCountIs(1); + +verify.currentSignatureParamterCountIs(2); +verify.currentSignatureHelpIs('sampleCls(str: string, num: number): sampleCls'); + +verify.currentParameterHelpArgumentNameIs('str'); +verify.currentParameterSpanIs("str: string"); + +goTo.marker('2'); +verify.currentParameterHelpArgumentNameIs('num'); +verify.currentParameterSpanIs("num: number"); diff --git a/tests/cases/fourslash/signatureHelpConstructorInheritance.ts b/tests/cases/fourslash/signatureHelpConstructorInheritance.ts new file mode 100644 index 00000000000..b066eab3fd4 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpConstructorInheritance.ts @@ -0,0 +1,22 @@ +/// + +////class base { +//// constructor(s: string); +//// constructor(n: number); +//// constructor(a: any) { } +////} +////class B1 extends base { } +////class B2 extends B1 { } +////class B3 extends B2 { +//// constructor() { +//// super(/*indirectSuperCall*/3); +//// } +////} + + +goTo.marker('indirectSuperCall'); +verify.signatureHelpCountIs(2); +verify.currentSignatureParamterCountIs(1); +verify.currentSignatureHelpIs('B2(n: number): B2'); +verify.currentParameterHelpArgumentNameIs("n"); +verify.currentParameterSpanIs("n: number"); diff --git a/tests/cases/fourslash/signatureHelpConstructorOverload.ts b/tests/cases/fourslash/signatureHelpConstructorOverload.ts new file mode 100644 index 00000000000..ce276e09d8f --- /dev/null +++ b/tests/cases/fourslash/signatureHelpConstructorOverload.ts @@ -0,0 +1,16 @@ +/// + +////class clsOverload { constructor(); constructor(test: string); constructor(test?: string) { } } +////var x = new clsOverload(/*1*/); +////var y = new clsOverload(/*2*/''); + +goTo.marker('1'); +verify.signatureHelpCountIs(2); +verify.currentSignatureParamterCountIs(0); +verify.currentSignatureHelpIs('clsOverload(): clsOverload'); + +goTo.marker('2'); +verify.currentSignatureParamterCountIs(1); +verify.currentSignatureHelpIs('clsOverload(test: string): clsOverload'); +verify.currentParameterHelpArgumentNameIs('test'); +verify.currentParameterSpanIs("test: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpEmptyList.ts b/tests/cases/fourslash/signatureHelpEmptyList.ts new file mode 100644 index 00000000000..6ea70159dcc --- /dev/null +++ b/tests/cases/fourslash/signatureHelpEmptyList.ts @@ -0,0 +1,20 @@ +/// + +////function Foo(arg1: string, arg2: string) { +////} +//// +////Foo(/*1*/); +////function Bar(arg1: string, arg2: string) { } +////Bar(); + +goTo.marker('1'); +verify.signatureHelpPresent(); +verify.signatureHelpCountIs(1); + +verify.currentSignatureHelpIs("Foo(arg1: string, arg2: string): void"); +verify.currentSignatureParamterCountIs(2); +verify.currentParameterHelpArgumentNameIs("arg1"); +verify.currentParameterSpanIs("arg1: string"); + +goTo.marker('2'); +verify.signatureHelpPresent(); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpForSuperCalls1.ts b/tests/cases/fourslash/signatureHelpForSuperCalls1.ts new file mode 100644 index 00000000000..58e083ea2ed --- /dev/null +++ b/tests/cases/fourslash/signatureHelpForSuperCalls1.ts @@ -0,0 +1,28 @@ +/// + +////class A { } +////class B extends A { } +////class C extends B { +//// constructor() { +//// super(/*1*/ // sig help here? +//// } +////} +////class A2 { } +////class B2 extends A2 { +//// constructor(x:number) {} +//// } +////class C2 extends B2 { +//// constructor() { +//// super(/*2*/ // sig help here? +//// } +////} + +// this line triggers a semantic/syntactic error check, remove line when 788570 is fixed +edit.insert(''); + +goTo.marker('1'); +verify.signatureHelpPresent(); +verify.currentSignatureHelpIs('B(): B'); + +goTo.marker('2'); +verify.currentSignatureHelpIs('B2(x: number): B2'); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpFunctionOverload.ts b/tests/cases/fourslash/signatureHelpFunctionOverload.ts new file mode 100644 index 00000000000..2c1cdb51291 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpFunctionOverload.ts @@ -0,0 +1,18 @@ +/// + +////function functionOverload(); +////function functionOverload(test: string); +////function functionOverload(test?: string) { } +////functionOverload(/*functionOverload1*/); +////functionOverload(""/*functionOverload2*/); + +goTo.marker('functionOverload1'); +verify.signatureHelpCountIs(2); +verify.currentSignatureParamterCountIs(0); +verify.currentSignatureHelpIs('functionOverload(): any'); + +goTo.marker('functionOverload2'); +verify.currentSignatureParamterCountIs(1); +verify.currentSignatureHelpIs('functionOverload(test: string): any'); +verify.currentParameterHelpArgumentNameIs("test"); +verify.currentParameterSpanIs("test: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpFunctionParameter.ts b/tests/cases/fourslash/signatureHelpFunctionParameter.ts new file mode 100644 index 00000000000..cb2264f2c42 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpFunctionParameter.ts @@ -0,0 +1,17 @@ +/// + +////function parameterFunction(callback: (a: number, b: string) => void) { +//// callback(/*parameterFunction1*/5, /*parameterFunction2*/""); +////} + +goTo.marker('parameterFunction1'); +verify.signatureHelpCountIs(1); +verify.currentSignatureParamterCountIs(2); +verify.currentSignatureHelpIs('callback(a: number, b: string): void'); +verify.currentParameterHelpArgumentNameIs("a"); +verify.currentParameterSpanIs("a: number"); + +goTo.marker('parameterFunction2'); +verify.currentSignatureHelpIs('callback(a: number, b: string): void'); +verify.currentParameterHelpArgumentNameIs("b"); +verify.currentParameterSpanIs("b: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpImplicitConstructor.ts b/tests/cases/fourslash/signatureHelpImplicitConstructor.ts new file mode 100644 index 00000000000..9e42d25dbe9 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpImplicitConstructor.ts @@ -0,0 +1,10 @@ +/// + +////class ImplicitConstructor { +////} +////var implicitConstructor = new ImplicitConstructor(/**/); + +goTo.marker(); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("ImplicitConstructor(): ImplicitConstructor"); +verify.currentSignatureParamterCountIs(0); diff --git a/tests/cases/fourslash/signatureHelpInCallback.ts b/tests/cases/fourslash/signatureHelpInCallback.ts new file mode 100644 index 00000000000..dd4856b48ef --- /dev/null +++ b/tests/cases/fourslash/signatureHelpInCallback.ts @@ -0,0 +1,11 @@ +/// + +////declare function forEach(f: () => void); +////forEach(/*1*/() => { +//// /*2*/ +////}); + +goTo.marker('1'); +verify.signatureHelpPresent(); +goTo.marker('2'); +verify.not.signatureHelpPresent(); diff --git a/tests/cases/fourslash/signatureHelpInCompleteGenericsCall.ts b/tests/cases/fourslash/signatureHelpInCompleteGenericsCall.ts new file mode 100644 index 00000000000..12036cd6db6 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpInCompleteGenericsCall.ts @@ -0,0 +1,8 @@ +/// + +////function foo(x: number, callback: (x: T) => number) { +////} +////foo(/*1*/ + +goTo.marker('1'); +verify.currentSignatureHelpIs("foo(x: number, callback: (x: T) => number): void"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles.ts b/tests/cases/fourslash/signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles.ts new file mode 100644 index 00000000000..2339af02529 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles.ts @@ -0,0 +1,14 @@ +/// + +// @Filename: signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles_file0.ts +////declare function fn(x: string, y: number); + +// @Filename: signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles_file1.ts +////declare function fn(x: string); + +// @Filename: signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles_file2.ts +////fn(/*1*/ + +diagnostics.setEditValidation(IncrementalEditValidation.None); +goTo.marker('1'); +verify.signatureHelpCountIs(2); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpInIncompleteInvocationExpression.ts b/tests/cases/fourslash/signatureHelpInIncompleteInvocationExpression.ts new file mode 100644 index 00000000000..2e097b2a76a --- /dev/null +++ b/tests/cases/fourslash/signatureHelpInIncompleteInvocationExpression.ts @@ -0,0 +1,19 @@ +/// + +/////** +//// * Returns the substring at the specified location within a String object. +//// * @param start The zero-based index integer indicating the beginning of the substring. +//// * @param end Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end. +//// * If end is omitted, the characters from start through the end of the original string are returned. +//// */ +////function foo(start: number, end?: number) { +//// return ""; +////} +//// +////foo(/*1*/ +goTo.marker('1'); +verify.currentParameterHelpArgumentDocCommentIs("The zero-based index integer indicating the beginning of the substring."); +edit.insert("10,"); +verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); +edit.insert(" "); +verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); diff --git a/tests/cases/fourslash/signatureHelpInParenthetical.ts b/tests/cases/fourslash/signatureHelpInParenthetical.ts new file mode 100644 index 00000000000..0628d904fdc --- /dev/null +++ b/tests/cases/fourslash/signatureHelpInParenthetical.ts @@ -0,0 +1,9 @@ +/// + +//// class base { constructor (public n: number, public y: string) { } } +//// (new base(/**/ + +goTo.marker(); +verify.currentParameterHelpArgumentNameIs('n'); +edit.insert('0, '); +verify.currentParameterHelpArgumentNameIs('y'); diff --git a/tests/cases/fourslash/signatureHelpIncompleteCalls.ts b/tests/cases/fourslash/signatureHelpIncompleteCalls.ts new file mode 100644 index 00000000000..e73217b1d8c --- /dev/null +++ b/tests/cases/fourslash/signatureHelpIncompleteCalls.ts @@ -0,0 +1,31 @@ +/// + +////module IncompleteCalls { +//// class Foo { +//// public f1() { } +//// public f2(n: number): number { return 0; } +//// public f3(n: number, s: string) : string { return ""; } +//// } +//// var x = new Foo(); +//// x.f1(); +//// x.f2(5); +//// x.f3(5, ""); +//// x.f1(/*incompleteCalls1*/ +//// x.f2(5,/*incompleteCalls2*/ +//// x.f3(5,/*incompleteCalls3*/ +////} + +goTo.marker('incompleteCalls1'); +verify.currentSignatureHelpIs("f1(): void"); +verify.currentSignatureParamterCountIs(0); + +goTo.marker('incompleteCalls2'); +verify.currentSignatureParamterCountIs(1); +verify.currentSignatureHelpIs("f2(n: number): number"); +goTo.marker('incompleteCalls3'); +verify.currentSignatureParamterCountIs(2); +verify.currentSignatureHelpIs("f3(n: number, s: string): string"); + +verify.currentParameterHelpArgumentNameIs("s"); +verify.currentParameterSpanIs("s: string"); + diff --git a/tests/cases/fourslash/signatureHelpNegativeTests2.ts b/tests/cases/fourslash/signatureHelpNegativeTests2.ts index 0302736ee97..28f25063ddf 100644 --- a/tests/cases/fourslash/signatureHelpNegativeTests2.ts +++ b/tests/cases/fourslash/signatureHelpNegativeTests2.ts @@ -1,10 +1,10 @@ /// ////class clsOverload { constructor(); constructor(test: string); constructor(test?: string) { } } -////var x = new clsOverload/*beforeOpenParen*/()/*afterOpenParen*/; +////var x = new clsOverload/*beforeOpenParen*/()/*afterCloseParen*/; goTo.marker('beforeOpenParen'); verify.not.signatureHelpPresent(); -goTo.marker('afterOpenParen'); +goTo.marker('afterCloseParen'); verify.not.signatureHelpPresent(); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpNoArguments.ts b/tests/cases/fourslash/signatureHelpNoArguments.ts new file mode 100644 index 00000000000..16a1896a741 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpNoArguments.ts @@ -0,0 +1,12 @@ +/// + + +////function foo(n: number): string { +////} +//// +////foo(/**/ + +goTo.marker(); +verify.currentSignatureHelpIs("foo(n: number): string"); +verify.currentParameterHelpArgumentNameIs("n"); +verify.currentParameterSpanIs("n: number"); diff --git a/tests/cases/fourslash/signatureHelpObjectLiteral.ts b/tests/cases/fourslash/signatureHelpObjectLiteral.ts new file mode 100644 index 00000000000..cbc5df697b9 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpObjectLiteral.ts @@ -0,0 +1,17 @@ +/// + +////var objectLiteral = { n: 5, s: "", f: (a: number, b: string) => "" }; +////objectLiteral.f(/*objectLiteral1*/4, /*objectLiteral2*/""); + +goTo.marker('objectLiteral1'); +verify.signatureHelpCountIs(1); +verify.currentSignatureParamterCountIs(2); +verify.currentSignatureHelpIs('f(a: number, b: string): string'); + +verify.currentParameterHelpArgumentNameIs("a"); +verify.currentParameterSpanIs("a: number"); + +goTo.marker('objectLiteral2'); +verify.currentSignatureHelpIs('f(a: number, b: string): string'); +verify.currentParameterHelpArgumentNameIs("b"); +verify.currentParameterSpanIs("b: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpOnNestedOverloads.ts b/tests/cases/fourslash/signatureHelpOnNestedOverloads.ts new file mode 100644 index 00000000000..476d79a8243 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnNestedOverloads.ts @@ -0,0 +1,20 @@ +/// + +////declare function fn(x: string); +////declare function fn(x: string, y: number); +////declare function fn2(x: string); +////declare function fn2(x: string, y: number); +////fn('', fn2(/*1*/ + +goTo.marker('1'); +verify.signatureHelpCountIs(2); +verify.currentSignatureHelpIs("fn2(x: string): any"); +verify.currentParameterHelpArgumentNameIs("x"); +verify.currentParameterSpanIs("x: string"); + +edit.insert("'',"); + +verify.signatureHelpCountIs(2); +// verify.currentSignatureHelpIs("fn2(x: string, y: number): any"); +// verify.currentParameterHelpArgumentNameIs("y"); +// verify.currentParameterSpanIs("y: number"); diff --git a/tests/cases/fourslash/signatureHelpOnOverloadOnConst.ts b/tests/cases/fourslash/signatureHelpOnOverloadOnConst.ts new file mode 100644 index 00000000000..8edd0617d70 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnOverloadOnConst.ts @@ -0,0 +1,26 @@ +/// + +////function x1(x: 'hi'); +////function x1(y: 'bye'); +////function x1(z: string); +////function x1(a: any) { +////} +//// +////x1(''/*1*/); +////x1('hi'/*2*/); +////x1('bye'/*3*/); + +goTo.marker('1'); +verify.signatureHelpCountIs(3); +verify.currentParameterHelpArgumentNameIs("z"); +verify.currentParameterSpanIs("z: string"); + +goTo.marker('2'); +verify.signatureHelpCountIs(3); +verify.currentParameterHelpArgumentNameIs("x"); +verify.currentParameterSpanIs("x: 'hi'"); + +goTo.marker('3'); +verify.signatureHelpCountIs(3); +verify.currentParameterHelpArgumentNameIs("y"); +verify.currentParameterSpanIs("y: 'bye'"); diff --git a/tests/cases/fourslash/signatureHelpOnOverloads.ts b/tests/cases/fourslash/signatureHelpOnOverloads.ts new file mode 100644 index 00000000000..83d7b75a4cf --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnOverloads.ts @@ -0,0 +1,18 @@ +/// + +////declare function fn(x: string); +////declare function fn(x: string, y: number); +////fn(/*1*/ + +goTo.marker('1'); +verify.signatureHelpCountIs(2); +verify.currentSignatureHelpIs("fn(x: string): any"); +verify.currentParameterHelpArgumentNameIs("x"); +verify.currentParameterSpanIs("x: string"); + +edit.insert("'',"); + +verify.signatureHelpCountIs(2); +// verify.currentSignatureHelpIs("fn(x: string, y: number): any"); +// verify.currentParameterHelpArgumentNameIs("y"); +// verify.currentParameterSpanIs("y: number"); diff --git a/tests/cases/fourslash/signatureHelpOnSuperWhenMembersAreNotResolved.ts b/tests/cases/fourslash/signatureHelpOnSuperWhenMembersAreNotResolved.ts new file mode 100644 index 00000000000..5613ca71a70 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpOnSuperWhenMembersAreNotResolved.ts @@ -0,0 +1,14 @@ +/// + +////class A { } +////class B extends A { constructor(public x: string) { } } +////class C extends B { +//// constructor() { +//// /*1*/ +//// } +////} + +diagnostics.setEditValidation(IncrementalEditValidation.None); +goTo.marker("1"); +edit.insert("super("); +verify.currentSignatureHelpIs("B(x: string): B"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpSimpleConstructorCall.ts b/tests/cases/fourslash/signatureHelpSimpleConstructorCall.ts new file mode 100644 index 00000000000..81af0422f9a --- /dev/null +++ b/tests/cases/fourslash/signatureHelpSimpleConstructorCall.ts @@ -0,0 +1,17 @@ +/// + +////class ConstructorCall { +//// constructor(str: string, num: number) { +//// } +////} +////var x = new ConstructorCall(/*constructorCall1*/1,/*constructorCall2*/2); + +goTo.marker('constructorCall1'); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("ConstructorCall(str: string, num: number): ConstructorCall"); +verify.currentParameterHelpArgumentNameIs("str"); +verify.currentParameterSpanIs("str: string"); +goTo.marker('constructorCall2'); +verify.currentSignatureHelpIs("ConstructorCall(str: string, num: number): ConstructorCall"); +verify.currentParameterHelpArgumentNameIs("num"); +verify.currentParameterSpanIs("num: number"); diff --git a/tests/cases/fourslash/signatureHelpSimpleFunctionCall.ts b/tests/cases/fourslash/signatureHelpSimpleFunctionCall.ts new file mode 100644 index 00000000000..6e5817ad90d --- /dev/null +++ b/tests/cases/fourslash/signatureHelpSimpleFunctionCall.ts @@ -0,0 +1,19 @@ +/// + +////// Simple function test +////function functionCall(str: string, num: number) { +////} +////functionCall(/*functionCall1*/); +////functionCall("", /*functionCall2*/1); + + +goTo.marker('functionCall1'); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("functionCall(str: string, num: number): void"); +verify.currentParameterHelpArgumentNameIs("str"); +verify.currentParameterSpanIs("str: string"); +goTo.marker('functionCall2'); +verify.currentSignatureHelpIs("functionCall(str: string, num: number): void"); +verify.currentParameterHelpArgumentNameIs("num"); +verify.currentParameterSpanIs("num: number"); + diff --git a/tests/cases/fourslash/signatureHelpSimpleSuperCall.ts b/tests/cases/fourslash/signatureHelpSimpleSuperCall.ts new file mode 100644 index 00000000000..ff8913a6b04 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpSimpleSuperCall.ts @@ -0,0 +1,20 @@ +/// + +////class SuperCallBase { +//// constructor(b: boolean) { +//// } +////} +////class SuperCall extends SuperCallBase { +//// constructor() { +//// super(/*superCall*/); +//// } +////} + +// this line triggers a semantic/syntactic error check, remove line when 788570 is fixed +edit.insert(''); + +goTo.marker('superCall'); +verify.signatureHelpCountIs(1); +verify.currentSignatureHelpIs("SuperCallBase(b: boolean): SuperCallBase"); +verify.currentParameterHelpArgumentNameIs("b"); +verify.currentParameterSpanIs("b: boolean"); diff --git a/tests/cases/fourslash/signatureHelpSuperConstructorOverload.ts b/tests/cases/fourslash/signatureHelpSuperConstructorOverload.ts new file mode 100644 index 00000000000..1be8c3202a1 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpSuperConstructorOverload.ts @@ -0,0 +1,28 @@ +/// + +////class SuperOverloadlBase { +//// constructor(); +//// constructor(test: string); +//// constructor(test?: string) { +//// } +////} +////class SuperOverLoad1 extends SuperOverloadlBase { +//// constructor() { +//// super(/*superOverload1*/); +//// } +////} +////class SuperOverLoad2 extends SuperOverloadlBase { +//// constructor() { +//// super(""/*superOverload2*/); +//// } +////} + +goTo.marker('superOverload1'); +verify.signatureHelpCountIs(2); +verify.currentSignatureHelpIs("SuperOverloadlBase(): SuperOverloadlBase"); +verify.currentSignatureParamterCountIs(0); +goTo.marker('superOverload2'); +verify.currentSignatureParamterCountIs(1); +verify.currentSignatureHelpIs("SuperOverloadlBase(test: string): SuperOverloadlBase"); +verify.currentParameterHelpArgumentNameIs("test"); +verify.currentParameterSpanIs("test: string"); \ No newline at end of file diff --git a/tests/cases/fourslash/signatureHelpWhenEditingCallExpression.ts b/tests/cases/fourslash/signatureHelpWhenEditingCallExpression.ts new file mode 100644 index 00000000000..61e51d0a4e7 --- /dev/null +++ b/tests/cases/fourslash/signatureHelpWhenEditingCallExpression.ts @@ -0,0 +1,30 @@ +/// + +/////** +//// * Returns the substring at the specified location within a String object. +//// * @param start The zero-based index integer indicating the beginning of the substring. +//// * @param end Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end. +//// * If end is omitted, the characters from start through the end of the original string are returned. +//// */ +////function foo(start: number, end?: number) { +//// return ""; +////} +//// +////fo/*1*/ +goTo.marker('1'); +verify.not.signatureHelpPresent(); +edit.insert("o"); +verify.not.signatureHelpPresent(); +edit.insert("("); +verify.currentParameterHelpArgumentDocCommentIs("The zero-based index integer indicating the beginning of the substring."); +edit.insert("10,"); +verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); +edit.insert(" "); +verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); +edit.insert(", "); +edit.backspace(3); +verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); +edit.insert("12"); +verify.currentParameterHelpArgumentDocCommentIs("Zero-based index integer indicating the end of the substring. The substring includes the characters up to, but not including, the character indicated by end.\nIf end is omitted, the characters from start through the end of the original string are returned."); +edit.insert(")"); +verify.not.signatureHelpPresent(); diff --git a/tests/cases/fourslash/staticGenericOverloads1.ts b/tests/cases/fourslash/staticGenericOverloads1.ts new file mode 100644 index 00000000000..56f358dd951 --- /dev/null +++ b/tests/cases/fourslash/staticGenericOverloads1.ts @@ -0,0 +1,22 @@ +/// + +////class A { +//// static B(v: A): A; +//// static B(v: S): A; +//// static B(v: any): A { +//// return null; +//// } +////} + +////var a = new A(); +////A.B(/**/ + +goTo.marker(); +verify.signatureHelpCountIs(2); +edit.insert('a'); +verify.signatureHelpCountIs(2); +// verify.currentSignatureHelpIs('B(v: A): A') +edit.insert('); A.B('); +verify.currentSignatureHelpIs('B(v: A): A'); +edit.insert('a'); +// verify.currentSignatureHelpIs('B(v: A): A') diff --git a/tests/cases/unittests/services/colorization.ts b/tests/cases/unittests/services/colorization.ts index 7b8ee376064..0a5ce1f0310 100644 --- a/tests/cases/unittests/services/colorization.ts +++ b/tests/cases/unittests/services/colorization.ts @@ -36,7 +36,7 @@ describe('Colorization', function () { } var finalEndOfLineState = classResult[classResult.length - 1]; - assert.equal(position, code.length, "Expected accumilative length of all entries to match the length of the source. expected: " + code.length + ", but got: " + position); + assert.equal(position, code.length, "Expected cumulative length of all entries to match the length of the source. expected: " + code.length + ", but got: " + position); return { tuples: tuples, @@ -84,8 +84,8 @@ describe('Colorization', function () { var actualEntry = getEntryAtPosistion(result, actualEntryPosition); assert(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition); - assert.equal(actualEntry.length, expectedEntry.value.length, "Classification class does not match expected."); - assert.equal(actualEntry.class, expectedEntry.class, "Classification class does not match expected."); + assert.equal(actualEntry.class, expectedEntry.class, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.class] + ", Actual: " + ts.TokenClass[actualEntry.class]); + assert.equal(actualEntry.length, expectedEntry.value.length, "Classification length does not match expected. Expected: " + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length]); } } } @@ -105,7 +105,7 @@ describe('Colorization', function () { punctuation(";")); }); - it("classifies correctelly a comment after a divide operator", function () { + it("correctly classifies a comment after a divide operator", function () { test("1 / 2 // comment", ts.EndOfLineState.Start, numberLiteral("1"), @@ -115,7 +115,7 @@ describe('Colorization', function () { comment("// comment")); }); - it("classifies correctelly a literal after a divide operator", function () { + it("correctly classifies a literal after a divide operator", function () { test("1 / 2, 3 / 4", ts.EndOfLineState.Start, numberLiteral("1"), @@ -127,48 +127,76 @@ describe('Colorization', function () { operator(",")); }); - it("classifies correctelly an unterminated multi-line string", function () { + it("correctly classifies an unterminated multi-line string", function () { test("'line1\\", ts.EndOfLineState.Start, stringLiteral("'line1\\"), finalEndOfLineState(ts.EndOfLineState.InSingleQuoteStringLiteral)); }); - it("classifies correctelly the second line of an unterminated multi-line string", function () { + it("correctly classifies the second line of an unterminated multi-line string", function () { test("\\", ts.EndOfLineState.InDoubleQuoteStringLiteral, stringLiteral("\\"), finalEndOfLineState(ts.EndOfLineState.InDoubleQuoteStringLiteral)); }); - it("classifies correctelly the last line of a multi-line string", function () { + it("correctly classifies the last line of a multi-line string", function () { test("'", ts.EndOfLineState.InSingleQuoteStringLiteral, stringLiteral("'"), finalEndOfLineState(ts.EndOfLineState.Start)); }); - it("classifies correctelly an unterminated multiline comment", function () { + it("correctly classifies an unterminated multiline comment", function () { test("/*", ts.EndOfLineState.Start, comment("/*"), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); }); - it("classifies correctelly an unterminated multiline comment with trailing space", function () { + it("correctly classifies the termination of a multiline comment", function () { + test(" */ ", + ts.EndOfLineState.InMultiLineCommentTrivia, + comment(" */"), + finalEndOfLineState(ts.EndOfLineState.Start)); + }); + + it("correctly classifies the continuation of a multiline comment", function () { + test("LOREM IPSUM DOLOR ", + ts.EndOfLineState.InMultiLineCommentTrivia, + comment("LOREM IPSUM DOLOR "), + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + }); + + it("correctly classifies an unterminated multiline comment on a line ending in '/*/'", function () { + test(" /*/", + ts.EndOfLineState.Start, + comment("/*/"), + finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); + }); + + it("correctly classifies an unterminated multiline comment with trailing space", function () { test("/* ", ts.EndOfLineState.Start, comment("/* "), finalEndOfLineState(ts.EndOfLineState.InMultiLineCommentTrivia)); }); - it("classifies correctelly a keyword after a dot", function () { + it("correctly classifies a keyword after a dot", function () { test("a.var", ts.EndOfLineState.Start, identifier("var")); }); - it("classifies keyword after a dot on previous line", function () { + it("classifies a property access with whitespace around the dot", function () { + test(" x .\tfoo ()", + ts.EndOfLineState.Start, + identifier("x"), + identifier("foo")); + }); + + it("classifies a keyword after a dot on previous line", function () { test("var", ts.EndOfLineState.Start, keyword("var"),