diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 4f8141fd866..6b2dafaa19d 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -206,7 +206,8 @@ module ts { if (symbolKind & SymbolFlags.Namespace) { exportKind |= SymbolFlags.ExportNamespace; } - if (node.flags & NodeFlags.Export || (node.kind !== SyntaxKind.ImportDeclaration && isAmbientContext(container))) { + + if (getCombinedNodeFlags(node) & NodeFlags.Export || (node.kind !== SyntaxKind.ImportDeclaration && isAmbientContext(container))) { if (exportKind) { var local = declareSymbol(container.locals, undefined, node, exportKind, symbolExcludes); local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes); @@ -234,10 +235,8 @@ module ts { parent = node; if (symbolKind & SymbolFlags.IsContainer) { container = node; - Debug.assert(container.nextContainer === undefined); if (lastContainer) { - Debug.assert(lastContainer.nextContainer === undefined); lastContainer.nextContainer = container; } @@ -391,7 +390,7 @@ module ts { if (isBindingPattern((node).name)) { bindChildren(node, 0, /*isBlockScopeContainer*/ false); } - else if (node.flags & NodeFlags.BlockScoped) { + else if (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) { bindBlockScopedVariableDeclaration(node); } else { @@ -483,9 +482,7 @@ module ts { break; } case SyntaxKind.Block: - case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: case SyntaxKind.SwitchStatement: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7726b786b7..ccc67ba3881 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16,7 +16,6 @@ module ts { /// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors. /// NOTE: checks that somehow affect decisions being made during typechecking should be executed in both cases. export function createTypeChecker(program: Program, fullTypeCheck: boolean): TypeChecker { - var Symbol = objectAllocator.getSymbolConstructor(); var Type = objectAllocator.getTypeConstructor(); var Signature = objectAllocator.getSignatureConstructor(); @@ -407,7 +406,7 @@ module ts { } if (result.flags & SymbolFlags.BlockScopedVariable) { // Block-scoped variables cannot be used before their definition - var declaration = forEach(result.declarations, d => d.flags & NodeFlags.BlockScoped ? d : undefined); + var declaration = forEach(result.declarations, d => getCombinedNodeFlags(d) & NodeFlags.BlockScoped ? d : undefined); Debug.assert(declaration !== undefined, "Block-scoped variable declaration is undefined"); if (!isDefinedBefore(declaration, errorLocation)) { error(errorLocation, Diagnostics.Block_scoped_variable_0_used_before_its_declaration, declarationNameToString(declaration.name)); @@ -657,7 +656,7 @@ module ts { var members = node.members; for (var i = 0; i < members.length; i++) { var member = members[i]; - if (member.kind === SyntaxKind.Constructor && (member).body) { + if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) { return member; } } @@ -771,7 +770,7 @@ module ts { // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) // and if symbolfrom symbolTable or alias resolution matches the symbol, // check the symbol can be qualified, it is only then this symbol is accessible - return !forEach(symbolFromSymbolTable.declarations, declaration => hasExternalModuleSymbol(declaration)) && + return !forEach(symbolFromSymbolTable.declarations, hasExternalModuleSymbol) && canQualifySymbol(symbolFromSymbolTable, meaning); } } @@ -875,7 +874,7 @@ module ts { // This could be a symbol that is not exported in the external module // or it could be a symbol from different external module that is not aliased and hence cannot be named - var symbolExternalModule = forEach(initialSymbol.declarations, declaration => getExternalModuleContainer(declaration)); + var symbolExternalModule = forEach(initialSymbol.declarations, getExternalModuleContainer); if (symbolExternalModule) { var enclosingExternalModule = getExternalModuleContainer(enclosingDeclaration); if (symbolExternalModule !== enclosingExternalModule) { @@ -1095,7 +1094,7 @@ module ts { } else { // If we didn't find accessible symbol chain for this symbol, break if this is external module - if (!parentSymbol && ts.forEach(symbol.declarations, declaration => hasExternalModuleSymbol(declaration))) { + if (!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) { return; } @@ -1564,7 +1563,7 @@ module ts { case SyntaxKind.ImportDeclaration: var parent = getDeclarationContainer(node); // If the node is not exported or it is not ambient module element (except import declaration) - if (!(node.flags & NodeFlags.Export) && + if (!(getCombinedNodeFlags(node) & NodeFlags.Export) && !(node.kind !== SyntaxKind.ImportDeclaration && parent.kind !== SyntaxKind.SourceFile && isInAmbientContext(parent))) { return isGlobalSourceFile(parent) || isUsedInExportAssignment(node); } @@ -1627,7 +1626,10 @@ module ts { function getDeclarationContainer(node: Node): Node { node = getRootDeclaration(node); - return node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent : node.parent; + + // Parent chain: + // VaribleDeclaration -> VariableDeclarationList -> VariableStatement -> 'Declaration Container' + return node.kind === SyntaxKind.VariableDeclaration ? node.parent.parent.parent : node.parent; } function getTypeOfPrototypeProperty(prototype: Symbol): Type { @@ -1701,7 +1703,7 @@ module ts { // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type { // A variable declared in a for..in statement is always of type any - if (declaration.parent.kind === SyntaxKind.ForInStatement) { + if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) { return anyType; } if (isBindingPattern(declaration.parent)) { @@ -2635,7 +2637,7 @@ module ts { returnType = getAnnotatedAccessorType(setter); } - if (!returnType && !(declaration).body) { + if (!returnType && nodeIsMissing((declaration).body)) { returnType = anyType; } } @@ -4133,7 +4135,7 @@ module ts { return anyType; } if (type.flags & TypeFlags.Union) { - return getUnionType(map((type).types, t => getWidenedType(t))); + return getUnionType(map((type).types, getWidenedType)); } if (isTypeOfObjectLiteral(type)) { return getWidenedTypeOfObjectLiteral(type); @@ -4551,9 +4553,7 @@ module ts { case SyntaxKind.LabeledStatement: case SyntaxKind.ThrowStatement: case SyntaxKind.TryStatement: - case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: return forEachChild(node, isAssignedIn); } return false; @@ -5142,7 +5142,7 @@ module ts { // Return true if the given contextual type is a tuple-like type function contextualTypeIsTupleLikeType(type: Type): boolean { - return !!(type.flags & TypeFlags.Union ? forEach((type).types, t => isTupleLikeType(t)) : isTupleLikeType(type)); + return !!(type.flags & TypeFlags.Union ? forEach((type).types, isTupleLikeType) : isTupleLikeType(type)); } // Return true if the given contextual type provides an index signature of the given kind @@ -5481,7 +5481,7 @@ module ts { } function getDeclarationFlagsFromSymbol(s: Symbol) { - return s.valueDeclaration ? s.valueDeclaration.flags : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; + return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; } function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, type: Type, prop: Symbol) { @@ -6439,7 +6439,7 @@ module ts { } // If all we have is a function signature, or an arrow function with an expression body, then there is nothing to check. - if (!func.body || func.body.kind !== SyntaxKind.Block) { + if (nodeIsMissing(func.body) || func.body.kind !== SyntaxKind.Block) { return; } @@ -7184,7 +7184,7 @@ module ts { var func = getContainingFunction(node); if (node.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) { func = getContainingFunction(node); - if (!(func.kind === SyntaxKind.Constructor && func.body)) { + if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation); } } @@ -7303,7 +7303,7 @@ module ts { } // exit early in the case of signature - super checks are not relevant to them - if (!node.body) { + if (nodeIsMissing(node.body)) { return; } @@ -7376,11 +7376,11 @@ module ts { function checkAccessorDeclaration(node: AccessorDeclaration) { // Grammar checking accessors - checkGrammarFunctionLikeDeclaration(node) || checkGrammarAccessor(node) || checkGrammarComputedPropertyName(node.name); + checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || checkGrammarFunctionLikeDeclaration(node) || checkGrammarAccessor(node) || checkGrammarComputedPropertyName(node.name); if (fullTypeCheck) { if (node.kind === SyntaxKind.GetAccessor) { - if (!isInAmbientContext(node) && node.body && !(bodyContainsAReturnStatement(node.body) || bodyContainsSingleThrowStatement(node.body))) { + if (!isInAmbientContext(node) && nodeIsPresent(node.body) && !(bodyContainsAReturnStatement(node.body) || bodyContainsSingleThrowStatement(node.body))) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value_or_consist_of_a_single_throw_statement); } } @@ -7478,7 +7478,7 @@ module ts { // TypeScript 1.0 spec (April 2014): 3.7.2.2 // Specialized signatures are not permitted in conjunction with a function body - if ((signatureDeclarationNode).body) { + if (nodeIsPresent((signatureDeclarationNode).body)) { error(signatureDeclarationNode, Diagnostics.A_signature_with_an_implementation_cannot_use_a_string_literal_type); return; } @@ -7511,7 +7511,7 @@ module ts { } function getEffectiveDeclarationFlags(n: Node, flagsToCheck: NodeFlags) { - var flags = n.flags; + var flags = getCombinedNodeFlags(n); if (n.parent.kind !== SyntaxKind.InterfaceDeclaration && isInAmbientContext(n)) { if (!(flags & NodeFlags.Ambient)) { // It is nested in an ambient context, which means it is automatically exported @@ -7611,7 +7611,7 @@ module ts { error(errorNode, diagnostic); return; } - else if ((subsequentNode).body) { + else if (nodeIsPresent((subsequentNode).body)) { error(errorNode, Diagnostics.Function_implementation_name_must_be_0, declarationNameToString(node.name)); return; } @@ -7653,7 +7653,7 @@ module ts { someHaveQuestionToken = someHaveQuestionToken || hasQuestionToken(node); allHaveQuestionToken = allHaveQuestionToken && hasQuestionToken(node); - if (node.body && bodyDeclaration) { + if (nodeIsPresent(node.body) && bodyDeclaration) { if (isConstructor) { multipleConstructorImplementation = true; } @@ -7665,7 +7665,7 @@ module ts { reportImplementationExpectedError(previousDeclaration); } - if (node.body) { + if (nodeIsPresent(node.body)) { if (!bodyDeclaration) { bodyDeclaration = node; } @@ -7810,8 +7810,9 @@ module ts { function checkFunctionDeclaration(node: FunctionDeclaration): void { // Grammar Checking, check signature of function declaration as checkFunctionLikeDeclaration call checkGarmmarFunctionLikeDeclaration checkFunctionLikeDeclaration(node); + //Grammar check other component of the functionDeclaration - checkGrammarFunctionName(node.name) || checkGrammarForGenerator(node); + checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || checkGrammarFunctionName(node.name) || checkGrammarForGenerator(node); if (fullTypeCheck) { checkCollisionWithCapturedSuperVariable(node, node.name); @@ -7852,7 +7853,7 @@ module ts { // Report an implicit any error if there is no body, no explicit return type, and node is not a private method // in an ambient context - if (compilerOptions.noImplicitAny && !node.body && !node.type && !isPrivateWithinAmbient(node)) { + if (compilerOptions.noImplicitAny && nodeIsMissing(node.body) && !node.type && !isPrivateWithinAmbient(node)) { reportImplicitAnyError(node, anyType); } } @@ -7871,7 +7872,7 @@ module ts { function checkCollisionWithArgumentsInGeneratedCode(node: SignatureDeclaration) { // no rest parameters \ declaration context \ overload - no codegen impact - if (!hasRestParameters(node) || isInAmbientContext(node) || !(node).body) { + if (!hasRestParameters(node) || isInAmbientContext(node) || nodeIsMissing((node).body)) { return; } @@ -7903,7 +7904,7 @@ module ts { } var root = getRootDeclaration(node); - if (root.kind === SyntaxKind.Parameter && !(root.parent).body) { + if (root.kind === SyntaxKind.Parameter && nodeIsMissing((root.parent).body)) { // just an overload - no codegen impact return false; } @@ -7996,7 +7997,7 @@ module ts { // const x = 0; // var x = 0; // } - if (node.initializer && (node.flags & NodeFlags.BlockScoped) === 0) { + if (node.initializer && (getCombinedNodeFlags(node) & NodeFlags.BlockScoped) === 0) { var symbol = getSymbolOfNode(node); if (symbol.flags & SymbolFlags.FunctionScopedVariable) { var localDeclarationSymbol = resolveName(node, (node.name).text, SymbolFlags.Variable, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); @@ -8063,7 +8064,7 @@ module ts { forEach((node.name).elements, checkSourceElement); } // For a parameter declaration with an initializer, error and exit if the containing function doesn't have a body - if (node.initializer && getRootDeclaration(node).kind === SyntaxKind.Parameter && !getContainingFunction(node).body) { + if (node.initializer && getRootDeclaration(node).kind === SyntaxKind.Parameter && nodeIsMissing(getContainingFunction(node).body)) { error(node, Diagnostics.A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation); return; } @@ -8117,9 +8118,27 @@ module ts { function checkVariableStatement(node: VariableStatement) { // Grammar checking - checkGrammarModifiers(node) || checkGrammarVariableDeclarations(node, node.declarations) || checkGrammarForDisallowedLetOrConstStatement(node); + checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || checkGrammarModifiers(node) || checkGrammarVariableDeclarationList(node.declarationList) || checkGrammarForDisallowedLetOrConstStatement(node); - forEach(node.declarations, checkSourceElement); + forEach(node.declarationList.declarations, checkSourceElement); + } + + function checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node: Node) { + if (node.modifiers) { + if (inBlockOrObjectLiteralExpression(node)) { + return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here); + } + } + } + + function inBlockOrObjectLiteralExpression(node: Node) { + while (node) { + if (node.kind === SyntaxKind.Block || node.kind === SyntaxKind.ObjectLiteralExpression) { + return true; + } + + node = node.parent; + } } function checkExpressionStatement(node: ExpressionStatement) { @@ -8156,10 +8175,21 @@ module ts { function checkForStatement(node: ForStatement) { // Grammar checking - checkGrammarForStatementInAmbientContext(node) || checkGrammarVariableDeclarations(node, node.declarations); + if (!checkGrammarForStatementInAmbientContext(node)) { + if (node.initializer && node.initializer.kind == SyntaxKind.VariableDeclarationList) { + checkGrammarVariableDeclarationList(node.initializer); + } + } + + if (node.initializer) { + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + forEach((node.initializer).declarations, checkVariableDeclaration) + } + else { + checkExpression(node.initializer) + } + } - if (node.declarations) forEach(node.declarations, checkVariableDeclaration); - if (node.initializer) checkExpression(node.initializer); if (node.condition) checkExpression(node.condition); if (node.iterator) checkExpression(node.iterator); checkSourceElement(node.statement); @@ -8168,10 +8198,12 @@ module ts { function checkForInStatement(node: ForInStatement) { // Grammar checking if (!checkGrammarForStatementInAmbientContext(node)) { - var declarations = node.declarations; - if (!checkGrammarVariableDeclarations(node, declarations)) { - if (declarations && declarations.length > 1) { - grammarErrorOnFirstToken(declarations[1], Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement); + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + var variableList = node.initializer; + if (!checkGrammarVariableDeclarationList(variableList)) { + if (variableList.declarations.length > 1) { + grammarErrorOnFirstToken(variableList.declarations[1], Diagnostics.Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement); + } } } } @@ -8181,28 +8213,29 @@ module ts { // for (var VarDecl in Expr) Statement // VarDecl must be a variable declaration without a type annotation that declares a variable of type Any, // and Expr must be an expression of type Any, an object type, or a type parameter type. - if (node.declarations) { - if (node.declarations.length >= 1) { - var decl = node.declarations[0]; + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + var variableDeclarationList = node.initializer; + if (variableDeclarationList.declarations.length >= 1) { + var decl = variableDeclarationList.declarations[0]; checkVariableDeclaration(decl); if (decl.type) { error(decl, Diagnostics.The_left_hand_side_of_a_for_in_statement_cannot_use_a_type_annotation); } } } - - // In a 'for-in' statement of the form - // for (Var in Expr) Statement - // Var must be an expression classified as a reference of type Any or the String primitive type, - // and Expr must be an expression of type Any, an object type, or a type parameter type. - if (node.variable) { - var exprType = checkExpression(node.variable); + else { + // In a 'for-in' statement of the form + // for (Var in Expr) Statement + // Var must be an expression classified as a reference of type Any or the String primitive type, + // and Expr must be an expression of type Any, an object type, or a type parameter type. + var varExpr = node.initializer; + var exprType = checkExpression(varExpr); if (exprType !== anyType && exprType !== stringType) { - error(node.variable, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); + error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any); } else { // run check only former check succeeded to avoid cascading errors - checkReferenceExpression(node.variable, Diagnostics.Invalid_left_hand_side_in_for_in_statement, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant); + checkReferenceExpression(varExpr, Diagnostics.Invalid_left_hand_side_in_for_in_statement, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant); } } @@ -8936,7 +8969,7 @@ module ts { var declarations = symbol.declarations; for (var i = 0; i < declarations.length; i++) { var declaration = declarations[i]; - if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && (declaration).body)) && !isInAmbientContext(declaration)) { + if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((declaration).body))) && !isInAmbientContext(declaration)) { return declaration; } } @@ -9256,10 +9289,9 @@ module ts { case SyntaxKind.LabeledStatement: case SyntaxKind.ThrowStatement: case SyntaxKind.TryStatement: - case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: case SyntaxKind.VariableDeclaration: + case SyntaxKind.VariableDeclarationList: case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.EnumMember: @@ -9871,7 +9903,7 @@ module ts { } function isImplementationOfOverload(node: FunctionLikeDeclaration) { - if (node.body) { + if (nodeIsPresent(node.body)) { var symbol = getSymbolOfNode(node); var signaturesOfSymbol = getSignaturesOfSymbol(symbol); // If this function body corresponds to function with multiple signature, it is implementation of overload @@ -10504,11 +10536,21 @@ module ts { } function checkGrammarMethod(node: MethodDeclaration) { - if (checkGrammarFunctionLikeDeclaration(node) || + if (checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node) || + checkGrammarFunctionLikeDeclaration(node) || checkGrammarForGenerator(node)) { return true; } + if (node.parent.kind === SyntaxKind.ObjectLiteralExpression) { + if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) { + return true; + } + else if (node.body === undefined) { + return grammarErrorAtPos(getSourceFile(node), node.end - 1, ";".length, Diagnostics._0_expected, "{"); + } + } + if (node.parent.kind === SyntaxKind.ClassDeclaration) { if (checkGrammarForInvalidQuestionMark(node, node.questionToken, Diagnostics.A_class_member_cannot_be_declared_optional)) { return true; @@ -10642,24 +10684,22 @@ module ts { return checkGrammarEvalOrArgumentsInStrictMode(node, node.name); } - function checkGrammarVariableDeclarations(container: Node, declarations: NodeArray): boolean { - if (declarations) { - if (checkGrammarForDisallowedTrailingComma(declarations)) { - return true; - } + function checkGrammarVariableDeclarationList(declarationList: VariableDeclarationList): boolean { + var declarations = declarationList.declarations; + if (checkGrammarForDisallowedTrailingComma(declarationList.declarations)) { + return true; + } - if (!declarations.length) { - return grammarErrorAtPos(getSourceFileOfNode(container), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); - } + if (!declarationList.declarations.length) { + return grammarErrorAtPos(getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); + } - var decl = declarations[0]; - if (compilerOptions.target < ScriptTarget.ES6) { - if (isLet(decl)) { - return grammarErrorOnFirstToken(decl, Diagnostics.let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher); - } - else if (isConst(decl)) { - return grammarErrorOnFirstToken(decl, Diagnostics.const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher); - } + if (compilerOptions.target < ScriptTarget.ES6) { + if (isLet(declarationList)) { + return grammarErrorOnFirstToken(declarationList, Diagnostics.let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher); + } + else if (isConst(declarationList)) { + return grammarErrorOnFirstToken(declarationList, Diagnostics.const_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher); } } } @@ -10682,10 +10722,10 @@ module ts { function checkGrammarForDisallowedLetOrConstStatement(node: VariableStatement) { if (!allowLetAndConstDeclarations(node.parent)) { - if (isLet(node)) { + if (isLet(node.declarationList)) { return grammarErrorOnNode(node, Diagnostics.let_declarations_can_only_be_declared_inside_a_block); } - else if (isConst(node)) { + else if (isConst(node.declarationList)) { return grammarErrorOnNode(node, Diagnostics.const_declarations_can_only_be_declared_inside_a_block); } } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index c35a443db40..9a8fe3aaa36 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -143,8 +143,9 @@ module ts { A_destructuring_declaration_must_have_an_initializer: { code: 1182, category: DiagnosticCategory.Error, key: "A destructuring declaration must have an initializer.", isEarly: true }, Destructuring_declarations_are_not_allowed_in_ambient_contexts: { code: 1183, category: DiagnosticCategory.Error, key: "Destructuring declarations are not allowed in ambient contexts.", isEarly: true }, An_implementation_cannot_be_declared_in_ambient_contexts: { code: 1184, category: DiagnosticCategory.Error, key: "An implementation cannot be declared in ambient contexts.", isEarly: true }, - Merge_conflict_marker_encountered: { code: 1184, category: DiagnosticCategory.Error, key: "Merge conflict marker encountered." }, - A_rest_element_cannot_have_an_initializer: { code: 1185, category: DiagnosticCategory.Error, key: "A rest element cannot have an initializer." }, + Modifiers_cannot_appear_here: { code: 1184, category: DiagnosticCategory.Error, key: "Modifiers cannot appear here." }, + Merge_conflict_marker_encountered: { code: 1185, category: DiagnosticCategory.Error, key: "Merge conflict marker encountered." }, + A_rest_element_cannot_have_an_initializer: { code: 1186, category: DiagnosticCategory.Error, key: "A rest element cannot have an initializer." }, Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." }, Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." }, Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 466977dee95..b0423b840cc 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -661,14 +661,18 @@ "code": 1184, "isEarly": true }, - "Merge conflict marker encountered.": { + "Modifiers cannot appear here.": { "category": "Error", "code": 1184 }, - "A rest element cannot have an initializer.": { + "Merge conflict marker encountered.": { "category": "Error", "code": 1185 }, + "A rest element cannot have an initializer.": { + "category": "Error", + "code": 1186 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index bb3de86bc7a..b713fddf676 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -268,7 +268,7 @@ module ts { function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration { return forEach(node.members, member => { - if (member.kind === SyntaxKind.Constructor && (member).body) { + if (member.kind === SyntaxKind.Constructor && nodeIsPresent((member).body)) { return member; } }); @@ -1014,20 +1014,20 @@ module ts { } function emitVariableStatement(node: VariableStatement) { - var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration)); + var hasDeclarationWithEmit = forEach(node.declarationList.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration)); if (hasDeclarationWithEmit) { emitJsDocComments(node); emitModuleElementDeclarationFlags(node); - if (isLet(node)) { + if (isLet(node.declarationList)) { write("let "); } - else if (isConst(node)) { + else if (isConst(node.declarationList)) { write("const "); } else { write("var "); } - emitCommaList(node.declarations, emitVariableDeclaration); + emitCommaList(node.declarationList.declarations, emitVariableDeclaration); write(";"); writeLine(); } @@ -2681,20 +2681,22 @@ module ts { var endPos = emitToken(SyntaxKind.ForKeyword, node.pos); write(" "); endPos = emitToken(SyntaxKind.OpenParenToken, endPos); - if (node.declarations) { - if (node.declarations[0] && isLet(node.declarations[0])) { + if (node.initializer && node.initializer.kind === SyntaxKind.VariableDeclarationList) { + var variableDeclarationList = node.initializer; + var declarations = variableDeclarationList.declarations; + if (declarations[0] && isLet(declarations[0])) { emitToken(SyntaxKind.LetKeyword, endPos); } - else if (node.declarations[0] && isConst(node.declarations[0])) { + else if (declarations[0] && isConst(declarations[0])) { emitToken(SyntaxKind.ConstKeyword, endPos); } else { emitToken(SyntaxKind.VarKeyword, endPos); } write(" "); - emitCommaList(node.declarations); + emitCommaList(variableDeclarationList.declarations); } - if (node.initializer) { + else if (node.initializer) { emit(node.initializer); } write(";"); @@ -2709,9 +2711,10 @@ module ts { var endPos = emitToken(SyntaxKind.ForKeyword, node.pos); write(" "); endPos = emitToken(SyntaxKind.OpenParenToken, endPos); - if (node.declarations) { - if (node.declarations.length >= 1) { - var decl = node.declarations[0]; + if (node.initializer.kind === SyntaxKind.VariableDeclarationList) { + var variableDeclarationList = node.initializer; + if (variableDeclarationList.declarations.length >= 1) { + var decl = variableDeclarationList.declarations[0]; if (isLet(decl)) { emitToken(SyntaxKind.LetKeyword, endPos); } @@ -2723,7 +2726,7 @@ module ts { } } else { - emit(node.variable); + emit(node.initializer); } write(" in "); emit(node.expression); @@ -2840,7 +2843,7 @@ module ts { function emitModuleMemberName(node: Declaration) { emitStart(node.name); - if (node.flags & NodeFlags.Export) { + if (getCombinedNodeFlags(node) & NodeFlags.Export) { var container = getContainingModule(node); write(container ? resolver.getLocalNameOfContainer(container) : "exports"); write("."); @@ -2853,7 +2856,7 @@ module ts { var emitCount = 0; // An exported declaration is actually emitted as an assignment (to a property on the module object), so // temporary variables in an exported declaration need to have real declarations elsewhere - var isDeclaration = (root.kind === SyntaxKind.VariableDeclaration && !(root.flags & NodeFlags.Export)) || root.kind === SyntaxKind.Parameter; + var isDeclaration = (root.kind === SyntaxKind.VariableDeclaration && !(getCombinedNodeFlags(root) & NodeFlags.Export)) || root.kind === SyntaxKind.Parameter; if (root.kind === SyntaxKind.BinaryExpression) { emitAssignmentExpression(root); } @@ -3086,17 +3089,17 @@ module ts { function emitVariableStatement(node: VariableStatement) { emitLeadingComments(node); if (!(node.flags & NodeFlags.Export)) { - if (isLet(node)) { + if (isLet(node.declarationList)) { write("let "); } - else if (isConst(node)) { + else if (isConst(node.declarationList)) { write("const "); } else { write("var "); } } - emitCommaList(node.declarations); + emitCommaList(node.declarationList.declarations); write(";"); emitTrailingComments(node); } @@ -3204,7 +3207,7 @@ module ts { } function emitFunctionDeclaration(node: FunctionLikeDeclaration) { - if (!node.body) { + if (nodeIsMissing(node.body)) { return emitPinnedOrTripleSlashComments(node); } @@ -3922,6 +3925,7 @@ module ts { if (!node) { return; } + if (node.flags & NodeFlags.Ambient) { return emitPinnedOrTripleSlashComments(node); } @@ -4014,8 +4018,6 @@ module ts { case SyntaxKind.OmittedExpression: return; case SyntaxKind.Block: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: return emitBlock(node); case SyntaxKind.VariableStatement: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b3d4cb5614c..1fb6c17b565 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -154,8 +154,6 @@ module ts { case SyntaxKind.SpreadElementExpression: return child((node).expression); case SyntaxKind.Block: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: return children((node).statements); case SyntaxKind.SourceFile: @@ -163,7 +161,9 @@ module ts { child((node).endOfFileToken); case SyntaxKind.VariableStatement: return children(node.modifiers) || - children((node).declarations); + child((node).declarationList); + case SyntaxKind.VariableDeclarationList: + return children((node).declarations); case SyntaxKind.ExpressionStatement: return child((node).expression); case SyntaxKind.IfStatement: @@ -177,14 +177,12 @@ module ts { return child((node).expression) || child((node).statement); case SyntaxKind.ForStatement: - return children((node).declarations) || - child((node).initializer) || + return child((node).initializer) || child((node).condition) || child((node).iterator) || child((node).statement); case SyntaxKind.ForInStatement: - return children((node).declarations) || - child((node).variable) || + return child((node).initializer) || child((node).expression) || child((node).statement); case SyntaxKind.ContinueStatement: @@ -435,15 +433,147 @@ module ts { function isUseStrictPrologueDirective(sourceFile: SourceFile, node: Node): boolean { Debug.assert(isPrologueDirective(node)); var nodeText = getSourceTextOfNodeFromSourceFile(sourceFile,(node).expression); + + // Note: the node text must be exactly "use strict" or 'use strict'. It is not ok for the + // string to contain unicode escapes (as per ES5). return nodeText === '"use strict"' || nodeText === "'use strict'"; } + interface IncrementalElement extends TextRange { + parent?: Node; + intersectsChange: boolean + length?: number; + _children: Node[]; + } + + interface IncrementalNode extends Node, IncrementalElement { + } + + interface IncrementalNodeArray extends NodeArray, IncrementalElement { + length: number + } + + // Allows finding nodes in the source file at a certain position in an efficient manner. + // The implementation takes advantage of the calling pattern it knows the parser will + // make in order to optimize finding nodes as quickly as possible. + interface SyntaxCursor { + currentNode(position: number): IncrementalNode; + } + + const enum InvalidPosition { + Value = -1 + } + + function createSyntaxCursor(sourceFile: SourceFile): SyntaxCursor { + var currentArray: NodeArray = sourceFile.statements; + var currentArrayIndex = 0; + + Debug.assert(currentArrayIndex < currentArray.length); + var current = currentArray[currentArrayIndex]; + var lastQueriedPosition = InvalidPosition.Value; + + return { + currentNode(position: number) { + // Only compute the current node if the position is different than the last time + // we were asked. The parser commonly asks for the node at the same position + // twice. Once to know if can read an appropriate list element at a certain point, + // and then to actually read and consume the node. + if (position !== lastQueriedPosition) { + // Much of the time the parser will need the very next node in the array that + // we just returned a node from.So just simply check for that case and move + // forward in the array instead of searching for the node again. + if (current && current.end === position && currentArrayIndex < currentArray.length) { + currentArrayIndex++; + current = currentArray[currentArrayIndex]; + } + + // If we don't have a node, or the node we have isn't in the right position, + // then try to find a viable node at the position requested. + if (!current || current.pos !== position) { + findHighestListElementThatStartsAtPosition(position); + } + } + + // Cache this query so that we don't do any extra work if the parser calls back + // into us. Note: this is very common as the parser will make pairs of calls like + // 'isListElement -> parseListElement'. If we were unable to find a node when + // called with 'isListElement', we don't want to redo the work when parseListElement + // is called immediately after. + lastQueriedPosition = position; + + // Either we don'd have a node, or we have a node at the position being asked for. + Debug.assert(!current || current.pos === position); + return current; + } + }; + + // Finds the highest element in the tree we can find that starts at the provided position. + // The element must be a direct child of some node list in the tree. This way after we + // return it, we can easily return its next sibling in the list. + function findHighestListElementThatStartsAtPosition(position: number) { + // Clear out any cached state about the last node we found. + currentArray = undefined; + currentArrayIndex = InvalidPosition.Value; + current = undefined; + + // Recurse into the source file to find the highest node at this position. + forEachChild(sourceFile, visitNode, visitArray); + + function visitNode(node: Node) { + if (position >= node.pos && position < node.end) { + // Position was within this node. Keep searching deeper to find the node. + forEachChild(node, visitNode, visitArray); + + // don't procede any futher in the search. + return true; + } + + // position wasn't in this node, have to keep searching. + return false; + } + + function visitArray(array: NodeArray) { + if (position >= array.pos && position < array.end) { + // position was in this array. Search through this array to see if we find a + // viable element. + for (var i = 0, n = array.length; i < n; i++) { + var child = array[i]; + if (child) { + if (child.pos === position) { + // Found the right node. We're done. + currentArray = array; + currentArrayIndex = i; + current = child; + return true; + } + else { + if (child.pos < position && position < child.end) { + // Position in somewhere within this child. Search in it and + // stop searching in this array. + forEachChild(child, visitNode, visitArray); + return true; + } + } + } + } + } + + // position wasn't in this array, have to keep searching. + return false; + } + } + } + export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile { var parsingContext: ParsingContext; - var identifiers: Map = {}; + var identifiers: Map; var identifierCount = 0; var nodeCount = 0; var lineStarts: number[]; + var syntacticDiagnostics: Diagnostic[]; + var scanner: Scanner; + var token: SyntaxKind; + var syntaxCursor: SyntaxCursor; // Flags that dictate what parsing context we're in. For example: // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is @@ -491,7 +621,7 @@ module ts { // Note: it should not be necessary to save/restore these flags during speculative/lookahead // parsing. These context flags are naturally stored and restored through normal recursive // descent parsing and unwinding. - var contextFlags: ParserContextFlags = 0; + var contextFlags: ParserContextFlags; // Whether or not we've had a parse error since creating the last AST node. If we have // encountered an error, it will be stored on the next AST node we create. Parse errors @@ -520,47 +650,406 @@ module ts { // // Note: any errors at the end of the file that do not precede a regular node, should get // attached to the EOF token. - var parseErrorBeforeNextFinishedNode = false; + var parseErrorBeforeNextFinishedNode: boolean; - var sourceFile = createNode(SyntaxKind.SourceFile, 0); - if (fileExtensionIs(filename, ".d.ts")) { - sourceFile.flags = NodeFlags.DeclarationFile; - } - sourceFile.end = sourceText.length; - sourceFile.filename = normalizePath(filename); - sourceFile.text = sourceText; + var sourceFile: SourceFile; - sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition; - sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter; - sourceFile.getLineStarts = getLineStarts; - sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics; + return parseSourceFile(sourceText, setParentNodes); - sourceFile.referenceDiagnostics = []; - sourceFile.parseDiagnostics = []; - sourceFile.semanticDiagnostics = []; + function parseSourceFile(text: string, setParentNodes: boolean): SourceFile { + // Set our initial state before parsing. + sourceText = text; + parsingContext = 0; + identifiers = {}; + lineStarts = undefined; + syntacticDiagnostics = undefined; + contextFlags = 0; + parseErrorBeforeNextFinishedNode = false; - processReferenceComments(); + sourceFile = createNode(SyntaxKind.SourceFile, 0); + sourceFile.referenceDiagnostics = []; + sourceFile.parseDiagnostics = []; + sourceFile.semanticDiagnostics = []; - // Create and prime the scanner before parsing the source elements. - var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError); - var token = nextToken(); + // Create and prime the scanner before parsing the source elements. + scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError); + token = nextToken(); - sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); - Debug.assert(token === SyntaxKind.EndOfFileToken); - sourceFile.endOfFileToken = parseTokenNode(); + sourceFile.flags = fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0; + sourceFile.end = sourceText.length; + sourceFile.filename = normalizePath(filename); + sourceFile.text = sourceText; - sourceFile.externalModuleIndicator = getExternalModuleIndicator(); + sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition; + sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter; + sourceFile.getLineStarts = getLineStarts; + sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics; + sourceFile.update = update; - sourceFile.nodeCount = nodeCount; - sourceFile.identifierCount = identifierCount; - sourceFile.languageVersion = languageVersion; - sourceFile.identifiers = identifiers; + processReferenceComments(sourceFile); - if (setParentNodes) { - fixupParentReferences(sourceFile); + sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); + Debug.assert(token === SyntaxKind.EndOfFileToken); + sourceFile.endOfFileToken = parseTokenNode(); + + setExternalModuleIndicator(sourceFile); + + sourceFile.nodeCount = nodeCount; + sourceFile.identifierCount = identifierCount; + sourceFile.languageVersion = languageVersion; + sourceFile.identifiers = identifiers; + + if (setParentNodes) { + fixupParentReferences(sourceFile); + } + + return sourceFile; } - return sourceFile; + function update(newText: string, textChangeRange: TextChangeRange) { + if (textChangeRangeIsUnchanged(textChangeRange)) { + // if the text didn't change, then we can just return our current source file as-is. + return sourceFile; + } + + if (sourceFile.statements.length === 0) { + // If we don't have any statements in the current source file, then there's no real + // way to incrementally parse. So just do a full parse instead. + return parseSourceFile(newText, /*setNodeParents*/ true); + } + + syntaxCursor = createSyntaxCursor(sourceFile); + + // Make the actual change larger so that we know to reparse anything whose lookahead + // might have intersected the change. + var changeRange = extendToAffectedRange(textChangeRange); + + // The is the amount the nodes after the edit range need to be adjusted. It can be + // positive (if the edit added characters), negative (if the edit deleted characters) + // or zero (if this was a pure overwrite with nothing added/removed). + var delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; + + // If we added or removed characters during the edit, then we need to go and adjust all + // the nodes after the edit. Those nodes may move forward down (if we inserted chars) + // or they may move backward (if we deleted chars). + // + // Doing this helps us out in two ways. First, it means that any nodes/tokens we want + // to reuse are already at the appropriate position in the new text. That way when we + // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes + // it very easy to determine if we can reuse a node. If the node's position is at where + // we are in the text, then we can reuse it. Otherwise we can't. If hte node's position + // is ahead of us, then we'll need to rescan tokens. If the node's position is behind + // us, then we'll need to skip it or crumble it as appropriate + // + // We will also adjust the positions of nodes that intersect the change range as well. + // By doing this, we ensure that all the positions in the old tree are consistent, not + // just the positions of nodes entirely before/after the change range. By being + // consistent, we can then easily map from positions to nodes in the old tree easily. + // + // Also, mark any syntax elements that intersect the changed span. We know, up front, + // that we cannot reuse these elements. + updateTokenPositionsAndMarkElements(sourceFile, + changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta); + + // Now that we've set up our internal incremental state just proceed and parse the + // source file in the normal fashion. When possible the parser will retrieve and + // reuse nodes from the old tree. + // + // Note: passing in 'true' for setNodeParents is very important. When incrementally + // parsing, we will be reusing nodes from the old tree, and placing it into new + // parents. If we don't set the parents now, we'll end up with an observably + // inconsistent tree. Setting the parents on the new tree should be very fast. We + // will immediately bail out of walking any subtrees when we can see that their parents + // are already correct. + var result = parseSourceFile(newText, /*setNodeParents*/ true); + + // Clear out the syntax cursor so it doesn't keep anything alive longer than it should. + syntaxCursor = undefined; + + return result; + } + + function updateTokenPositionsAndMarkElements(node: IncrementalNode, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number): void { + visitNode(node); + + function visitNode(child: IncrementalNode) { + if (child.pos > changeRangeOldEnd) { + // Node is entirely past the change range. We need to move both its pos and + // end, forward or backward appropriately. + moveElementEntirelyPastChangeRange(child, delta); + return; + } + + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + var fullEnd = child.end; + if (fullEnd >= changeStart) { + child.intersectsChange = true; + + // Adjust the pos or end (or both) of the intersecting element accordingly. + adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + forEachChild(child, visitNode, visitArray); + return; + } + + // Otherwise, the node is entirely before the change range. No need to do anything with it. + } + + function visitArray(array: IncrementalNodeArray) { + if (array.pos > changeRangeOldEnd) { + // Array is entirely after the change range. We need to move it, and move any of + // its children. + moveElementEntirelyPastChangeRange(array, delta); + } + else { + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + var fullEnd = array.end; + if (fullEnd >= changeStart) { + array.intersectsChange = true; + + // Adjust the pos or end (or both) of the intersecting array accordingly. + adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + for (var i = 0, n = array.length; i < n; i++) { + visitNode(array[i]); + } + } + // else { + // Otherwise, the array is entirely before the change range. No need to do anything with it. + // } + } + } + } + + function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { + Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); + Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + + // We have an element that intersects the change range in some way. It may have its + // start, or its end (or both) in the changed range. We want to adjust any part + // that intersects such that the final tree is in a consistent state. i.e. all + // chlidren have spans within the span of their parent, and all siblings are ordered + // properly. + + // We may need to update both the 'pos' and the 'end' of the element. + + // If the 'pos' is before the start of the change, then we don't need to touch it. + // If it isn't, then the 'pos' must be inside the change. How we update it will + // depend if delta is positive or negative. If delta is positive then we have + // something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that started in the change range to still be + // starting at the same position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that started in the 'X' range will keep its position. + // However any element htat started after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that started in the 'Y' range will + // be adjusted to have their start at the end of the 'Z' range. + // + // The element will keep its position if possible. Or Move backward to the new-end + // if it's in the 'Y' range. + element.pos = Math.min(element.pos, changeRangeNewEnd); + + // If the 'end' is after the change range, then we always adjust it by the delta + // amount. However, if the end is in the change range, then how we adjust it + // will depend on if delta is positive or negative. If delta is positive then we + // have something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that ended inside the change range to keep its + // end position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that ended in the 'X' range will keep its position. + // However any element htat ended after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that ended in the 'Y' range will + // be adjusted to have their end at the end of the 'Z' range. + if (element.end >= changeRangeOldEnd) { + // Element ends after the change range. Always adjust the end pos. + element.end += delta; + } + else { + // Element ends in the change range. The element will keep its position if + // possible. Or Move backward to the new-end if it's in the 'Y' range. + element.end = Math.min(element.end, changeRangeNewEnd); + } + + Debug.assert(element.pos <= element.end); + if (element.parent) { + Debug.assert(element.pos >= element.parent.pos); + Debug.assert(element.end <= element.parent.end); + } + } + + function moveElementEntirelyPastChangeRange(element: IncrementalElement, delta: number) { + if (element.length) { + visitArray(element); + } + else { + visitNode(element); + } + + function visitNode(node: IncrementalNode) { + // Ditch any existing LS children we may have created. This way we can avoid + // moving them forward. + node._children = undefined; + node.pos += delta; + node.end += delta; + + forEachChild(node, visitNode, visitArray); + } + + function visitArray(array: IncrementalNodeArray) { + array.pos += delta; + array.end += delta; + + for (var i = 0, n = array.length; i < n; i++) { + visitNode(array[i]); + } + } + } + + function extendToAffectedRange(changeRange: TextChangeRange): TextChangeRange { + // Consider the following code: + // void foo() { /; } + // + // If the text changes with an insertion of / just before the semicolon then we end up with: + // void foo() { //; } + // + // If we were to just use the changeRange a is, then we would not rescan the { token + // (as it does not intersect the actual original change range). Because an edit may + // change the token touching it, we actually need to look back *at least* one token so + // that the prior token sees that change. + var maxLookahead = 1; + + var start = changeRange.span.start; + + // the first iteration aligns us with the change start. subsequent iteration move us to + // the left by maxLookahead tokens. We only need to do this as long as we're not at the + // start of the tree. + for (var i = 0; start > 0 && i <= maxLookahead; i++) { + var nearestNode = findNearestNodeStartingBeforeOrAtPosition(start); + var position = nearestNode.pos; + + start = Math.max(0, position - 1); + } + + var finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); + var finalLength = changeRange.newLength + (changeRange.span.start - start); + + return createTextChangeRange(finalSpan, finalLength); + } + + function findNearestNodeStartingBeforeOrAtPosition(position: number): Node { + var bestResult: Node = sourceFile; + var lastNodeEntirelyBeforePosition: Node; + + forEachChild(sourceFile, visit); + + if (lastNodeEntirelyBeforePosition) { + var lastChildOfLastEntireNodeBeforePosition = getLastChild(lastNodeEntirelyBeforePosition); + if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { + bestResult = lastChildOfLastEntireNodeBeforePosition; + } + } + + return bestResult; + + function getLastChild(node: Node): Node { + while (true) { + var lastChild = getLastChildWorker(node); + if (lastChild) { + node = lastChild; + } + else { + return node; + } + } + } + + function getLastChildWorker(node: Node): Node { + var last:Node = undefined; + forEachChild(node, child => { + if (nodeIsPresent(child)) { + last = child; + } + }); + return last; + } + + function visit(child: Node) { + if (nodeIsMissing(child)) { + // Missing nodes are effectively invisible to us. We never even consider them + // When trying to find the nearest node before us. + return; + } + + // If the child intersects this position, then this node is currently the nearest + // node that starts before the position. + if (child.pos <= position) { + if (child.pos >= bestResult.pos) { + // This node starts before the position, and is closer to the position than + // the previous best node we found. It is now the new best node. + bestResult = child; + } + + // Now, the node may overlap the position, or it may end entirely before the + // position. If it overlaps with the position, then either it, or one of its + // children must be the nearest node before the position. So we can just + // recurse into this child to see if we can find something better. + if (position < child.end) { + // The nearest node is either this child, or one of the children inside + // of it. We've already marked this child as the best so far. Recurse + // in case one of the children is better. + forEachChild(child, visit); + + // Once we look at the children of this node, then there's no need to + // continue any further. + return true; + } + else { + Debug.assert(child.end <= position); + // The child ends entirely before this position. Say you have the following + // (where $ is the position) + // + // ? $ : <...> <...> + // + // We would want to find the nearest preceding node in "complex expr 2". + // To support that, we keep track of this node, and once we're done searching + // for a best node, we recurse down this node to see if we can find a good + // result in it. + // + // This approach allows us to quickly skip over nodes that are entirely + // before the position, while still allowing us to find any nodes in the + // last one that might be what we want. + lastNodeEntirelyBeforePosition = child; + } + } + else { + Debug.assert(child.pos > position); + // We're now at a node that is entirely past the position we're searching for. + // This node (and all following nodes) could never contribute to the result, + // so just skip them by returning 'true' here. + return true; + } + } + } function setContextFlag(val: Boolean, flag: ParserContextFlags) { if (val) { @@ -682,9 +1171,9 @@ module ts { parseErrorBeforeNextFinishedNode = true; } - function scanError(message: DiagnosticMessage) { + function scanError(message: DiagnosticMessage, length?: number) { var pos = scanner.getTextPos(); - parseErrorAtPosition(pos, 0, message); + parseErrorAtPosition(pos, length || 0, message); } function getNodePos(): number { @@ -777,7 +1266,7 @@ module ts { return inStrictModeContext() ? token > SyntaxKind.LastFutureReservedWord : token > SyntaxKind.LastReservedWord; } - function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): boolean { + function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage): boolean { if (token === kind) { nextToken(); return true; @@ -785,7 +1274,7 @@ module ts { // Report specific message if provided with one. Otherwise, report generic fallback message. if (diagnosticMessage) { - parseErrorAtCurrentToken(diagnosticMessage, arg0); + parseErrorAtCurrentToken(diagnosticMessage); } else { parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); @@ -820,7 +1309,7 @@ module ts { return token === SyntaxKind.CloseBraceToken || token === SyntaxKind.EndOfFileToken || scanner.hasPrecedingLineBreak(); } - function parseSemicolon(diagnosticMessage?: DiagnosticMessage): boolean { + function parseSemicolon(): boolean { if (canParseSemicolon()) { if (token === SyntaxKind.SemicolonToken) { // consume the semicolon if it was explicitly provided. @@ -830,7 +1319,7 @@ module ts { return true; } else { - return parseExpected(SyntaxKind.SemicolonToken, diagnosticMessage); + return parseExpected(SyntaxKind.SemicolonToken); } } @@ -978,14 +1467,19 @@ module ts { } // True if positioned at the start of a list element - function isListElement(kind: ParsingContext, inErrorRecovery: boolean): boolean { - switch (kind) { + function isListElement(parsingContext: ParsingContext, inErrorRecovery: boolean): boolean { + var node = currentNode(parsingContext); + if (node) { + return true; + } + + switch (parsingContext) { case ParsingContext.SourceElements: case ParsingContext.ModuleElements: return isSourceElement(inErrorRecovery); case ParsingContext.BlockStatements: case ParsingContext.SwitchClauseStatements: - return isStatement(inErrorRecovery); + return isStartOfStatement(inErrorRecovery); case ParsingContext.SwitchClauses: return token === SyntaxKind.CaseKeyword || token === SyntaxKind.DefaultKeyword; case ParsingContext.TypeMembers: @@ -1134,7 +1628,7 @@ module ts { while (!isListTerminator(kind)) { if (isListElement(kind, /* inErrorRecovery */ false)) { - var element = parseElement(); + var element = parseListElement(kind, parseElement); result.push(element); // test elements only if we are not already in strict mode @@ -1164,6 +1658,297 @@ module ts { return result; } + function parseListElement(kind: ParsingContext, parseElement: () => T): T { + var node = currentNode(kind); + if (node) { + return consumeNode(node); + } + + return parseElement(); + } + + function currentNode(parsingContext: ParsingContext): Node { + // If there is an outstanding parse error that we've encountered, but not attached to + // some node, then we cannot get a node from the old source tree. This is because we + // want to mark the next node we encounter as being unusable. + // + // Note: This may be too conservative. Perhaps we could reuse hte node and set the bit + // on it (or its leftmost child) as having the error. For now though, being conservative + // is nice and likely won't ever affect perf. + if (parseErrorBeforeNextFinishedNode) { + return undefined; + } + + if (!syntaxCursor) { + // if we don't have a cursor, we could never return a node from the old tree. + return undefined; + } + + var node = syntaxCursor.currentNode(scanner.getStartPos()); + + // Can't reuse a missing node. + if (nodeIsMissing(node)) { + return undefined; + } + + // Can't reuse a node that intersected the change range. + if (node.intersectsChange) { + return undefined; + } + + // Can't reuse a node that contains a parse error. This is necessary so that we + // produce the same set of errors again. + if (containsParseError(node)) { + return undefined; + } + + // We can only reuse a node if it was parsed under the same strict mode that we're + // currently in. i.e. if we originally parsed a node in non-strict mode, but then + // the user added 'using strict' at the top of the file, then we can't use that node + // again as the presense of strict mode may cause us to parse the tokens in the file + // differetly. + // + // Note: we *can* reuse tokens when the strict mode changes. That's because tokens + // are unaffected by strict mode. It's just the parser will decide what to do with it + // differently depending on what mode it is in. + // + // This also applies to all our other context flags as well. + var nodeContextFlags = node.parserContextFlags & ParserContextFlags.ParserGeneratedFlags; + if (nodeContextFlags !== contextFlags) { + return undefined; + } + + // Ok, we have a node that looks like it could be reused. Now verify that it is valid + // in the currest list parsing context that we're currently at. + if (!canReuseNode(node, parsingContext)) { + return undefined; + } + + return node; + } + + function consumeNode(node: Node) { + // Move the scanner so it is after the node we just consumed. + scanner.setTextPos(node.end); + nextToken(); + return node; + } + + function canReuseNode(node: Node, parsingContext: ParsingContext): boolean { + switch (parsingContext) { + case ParsingContext.ModuleElements: + return isReusableModuleElement(node); + + case ParsingContext.ClassMembers: + return isReusableClassMember(node); + + case ParsingContext.SwitchClauses: + return isReusableSwitchClause(node); + + case ParsingContext.BlockStatements: + case ParsingContext.SwitchClauseStatements: + return isReusableStatement(node); + + case ParsingContext.EnumMembers: + return isReusableEnumMember(node); + + case ParsingContext.TypeMembers: + return isReusableTypeMember(node); + + case ParsingContext.VariableDeclarations: + return isReusableVariableDeclaration(node); + + case ParsingContext.Parameters: + return isReusableParameter(node); + + // Any other lists we do not care about reusing nodes in. But feel free to add if + // you can do so safely. Danger areas involve nodes that may involve speculative + // parsing. If speculative parsing is involved with the node, then the range the + // parser reached while looking ahead might be in the edited range (see the example + // in canReuseVariableDeclaratorNode for a good case of this). + case ParsingContext.HeritageClauses: + // This would probably be safe to reuse. There is no speculative parsing with + // heritage clauses. + + case ParsingContext.TypeReferences: + // This would probably be safe to reuse. There is no speculative parsing with + // type names in a heritage clause. There can be generic names in the type + // name list. But because it is a type context, we never use speculative + // parsing on the type argument list. + + case ParsingContext.TypeParameters: + // This would probably be safe to reuse. There is no speculative parsing with + // type parameters. Note that that's because type *parameters* only occur in + // unambiguous *type* contexts. While type *arguments* occur in very ambiguous + // *expression* contexts. + + case ParsingContext.TupleElementTypes: + // This would probably be safe to reuse. There is no speculative parsing with + // tuple types. + + // Technically, type argument list types are probably safe to reuse. While + // speculative parsing is involved with them (since type argument lists are only + // produced from speculative parsing a < as a type argument list), we only have + // the types because speculative parsing succeeded. Thus, the lookahead never + // went past the end of the list and rewound. + case ParsingContext.TypeArguments: + + // Note: these are almost certainly not safe to ever reuse. Expressions commonly + // need a large amount of lookahead, and we should not reuse them as they may + // have actually intersected the edit. + case ParsingContext.ArgumentExpressions: + + // This is not safe to reuse for the same reason as the 'AssignmentExpression' + // cases. i.e. a property assignment may end with an expression, and thus might + // have lookahead far beyond it's old node. + case ParsingContext.ObjectLiteralMembers: + } + + return false; + } + + function isReusableModuleElement(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportAssignment: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + + // Keep in sync with isStatement: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.DebuggerStatement: + return true; + } + } + + return false; + } + + function isReusableClassMember(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.Constructor: + case SyntaxKind.IndexSignature: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertyDeclaration: + return true; + } + } + + return false; + } + + function isReusableSwitchClause(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return true; + } + } + + return false; + } + + function isReusableStatement(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.VariableStatement: + case SyntaxKind.Block: + case SyntaxKind.IfStatement: + case SyntaxKind.ExpressionStatement: + case SyntaxKind.ThrowStatement: + case SyntaxKind.ReturnStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.EmptyStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.LabeledStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.DebuggerStatement: + return true; + } + } + + return false; + } + + function isReusableEnumMember(node: Node) { + return node.kind === SyntaxKind.EnumMember; + } + + function isReusableTypeMember(node: Node) { + if (node) { + switch (node.kind) { + case SyntaxKind.ConstructSignature: + case SyntaxKind.MethodSignature: + case SyntaxKind.IndexSignature: + case SyntaxKind.PropertySignature: + case SyntaxKind.CallSignature: + return true; + } + } + + return false; + } + + function isReusableVariableDeclaration(node: Node) { + if (node.kind !== SyntaxKind.VariableDeclaration) { + return false; + } + + // Very subtle incremental parsing bug. Consider the following code: + // + // var v = new List < A, B + // + // This is actually legal code. It's a list of variable declarators "v = new List() + // + // then we have a problem. "v = new Listnode; + return variableDeclarator.initializer === undefined; + } + + function isReusableParameter(node: Node) { + // TODO: this most likely needs the same initializer check that + // isReusableVariableDeclaration has. + return node.kind === SyntaxKind.Parameter; + } + // Returns true if we should abort parsing. function abortParsingListOrMoveToNextToken(kind: ParsingContext) { parseErrorAtCurrentToken(parsingContextErrors(kind)); @@ -1185,7 +1970,7 @@ module ts { var commaStart = -1; // Meaning the previous token was not a comma while (true) { if (isListElement(kind, /* inErrorRecovery */ false)) { - result.push(parseElement()); + result.push(parseListElement(kind, parseElement)); commaStart = scanner.getTokenPos(); if (parseOptional(SyntaxKind.CommaToken)) { continue; @@ -1626,7 +2411,8 @@ module ts { return token === SyntaxKind.ColonToken || token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBracketToken; } - function parseIndexSignatureDeclaration(fullStart: number, modifiers: ModifiersArray): IndexSignatureDeclaration { + function parseIndexSignatureDeclaration(modifiers: ModifiersArray): IndexSignatureDeclaration { + var fullStart = modifiers ? modifiers.pos : scanner.getStartPos(); var node = createNode(SyntaxKind.IndexSignature, fullStart); setModifiers(node, modifiers); node.parameters = parseBracketedList(ParsingContext.Parameters, parseParameter, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); @@ -1668,10 +2454,25 @@ module ts { case SyntaxKind.OpenBracketToken: // Both for indexers and computed properties return true; default: + if (isModifier(token)) { + var result = lookAhead(isStartOfIndexSignatureDeclaration); + if (result) { + return result; + } + } + return isLiteralPropertyName() && lookAhead(isTypeMemberWithLiteralPropertyName); } } + function isStartOfIndexSignatureDeclaration() { + while (isModifier(token)) { + nextToken(); + } + + return isIndexSignature(); + } + function isTypeMemberWithLiteralPropertyName() { nextToken(); return token === SyntaxKind.OpenParenToken || @@ -1688,7 +2489,9 @@ module ts { return parseSignatureMember(SyntaxKind.CallSignature); case SyntaxKind.OpenBracketToken: // Indexer or computed property - return isIndexSignature() ? parseIndexSignatureDeclaration(scanner.getStartPos(), /*modifiers:*/ undefined) : parsePropertyOrMethodSignature(); + return isIndexSignature() + ? parseIndexSignatureDeclaration(/*modifiers:*/ undefined) + : parsePropertyOrMethodSignature(); case SyntaxKind.NewKeyword: if (lookAhead(isStartOfConstructSignature)) { return parseSignatureMember(SyntaxKind.ConstructSignature); @@ -1698,12 +2501,32 @@ module ts { case SyntaxKind.NumericLiteral: return parsePropertyOrMethodSignature(); default: + // Index declaration as allowed as a type member. But as per the grammar, + // they also allow modifiers. So we have to check for an index declaration + // that might be following modifiers. This ensures that things work properly + // when incrementally parsing as the parser will produce the Index declaration + // if it has the same text regardless of whether it is inside a class or an + // object type. + if (isModifier(token)) { + var result = tryParse(parseIndexSignatureWithModifiers); + if (result) { + return result; + } + } + if (isIdentifierOrKeyword()) { return parsePropertyOrMethodSignature(); } } } + function parseIndexSignatureWithModifiers() { + var modifiers = parseModifiers(); + return isIndexSignature() + ? parseIndexSignatureDeclaration(modifiers) + : undefined; + } + function isStartOfConstructSignature() { nextToken(); return token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken; @@ -2286,7 +3109,7 @@ module ts { return parseFunctionBlock(/*allowYield:*/ false, /* ignoreMissingOpenBrace */ false); } - if (isStatement(/* inErrorRecovery */ true) && !isStartOfExpressionStatement() && token !== SyntaxKind.FunctionKeyword) { + if (isStartOfStatement(/*inErrorRecovery:*/ true) && !isStartOfExpressionStatement() && token !== SyntaxKind.FunctionKeyword) { // Check if we got a plain statement (i.e. no expression-statements, no functions expressions/declarations) // // Here we try to recover from a potential error situation in the case where the @@ -2803,25 +3626,36 @@ module ts { return finishNode(node); } + function tryParseAccessorDeclaration(fullStart: number, modifiers: ModifiersArray): AccessorDeclaration { + if (parseContextualModifier(SyntaxKind.GetKeyword)) { + return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, modifiers); + } + else if (parseContextualModifier(SyntaxKind.SetKeyword)) { + return parseAccessorDeclaration(SyntaxKind.SetAccessor, fullStart, modifiers); + } + + return undefined; + } + function parseObjectLiteralElement(): ObjectLiteralElement { var fullStart = scanner.getStartPos(); - var initialToken = token; + var modifiers = parseModifiers(); - if (parseContextualModifier(SyntaxKind.GetKeyword) || parseContextualModifier(SyntaxKind.SetKeyword)) { - var kind = initialToken === SyntaxKind.GetKeyword ? SyntaxKind.GetAccessor : SyntaxKind.SetAccessor; - return parseAccessorDeclaration(kind, fullStart, /*modifiers*/undefined); + var accessor = tryParseAccessorDeclaration(fullStart, modifiers); + if (accessor) { + return accessor; } var asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); var tokenIsIdentifier = isIdentifier(); var nameToken = token; var propertyName = parsePropertyName(); - if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { - return parseMethodDeclaration(fullStart, /*modifiers:*/ undefined, asteriskToken, propertyName, /*questionToken:*/ undefined, /*requireBlock:*/ true); - } // Disallowing of optional property assignments happens in the grammar checker. var questionToken = parseOptionalToken(SyntaxKind.QuestionToken); + if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { + return parseMethodDeclaration(fullStart, modifiers, asteriskToken, propertyName, questionToken); + } // Parse to check if it is short-hand property assignment or normal property assignment if ((token === SyntaxKind.CommaToken || token === SyntaxKind.CloseBraceToken) && tokenIsIdentifier) { @@ -2883,9 +3717,9 @@ module ts { } // STATEMENTS - function parseBlock(kind: SyntaxKind, ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean): Block { - var node = createNode(kind); - if (parseExpected(SyntaxKind.OpenBraceToken) || ignoreMissingOpenBrace) { + function parseBlock(ignoreMissingOpenBrace: boolean, checkForStrictMode: boolean, diagnosticMessage?: DiagnosticMessage): Block { + var node = createNode(SyntaxKind.Block); + if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) { node.statements = parseList(ParsingContext.BlockStatements, checkForStrictMode, parseStatement); parseExpected(SyntaxKind.CloseBraceToken); } @@ -2895,11 +3729,11 @@ module ts { return finishNode(node); } - function parseFunctionBlock(allowYield: boolean, ignoreMissingOpenBrace: boolean): Block { + function parseFunctionBlock(allowYield: boolean, ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { var savedYieldContext = inYieldContext(); setYieldContext(allowYield); - var block = parseBlock(SyntaxKind.Block, ignoreMissingOpenBrace, /*checkForStrictMode*/ true); + var block = parseBlock(ignoreMissingOpenBrace, /*checkForStrictMode*/ true, diagnosticMessage); setYieldContext(savedYieldContext); @@ -2954,42 +3788,27 @@ module ts { var pos = getNodePos(); parseExpected(SyntaxKind.ForKeyword); parseExpected(SyntaxKind.OpenParenToken); + + var initializer: VariableDeclarationList | Expression = undefined; if (token !== SyntaxKind.SemicolonToken) { - if (parseOptional(SyntaxKind.VarKeyword)) { - var declarations = disallowInAnd(parseVariableDeclarationList); - } - else if (parseOptional(SyntaxKind.LetKeyword)) { - var declarations = setFlag(disallowInAnd(parseVariableDeclarationList), NodeFlags.Let); - } - else if (parseOptional(SyntaxKind.ConstKeyword)) { - var declarations = setFlag(disallowInAnd(parseVariableDeclarationList), NodeFlags.Const); + if (token === SyntaxKind.VarKeyword || token === SyntaxKind.LetKeyword || token === SyntaxKind.ConstKeyword) { + initializer = parseVariableDeclarationList(/*disallowIn:*/ true); } else { - var varOrInit = disallowInAnd(parseExpression); + initializer = disallowInAnd(parseExpression); } } var forOrForInStatement: IterationStatement; if (parseOptional(SyntaxKind.InKeyword)) { var forInStatement = createNode(SyntaxKind.ForInStatement, pos); - if (declarations) { - forInStatement.declarations = declarations; - } - else { - forInStatement.variable = varOrInit; - } + forInStatement.initializer = initializer; forInStatement.expression = allowInAnd(parseExpression); parseExpected(SyntaxKind.CloseParenToken); forOrForInStatement = forInStatement; } else { var forStatement = createNode(SyntaxKind.ForStatement, pos); - if (declarations) { - forStatement.declarations = declarations; - } - if (varOrInit) { - forStatement.initializer = varOrInit; - } - + forStatement.initializer = initializer; parseExpected(SyntaxKind.SemicolonToken); if (token !== SyntaxKind.SemicolonToken && token !== SyntaxKind.CloseParenToken) { forStatement.condition = allowInAnd(parseExpression); @@ -3093,25 +3912,19 @@ module ts { // TODO: Review for error recovery function parseTryStatement(): TryStatement { var node = createNode(SyntaxKind.TryStatement); - node.tryBlock = parseTokenAndBlock(SyntaxKind.TryKeyword); + + parseExpected(SyntaxKind.TryKeyword); + node.tryBlock = parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode*/ false); node.catchClause = token === SyntaxKind.CatchKeyword ? parseCatchClause() : undefined; // If we don't have a catch clause, then we must have a finally clause. Try to parse // one out no matter what. - node.finallyBlock = !node.catchClause || token === SyntaxKind.FinallyKeyword - ? parseTokenAndBlock(SyntaxKind.FinallyKeyword) - : undefined; - return finishNode(node); - } + if (!node.catchClause || token === SyntaxKind.FinallyKeyword) { + parseExpected(SyntaxKind.FinallyKeyword); + node.finallyBlock = parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode*/ false); + } - function parseTokenAndBlock(token: SyntaxKind): Block { - var pos = getNodePos(); - parseExpected(token); - var result = parseBlock( - token === SyntaxKind.TryKeyword ? SyntaxKind.TryBlock : SyntaxKind.FinallyBlock, - /* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); - result.pos = pos; - return result; + return finishNode(node); } function parseCatchClause(): CatchClause { @@ -3121,7 +3934,7 @@ module ts { result.name = parseIdentifier(); result.type = parseTypeAnnotation(); parseExpected(SyntaxKind.CloseParenToken); - result.block = parseBlock(SyntaxKind.Block, /* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); + result.block = parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode:*/ false); return finishNode(result); } @@ -3153,7 +3966,19 @@ module ts { } } - function isStatement(inErrorRecovery: boolean): boolean { + function isStartOfStatement(inErrorRecovery: boolean): boolean { + // Functions and variable statements are allowed as a statement. But as per the grammar, + // they also allow modifiers. So we have to check for those statements that might be + // following modifiers.This ensures that things work properly when incrementally parsing + // as the parser will produce the same FunctionDeclaraiton or VariableStatement if it has + // the same text regardless of whether it is inside a block or not. + if (isModifier(token)) { + var result = lookAhead(parseVariableStatementOrFunctionDeclarationWithModifiers); + if (result) { + return true; + } + } + switch (token) { case SyntaxKind.SemicolonToken: // If we're in error recovery, then we don't want to treat ';' as an empty statement. @@ -3228,7 +4053,7 @@ module ts { function parseStatement(): Statement { switch (token) { case SyntaxKind.OpenBraceToken: - return parseBlock(SyntaxKind.Block, /* ignoreMissingOpenBrace */ false, /*checkForStrictMode*/ false); + return parseBlock(/*ignoreMissingOpenBrace:*/ false, /*checkForStrictMode:*/ false); case SyntaxKind.VarKeyword: case SyntaxKind.ConstKeyword: // const here should always be parsed as const declaration because of check in 'isStatement' @@ -3271,19 +4096,58 @@ module ts { } // Else parse it like identifier - fall through default: + // Functions and variable statements are allowed as a statement. But as per + // the grammar, they also allow modifiers. So we have to check for those + // statements that might be following modifiers. This ensures that things + // work properly when incrementally parsing as the parser will produce the + // same FunctionDeclaraiton or VariableStatement if it has the same text + // regardless of whether it is inside a block or not. + if (isModifier(token)) { + var result = tryParse(parseVariableStatementOrFunctionDeclarationWithModifiers); + if (result) { + return result; + } + } + return parseExpressionOrLabeledStatement(); } } - function parseFunctionBlockOrSemicolon(isGenerator: boolean): Block { - if (token === SyntaxKind.OpenBraceToken) { - return parseFunctionBlock(isGenerator, /*ignoreMissingOpenBrace:*/ false); + function parseVariableStatementOrFunctionDeclarationWithModifiers(): FunctionDeclaration | VariableStatement { + var start = scanner.getStartPos(); + var modifiers = parseModifiers(); + switch (token) { + case SyntaxKind.ConstKeyword: + var nextTokenIsEnum = lookAhead(nextTokenIsEnumKeyword) + if (nextTokenIsEnum) { + return undefined; + } + return parseVariableStatement(start, modifiers); + + case SyntaxKind.LetKeyword: + if (!isLetDeclaration()) { + return undefined; + } + return parseVariableStatement(start, modifiers); + + case SyntaxKind.VarKeyword: + return parseVariableStatement(start, modifiers); + case SyntaxKind.FunctionKeyword: + return parseFunctionDeclaration(start, modifiers); } - parseSemicolon(Diagnostics.or_expected); return undefined; } + function parseFunctionBlockOrSemicolon(isGenerator: boolean, diagnosticMessage?: DiagnosticMessage): Block { + if (token !== SyntaxKind.OpenBraceToken && canParseSemicolon()) { + parseSemicolon(); + return; + } + + return parseFunctionBlock(isGenerator, /*ignoreMissingOpenBrace:*/ false, diagnosticMessage); + } + // DECLARATIONS function parseArrayBindingElement(): BindingElement { @@ -3351,39 +4215,37 @@ module ts { return finishNode(node); } - function setFlag(nodes: NodeArray, flag: NodeFlags): NodeArray { - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - node.flags |= flag; - if (node.name && isBindingPattern(node.name)) { - setFlag((node.name).elements, flag); - } - } - return nodes; - } + function parseVariableDeclarationList(disallowIn: boolean): VariableDeclarationList { + var node = createNode(SyntaxKind.VariableDeclarationList); - function parseVariableDeclarationList(): NodeArray { - return parseDelimitedList(ParsingContext.VariableDeclarations, parseVariableDeclaration); + switch (token) { + case SyntaxKind.VarKeyword: + break; + case SyntaxKind.LetKeyword: + node.flags |= NodeFlags.Let; + break; + case SyntaxKind.ConstKeyword: + node.flags |= NodeFlags.Const; + break; + default: + Debug.fail(); + } + + nextToken(); + var savedDisallowIn = inDisallowInContext(); + setDisallowInContext(disallowIn); + + node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, parseVariableDeclaration); + + setDisallowInContext(savedDisallowIn); + + return finishNode(node); } function parseVariableStatement(fullStart: number, modifiers: ModifiersArray): VariableStatement { var node = createNode(SyntaxKind.VariableStatement, fullStart); setModifiers(node, modifiers); - - if (token === SyntaxKind.LetKeyword) { - node.flags |= NodeFlags.Let; - } - else if (token === SyntaxKind.ConstKeyword) { - node.flags |= NodeFlags.Const; - } - else { - Debug.assert(token === SyntaxKind.VarKeyword); - } - - nextToken(); - node.declarations = allowInAnd(parseVariableDeclarationList); - setFlag(node.declarations, node.flags); - + node.declarationList = parseVariableDeclarationList(/*disallowIn:*/ false); parseSemicolon(); return finishNode(node); } @@ -3395,7 +4257,7 @@ module ts { node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); node.name = parseIdentifier(); fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!node.asteriskToken, /*requireCompleteParameterList:*/ false, node); - node.body = parseFunctionBlockOrSemicolon(!!node.asteriskToken); + node.body = parseFunctionBlockOrSemicolon(!!node.asteriskToken, Diagnostics.or_expected); return finishNode(node); } @@ -3404,18 +4266,18 @@ module ts { setModifiers(node, modifiers); parseExpected(SyntaxKind.ConstructorKeyword); fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ false, /*requireCompleteParameterList:*/ false, node); - node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false); + node.body = parseFunctionBlockOrSemicolon(/*isGenerator:*/ false, Diagnostics.or_expected); return finishNode(node); } - function parseMethodDeclaration(fullStart: number, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, requireBlock: boolean): MethodDeclaration { + function parseMethodDeclaration(fullStart: number, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { var method = createNode(SyntaxKind.MethodDeclaration, fullStart); setModifiers(method, modifiers); method.asteriskToken = asteriskToken; method.name = name; method.questionToken = questionToken; fillSignature(SyntaxKind.ColonToken, /*yieldAndGeneratorParameterContext:*/ !!asteriskToken, /*requireCompleteParameterList:*/ false, method); - method.body = requireBlock ? parseFunctionBlock(!!asteriskToken, /*ignoreMissingOpenBrace:*/ false) : parseFunctionBlockOrSemicolon(!!asteriskToken); + method.body = parseFunctionBlockOrSemicolon(!!asteriskToken, diagnosticMessage); return finishNode(method); } @@ -3427,7 +4289,7 @@ module ts { // report an error in the grammar checker. var questionToken = parseOptionalToken(SyntaxKind.QuestionToken); if (asteriskToken || token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) { - return parseMethodDeclaration(fullStart, modifiers, asteriskToken, name, questionToken, /*requireBlock:*/ false); + return parseMethodDeclaration(fullStart, modifiers, asteriskToken, name, questionToken, Diagnostics.or_expected); } else { var property = createNode(SyntaxKind.PropertyDeclaration, fullStart); @@ -3536,22 +4398,28 @@ module ts { function parseClassElement(): ClassElement { var fullStart = getNodePos(); var modifiers = parseModifiers(); - if (parseContextualModifier(SyntaxKind.GetKeyword)) { - return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, modifiers); - } - if (parseContextualModifier(SyntaxKind.SetKeyword)) { - return parseAccessorDeclaration(SyntaxKind.SetAccessor, fullStart, modifiers); + + var accessor = tryParseAccessorDeclaration(fullStart, modifiers); + if (accessor) { + return accessor; } + if (token === SyntaxKind.ConstructorKeyword) { return parseConstructorDeclaration(fullStart, modifiers); } + if (isIndexSignature()) { - return parseIndexSignatureDeclaration(fullStart, modifiers); + return parseIndexSignatureDeclaration(modifiers); } + // It is very important that we check this *after* checking indexers because // the [ token can start an index signature or a computed property name - if (isIdentifierOrKeyword() || token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral || - token === SyntaxKind.AsteriskToken || token === SyntaxKind.OpenBracketToken) { + if (isIdentifierOrKeyword() || + token === SyntaxKind.StringLiteral || + token === SyntaxKind.NumericLiteral || + token === SyntaxKind.AsteriskToken || + token === SyntaxKind.OpenBracketToken) { + return parsePropertyOrMethodDeclaration(fullStart, modifiers); } @@ -3857,7 +4725,7 @@ module ts { } function isSourceElement(inErrorRecovery: boolean): boolean { - return isDeclarationStart() || isStatement(inErrorRecovery); + return isDeclarationStart() || isStartOfStatement(inErrorRecovery); } function parseSourceElement() { @@ -3874,7 +4742,7 @@ module ts { : parseStatement(); } - function processReferenceComments(): void { + function processReferenceComments(sourceFile: SourceFile): void { var triviaScanner = createScanner(languageVersion, /*skipTrivia*/false, sourceText); var referencedFiles: FileReference[] = []; var amdDependencies: string[] = []; @@ -3930,16 +4798,15 @@ module ts { sourceFile.amdModuleName = amdModuleName; } - function getExternalModuleIndicator() { - return forEach(sourceFile.statements, node => + function setExternalModuleIndicator(sourceFile: SourceFile) { + sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node => node.flags & NodeFlags.Export || node.kind === SyntaxKind.ImportDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference || node.kind === SyntaxKind.ExportAssignment - ? node - : undefined); + ? node + : undefined); } - var syntacticDiagnostics: Diagnostic[]; function getSyntacticDiagnostics() { if (syntacticDiagnostics === undefined) { // Don't bother doing any grammar checks if there are already parser errors. diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 9853e22d9f1..1c4dc094b25 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -5,7 +5,7 @@ module ts { export interface ErrorCallback { - (message: DiagnosticMessage): void; + (message: DiagnosticMessage, length: number): void; } export interface CommentCallback { @@ -392,24 +392,24 @@ module ts { } } + // All conflict markers consist of the same character repeated seven times. If it is + // a <<<<<<< or >>>>>>> marker then it is also followd by a space. + var mergeConflictMarkerLength = "<<<<<<<".length; + function isConflictMarkerTrivia(text: string, pos: number) { // Conflict markers must be at the start of a line. if (pos > 0 && isLineBreak(text.charCodeAt(pos - 1))) { var ch = text.charCodeAt(pos); - // All conflict markers consist of the same character repeated seven times. If it is - // a <<<<<<< or >>>>>>> marker then it is also followd by a space. - var markerLength = "<<<<<<<".length; - - if ((pos + markerLength) < text.length) { - for (var i = 0, n = markerLength; i < n; i++) { + if ((pos + mergeConflictMarkerLength) < text.length) { + for (var i = 0, n = mergeConflictMarkerLength; i < n; i++) { if (text.charCodeAt(pos + i) !== ch) { return false; } } return ch === CharacterCodes.equals || - text.charCodeAt(pos + markerLength) === CharacterCodes.space; + text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space; } } @@ -529,9 +529,9 @@ module ts { var precedingLineBreak: boolean; var tokenIsUnterminated: boolean; - function error(message: DiagnosticMessage): void { + function error(message: DiagnosticMessage, length?: number): void { if (onError) { - onError(message); + onError(message, length || 0); } } @@ -1058,7 +1058,7 @@ module ts { return pos++, token = SyntaxKind.SemicolonToken; case CharacterCodes.lessThan: if (isConflictMarkerTrivia(text, pos)) { - error(Diagnostics.Merge_conflict_marker_encountered); + mergeConflictError(); pos = scanConflictMarkerTrivia(text, pos); if (skipTrivia) { continue; @@ -1080,7 +1080,7 @@ module ts { return pos++, token = SyntaxKind.LessThanToken; case CharacterCodes.equals: if (isConflictMarkerTrivia(text, pos)) { - error(Diagnostics.Merge_conflict_marker_encountered); + mergeConflictError(); pos = scanConflictMarkerTrivia(text, pos); if (skipTrivia) { continue; @@ -1102,7 +1102,7 @@ module ts { return pos++, token = SyntaxKind.EqualsToken; case CharacterCodes.greaterThan: if (isConflictMarkerTrivia(text, pos)) { - error(Diagnostics.Merge_conflict_marker_encountered); + mergeConflictError(); pos = scanConflictMarkerTrivia(text, pos); if (skipTrivia) { continue; @@ -1172,6 +1172,10 @@ module ts { } } + function mergeConflictError() { + error(Diagnostics.Merge_conflict_marker_encountered, mergeConflictMarkerLength); + } + function reScanGreaterToken(): SyntaxKind { if (token === SyntaxKind.GreaterThanToken) { if (text.charCodeAt(pos) === CharacterCodes.greaterThan) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f3c87ceb689..5236d022b07 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -218,10 +218,9 @@ module ts { LabeledStatement, ThrowStatement, TryStatement, - TryBlock, - FinallyBlock, DebuggerStatement, VariableDeclaration, + VariableDeclarationList, FunctionDeclaration, ClassDeclaration, InterfaceDeclaration, @@ -284,18 +283,18 @@ module ts { } export const enum NodeFlags { - Export = 0x00000001, // Declarations - Ambient = 0x00000002, // Declarations - Public = 0x00000010, // Property/Method - Private = 0x00000020, // Property/Method - Protected = 0x00000040, // Property/Method - Static = 0x00000080, // Property/Method - MultiLine = 0x00000100, // Multi-line array or object literal - Synthetic = 0x00000200, // Synthetic node (for full fidelity) - DeclarationFile = 0x00000400, // Node is a .d.ts file - Let = 0x00000800, // Variable declaration - Const = 0x00001000, // Variable declaration - OctalLiteral = 0x00002000, + Export = 0x00000001, // Declarations + Ambient = 0x00000002, // Declarations + Public = 0x00000010, // Property/Method + Private = 0x00000020, // Property/Method + Protected = 0x00000040, // Property/Method + Static = 0x00000080, // Property/Method + MultiLine = 0x00000100, // Multi-line array or object literal + Synthetic = 0x00000200, // Synthetic node (for full fidelity) + DeclarationFile = 0x00000400, // Node is a .d.ts file + Let = 0x00000800, // Variable declaration + Const = 0x00001000, // Variable declaration + OctalLiteral = 0x00002000, Modifier = Export | Ambient | Public | Private | Protected | Static, AccessibilityModifier = Public | Private | Protected, @@ -396,11 +395,16 @@ module ts { // SyntaxKind.VariableDeclaration export interface VariableDeclaration extends Declaration { + parent?: VariableDeclarationList; name: Identifier | BindingPattern; // Declared variable name type?: TypeNode; // Optional type annotation initializer?: Expression; // Optional initializer } + export interface VariableDeclarationList extends Node { + declarations: NodeArray; + } + // SyntaxKind.Parameter export interface ParameterDeclaration extends Declaration { dotDotDotToken?: Node; // Present on rest parameter @@ -606,7 +610,7 @@ module ts { export interface VoidExpression extends UnaryExpression { expression: UnaryExpression; } - + export interface YieldExpression extends Expression { asteriskToken?: Node; expression: Expression; @@ -709,7 +713,7 @@ module ts { } export interface VariableStatement extends Statement { - declarations: NodeArray; + declarationList: VariableDeclarationList; } export interface ExpressionStatement extends Statement { @@ -735,15 +739,13 @@ module ts { } export interface ForStatement extends IterationStatement { - declarations?: NodeArray; - initializer?: Expression; + initializer?: VariableDeclarationList | Expression; condition?: Expression; iterator?: Expression; } export interface ForInStatement extends IterationStatement { - declarations?: NodeArray; - variable?: Expression; + initializer: VariableDeclarationList | Expression; expression: Expression; } @@ -881,9 +883,22 @@ module ts { filename: string; text: string; + getLineAndCharacterFromPosition(position: number): LineAndCharacter; getPositionFromLineAndCharacter(line: number, character: number): number; getLineStarts(): number[]; + + // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter + // indicates what changed between the 'text' that this SourceFile has and the 'newText'. + // The SourceFile will be created with the compiler attempting to reuse as many nodes from + // this file as possible. + // + // Note: this function mutates nodes from this SourceFile. That means any existing nodes + // from this SourceFile that are being held onto may change as a result (including + // becoming detached from any SourceFile). It is recommended that this SourceFile not + // be used once 'update' is called on it. + update(newText: string, textChangeRange: TextChangeRange): SourceFile; + amdDependencies: string[]; amdModuleName: string; referencedFiles: FileReference[]; @@ -1030,7 +1045,7 @@ module ts { } export const enum TypeFormatFlags { - None = 0x00000000, + None = 0x00000000, WriteArrayAsGenericType = 0x00000001, // Write Array instead T[] UseTypeOfFunction = 0x00000002, // Write typeof instead of function type literal NoTruncation = 0x00000004, // Don't truncate typeToString result @@ -1041,14 +1056,18 @@ module ts { } export const enum SymbolFormatFlags { - None = 0x00000000, - WriteTypeParametersOrArguments = 0x00000001, // Write symbols's type argument if it is instantiated symbol - // eg. class C { p: T } <-- Show p as C.p here - // var a: C; - // var p = a.p; <--- Here p is property of C so show it as C.p instead of just C.p - UseOnlyExternalAliasing = 0x00000002, // Use only external alias information to get the symbol name in the given context - // eg. module m { export class c { } } import x = m.c; - // When this flag is specified m.c will be used to refer to the class instead of alias symbol x + None = 0x00000000, + + // Write symbols's type argument if it is instantiated symbol + // eg. class C { p: T } <-- Show p as C.p here + // var a: C; + // var p = a.p; <--- Here p is property of C so show it as C.p instead of just C.p + WriteTypeParametersOrArguments = 0x00000001, + + // Use only external alias information to get the symbol name in the given context + // eg. module m { export class c { } } import x = m.c; + // When this flag is specified m.c will be used to refer to the class instead of alias symbol x + UseOnlyExternalAliasing = 0x00000002, } export const enum SymbolAccessibility { @@ -1091,46 +1110,46 @@ module ts { } export const enum SymbolFlags { - FunctionScopedVariable = 0x00000001, // Variable (var) or parameter - BlockScopedVariable = 0x00000002, // A block-scoped variable (let or const) - Property = 0x00000004, // Property or enum member - EnumMember = 0x00000008, // Enum member - Function = 0x00000010, // Function - Class = 0x00000020, // Class - Interface = 0x00000040, // Interface - ConstEnum = 0x00000080, // Const enum - RegularEnum = 0x00000100, // Enum - ValueModule = 0x00000200, // Instantiated module - NamespaceModule = 0x00000400, // Uninstantiated module - TypeLiteral = 0x00000800, // Type Literal - ObjectLiteral = 0x00001000, // Object Literal - Method = 0x00002000, // Method - Constructor = 0x00004000, // Constructor - GetAccessor = 0x00008000, // Get accessor - SetAccessor = 0x00010000, // Set accessor - Signature = 0x00020000, // Call, construct, or index signature - TypeParameter = 0x00040000, // Type parameter - TypeAlias = 0x00080000, // Type alias + FunctionScopedVariable = 0x00000001, // Variable (var) or parameter + BlockScopedVariable = 0x00000002, // A block-scoped variable (let or const) + Property = 0x00000004, // Property or enum member + EnumMember = 0x00000008, // Enum member + Function = 0x00000010, // Function + Class = 0x00000020, // Class + Interface = 0x00000040, // Interface + ConstEnum = 0x00000080, // Const enum + RegularEnum = 0x00000100, // Enum + ValueModule = 0x00000200, // Instantiated module + NamespaceModule = 0x00000400, // Uninstantiated module + TypeLiteral = 0x00000800, // Type Literal + ObjectLiteral = 0x00001000, // Object Literal + Method = 0x00002000, // Method + Constructor = 0x00004000, // Constructor + GetAccessor = 0x00008000, // Get accessor + SetAccessor = 0x00010000, // Set accessor + Signature = 0x00020000, // Call, construct, or index signature + TypeParameter = 0x00040000, // Type parameter + TypeAlias = 0x00080000, // Type alias // Export markers (see comment in declareModuleMember in binder) - ExportValue = 0x00100000, // Exported value marker - ExportType = 0x00200000, // Exported type marker - ExportNamespace = 0x00400000, // Exported namespace marker - Import = 0x00800000, // Import - Instantiated = 0x01000000, // Instantiated symbol - Merged = 0x02000000, // Merged symbol (created during program binding) - Transient = 0x04000000, // Transient symbol (created during type check) - Prototype = 0x08000000, // Prototype property (no source representation) - UnionProperty = 0x10000000, // Property in union type - Optional = 0x20000000, // Optional property + ExportValue = 0x00100000, // Exported value marker + ExportType = 0x00200000, // Exported type marker + ExportNamespace = 0x00400000, // Exported namespace marker + Import = 0x00800000, // Import + Instantiated = 0x01000000, // Instantiated symbol + Merged = 0x02000000, // Merged symbol (created during program binding) + Transient = 0x04000000, // Transient symbol (created during type check) + Prototype = 0x08000000, // Prototype property (no source representation) + UnionProperty = 0x10000000, // Property in union type + Optional = 0x20000000, // Optional property - Enum = RegularEnum | ConstEnum, - Variable = FunctionScopedVariable | BlockScopedVariable, - Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, - Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias, + Enum = RegularEnum | ConstEnum, + Variable = FunctionScopedVariable | BlockScopedVariable, + Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, + Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias, Namespace = ValueModule | NamespaceModule, - Module = ValueModule | NamespaceModule, - Accessor = GetAccessor | SetAccessor, + Module = ValueModule | NamespaceModule, + Accessor = GetAccessor | SetAccessor, // Variables can be redeclared, but can not redeclare a block-scoped declaration with the // same name, or any other value that is not a variable, e.g. ValueModule or Class @@ -1140,34 +1159,34 @@ module ts { // they can not merge with anything in the value space BlockScopedVariableExcludes = Value, - ParameterExcludes = Value, - PropertyExcludes = Value, - EnumMemberExcludes = Value, - FunctionExcludes = Value & ~(Function | ValueModule), - ClassExcludes = (Value | Type) & ~ValueModule, - InterfaceExcludes = Type & ~Interface, - RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules - ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums - ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule), + ParameterExcludes = Value, + PropertyExcludes = Value, + EnumMemberExcludes = Value, + FunctionExcludes = Value & ~(Function | ValueModule), + ClassExcludes = (Value | Type) & ~ValueModule, + InterfaceExcludes = Type & ~Interface, + RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules + ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums + ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule), NamespaceModuleExcludes = 0, - MethodExcludes = Value & ~Method, - GetAccessorExcludes = Value & ~SetAccessor, - SetAccessorExcludes = Value & ~GetAccessor, - TypeParameterExcludes = Type & ~TypeParameter, - TypeAliasExcludes = Type, - ImportExcludes = Import, // Imports collide with all other imports with the same name + MethodExcludes = Value & ~Method, + GetAccessorExcludes = Value & ~SetAccessor, + SetAccessorExcludes = Value & ~GetAccessor, + TypeParameterExcludes = Type & ~TypeParameter, + TypeAliasExcludes = Type, + ImportExcludes = Import, // Imports collide with all other imports with the same name ModuleMember = Variable | Function | Class | Interface | Enum | Module | TypeAlias | Import, ExportHasLocal = Function | Class | Enum | ValueModule, - HasLocals = Function | Module | Method | Constructor | Accessor | Signature, + HasLocals = Function | Module | Method | Constructor | Accessor | Signature, HasExports = Class | Enum | Module, HasMembers = Class | Interface | TypeLiteral | ObjectLiteral, - IsContainer = HasLocals | HasExports | HasMembers, + IsContainer = HasLocals | HasExports | HasMembers, PropertyOrAccessor = Property | Accessor, - Export = ExportNamespace | ExportType | ExportValue, + Export = ExportNamespace | ExportType | ExportValue, } export interface Symbol { @@ -1201,16 +1220,16 @@ module ts { } export const 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, + EnumValuesComputed = 0x00000080, } export interface NodeLinks { @@ -1228,26 +1247,26 @@ module ts { } export const enum TypeFlags { - Any = 0x00000001, - String = 0x00000002, - Number = 0x00000004, - Boolean = 0x00000008, - Void = 0x00000010, - Undefined = 0x00000020, - Null = 0x00000040, - Enum = 0x00000080, // Enum type - StringLiteral = 0x00000100, // String literal type - TypeParameter = 0x00000200, // Type parameter - Class = 0x00000400, // Class - Interface = 0x00000800, // Interface - Reference = 0x00001000, // Generic type reference - Tuple = 0x00002000, // Tuple - Union = 0x00004000, // Union - Anonymous = 0x00008000, // Anonymous - FromSignature = 0x00010000, // Created for signature assignment check - Unwidened = 0x00020000, // Unwidened type (is or contains Undefined or Null type) + Any = 0x00000001, + String = 0x00000002, + Number = 0x00000004, + Boolean = 0x00000008, + Void = 0x00000010, + Undefined = 0x00000020, + Null = 0x00000040, + Enum = 0x00000080, // Enum type + StringLiteral = 0x00000100, // String literal type + TypeParameter = 0x00000200, // Type parameter + Class = 0x00000400, // Class + Interface = 0x00000800, // Interface + Reference = 0x00001000, // Generic type reference + Tuple = 0x00002000, // Tuple + Union = 0x00004000, // Union + Anonymous = 0x00008000, // Anonymous + FromSignature = 0x00010000, // Created for signature assignment check + Unwidened = 0x00020000, // Unwidened type (is or contains Undefined or Null type) - Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null, + Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null, StringLike = String | StringLiteral, NumberLike = Number | Enum, ObjectType = Class | Interface | Reference | Tuple | Anonymous, @@ -1364,7 +1383,7 @@ module ts { inferences: TypeInferences[]; // Inferences made for each type parameter inferredTypes: Type[]; // Inferred type for each type parameter failedTypeParameterIndex?: number; // Index of type parameter for which inference failed - // It is optional because in contextual signature instantiation, nothing fails + // It is optional because in contextual signature instantiation, nothing fails } export interface DiagnosticMessage { @@ -1448,7 +1467,6 @@ module ts { character: number; } - export const enum ScriptTarget { ES3 = 0, ES5 = 1, @@ -1499,7 +1517,7 @@ module ts { narrowNoBreakSpace = 0x202F, ideographicSpace = 0x3000, mathematicalSpace = 0x205F, - ogham = 0x1680, + ogham = 0x1680, _ = 0x5F, $ = 0x24, @@ -1620,4 +1638,14 @@ module ts { useCaseSensitiveFileNames(): boolean; getNewLine(): string; } + + export interface TextSpan { + start: number; + length: number; + } + + export interface TextChangeRange { + span: TextSpan; + newLength: number; + } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4c57cf2cf06..bbe4d7dbf35 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -62,22 +62,18 @@ module ts { return node.end - node.pos; } - function hasFlag(val: number, flag: number): boolean { - return (val & flag) !== 0; - } - // Returns true if this node contains a parse error anywhere underneath it. export function containsParseError(node: Node): boolean { aggregateChildData(node); - return hasFlag(node.parserContextFlags, ParserContextFlags.ThisNodeOrAnySubNodesHasError); + return (node.parserContextFlags & ParserContextFlags.ThisNodeOrAnySubNodesHasError) !== 0 } function aggregateChildData(node: Node): void { - if (!hasFlag(node.parserContextFlags, ParserContextFlags.HasAggregatedChildData)) { + if (!(node.parserContextFlags & ParserContextFlags.HasAggregatedChildData)) { // A node is considered to contain a parse error if: // a) the parser explicitly marked that it had an error // b) any of it's children reported that it had an error. - var thisNodeOrAnySubNodesHasError = hasFlag(node.parserContextFlags, ParserContextFlags.ThisNodeHasError) || + var thisNodeOrAnySubNodesHasError = ((node.parserContextFlags & ParserContextFlags.ThisNodeHasError) !== 0) || forEachChild(node, containsParseError); // If so, mark ourselves accordingly. @@ -110,14 +106,34 @@ module ts { return node.pos; } - export function isMissingNode(node: Node) { + // Returns true if this node is missing from the actual source code. 'missing' is different + // from 'undefined/defined'. When a node is undefined (which can happen for optional nodes + // in the tree), it is definitel missing. HOwever, a node may be defined, but still be + // missing. This happens whenever the parser knows it needs to parse something, but can't + // get anything in the source code that it expects at that location. For example: + // + // var a: ; + // + // Here, the Type in the Type-Annotation is not-optional (as there is a colon in the source + // code). So the parser will attempt to parse out a type, and will create an actual node. + // However, this node will be 'missing' in the sense that no actual source-code/tokens are + // contained within it. + export function nodeIsMissing(node: Node) { + if (!node) { + return true; + } + return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken; } + + export function nodeIsPresent(node: Node) { + return !nodeIsMissing(node); + } export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { // With nodes that have no width (i.e. 'Missing' nodes), we actually *don't* // want to skip trivia because this will launch us forward to the next token. - if (isMissingNode(node)) { + if (nodeIsMissing(node)) { return node.pos; } @@ -125,7 +141,7 @@ module ts { } export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string { - if (isMissingNode(node)) { + if (nodeIsMissing(node)) { return ""; } @@ -134,7 +150,7 @@ module ts { } export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string { - if (isMissingNode(node)) { + if (nodeIsMissing(node)) { return ""; } @@ -216,12 +232,47 @@ module ts { return node.kind === SyntaxKind.EnumDeclaration && isConst(node); } + function walkUpBindingElementsAndPatterns(node: Node): Node { + while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) { + node = node.parent; + } + + return node; + } + + // Returns the node flags for this node and all relevant parent nodes. This is done so that + // nodes like variable declarations and binding elements can returned a view of their flags + // that includes the modifiers from their container. i.e. flags like export/declare aren't + // stored on the variable declaration directly, but on the containing variable statement + // (if it has one). Similarly, flags for let/const are store on the variable declaration + // list. By calling this function, all those flags are combined so that the client can treat + // the node as if it actually had those flags. + export function getCombinedNodeFlags(node: Node): NodeFlags { + node = walkUpBindingElementsAndPatterns(node); + + var flags = node.flags; + if (node.kind === SyntaxKind.VariableDeclaration) { + node = node.parent; + } + + if (node && node.kind === SyntaxKind.VariableDeclarationList) { + flags |= node.flags; + node = node.parent; + } + + if (node && node.kind === SyntaxKind.VariableStatement) { + flags |= node.flags; + } + + return flags; + } + export function isConst(node: Node): boolean { - return !!(node.flags & NodeFlags.Const); + return !!(getCombinedNodeFlags(node) & NodeFlags.Const); } export function isLet(node: Node): boolean { - return !!(node.flags & NodeFlags.Let); + return !!(getCombinedNodeFlags(node) & NodeFlags.Let); } export function isPrologueDirective(node: Node): boolean { @@ -281,9 +332,7 @@ module ts { case SyntaxKind.DefaultClause: case SyntaxKind.LabeledStatement: case SyntaxKind.TryStatement: - case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: return forEachChild(node, traverse); } } @@ -455,12 +504,14 @@ module ts { case SyntaxKind.SwitchStatement: return (parent).expression === node; case SyntaxKind.ForStatement: - return (parent).initializer === node || - (parent).condition === node || - (parent).iterator === node; + var forStatement = parent; + return (forStatement.initializer === node && forStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || + forStatement.condition === node || + forStatement.iterator === node; case SyntaxKind.ForInStatement: - return (parent).variable === node || - (parent).expression === node; + var forInStatement = parent; + return (forInStatement.initializer === node && forInStatement.initializer.kind !== SyntaxKind.VariableDeclarationList) || + forInStatement.expression === node; case SyntaxKind.TypeAssertionExpression: return node === (parent).expression; case SyntaxKind.TemplateSpan: @@ -532,7 +583,10 @@ module ts { export function isInAmbientContext(node: Node): boolean { while (node) { - if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true; + if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) { + return true; + } + node = node.parent; } return false; @@ -710,6 +764,7 @@ module ts { } } } + return undefined; } @@ -735,4 +790,214 @@ module ts { return false; } + export function textSpanEnd(span: TextSpan) { + return span.start + span.length + } + + export function textSpanIsEmpty(span: TextSpan) { + return span.length === 0 + } + + export function textSpanContainsPosition(span: TextSpan, position: number) { + return position >= span.start && position < textSpanEnd(span); + } + + // Returns true if 'span' contains 'other'. + export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) { + return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span); + } + + export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) { + var overlapStart = Math.max(span.start, other.start); + var overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other)); + return overlapStart < overlapEnd; + } + + export function textSpanOverlap(span1: TextSpan, span2: TextSpan) { + var overlapStart = Math.max(span1.start, span2.start); + var overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2)); + if (overlapStart < overlapEnd) { + return createTextSpanFromBounds(overlapStart, overlapEnd); + } + return undefined; + } + + export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) { + return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start + } + + export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) { + var end = start + length; + return start <= textSpanEnd(span) && end >= span.start; + } + + export function textSpanIntersectsWithPosition(span: TextSpan, position: number) { + return position <= textSpanEnd(span) && position >= span.start; + } + + export function textSpanIntersection(span1: TextSpan, span2: TextSpan) { + var intersectStart = Math.max(span1.start, span2.start); + var intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2)); + if (intersectStart <= intersectEnd) { + return createTextSpanFromBounds(intersectStart, intersectEnd); + } + return undefined; + } + + export function createTextSpan(start: number, length: number): TextSpan { + if (start < 0) { + throw new Error("start < 0"); + } + if (length < 0) { + throw new Error("length < 0"); + } + + return { start, length }; + } + + export function createTextSpanFromBounds(start: number, end: number) { + return createTextSpan(start, end - start); + } + + export function textChangeRangeNewSpan(range: TextChangeRange) { + return createTextSpan(range.span.start, range.newLength); + } + + export function textChangeRangeIsUnchanged(range: TextChangeRange) { + return textSpanIsEmpty(range.span) && range.newLength === 0; + } + + export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange { + if (newLength < 0) { + throw new Error("newLength < 0"); + } + + return { span, newLength }; + } + + export var unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0); + + /** + * Called to merge all the changes that occurred across several versions of a script snapshot + * into a single change. i.e. if a user keeps making successive edits to a script we will + * have a text change from V1 to V2, V2 to V3, ..., Vn. + * + * This function will then merge those changes into a single change range valid between V1 and + * Vn. + */ + export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange { + if (changes.length === 0) { + return unchangedTextChangeRange; + } + + if (changes.length === 1) { + return changes[0]; + } + + // We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd } + // as it makes things much easier to reason about. + var change0 = changes[0]; + + var oldStartN = change0.span.start; + var oldEndN = textSpanEnd(change0.span); + var newEndN = oldStartN + change0.newLength; + + for (var i = 1; i < changes.length; i++) { + var nextChange = changes[i]; + + // Consider the following case: + // i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting + // at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }. + // i.e. the span starting at 30 with length 30 is increased to length 40. + // + // 0 10 20 30 40 50 60 70 80 90 100 + // ------------------------------------------------------------------------------------------------------- + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ------------------------------------------------------------------------------------------------------- + // | \ + // | \ + // T2 | \ + // | \ + // | \ + // ------------------------------------------------------------------------------------------------------- + // + // Merging these turns out to not be too difficult. First, determining the new start of the change is trivial + // it's just the min of the old and new starts. i.e.: + // + // 0 10 20 30 40 50 60 70 80 90 100 + // ------------------------------------------------------------*------------------------------------------ + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ----------------------------------------$-------------------$------------------------------------------ + // . | \ + // . | \ + // T2 . | \ + // . | \ + // . | \ + // ----------------------------------------------------------------------*-------------------------------- + // + // (Note the dots represent the newly inferrred start. + // Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the + // absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see + // which if the two $'s precedes the other, and we move that one forward until they line up. in this case that + // means: + // + // 0 10 20 30 40 50 60 70 80 90 100 + // --------------------------------------------------------------------------------*---------------------- + // | / + // | /---- + // T1 | /---- + // | /---- + // | /---- + // ------------------------------------------------------------$------------------------------------------ + // . | \ + // . | \ + // T2 . | \ + // . | \ + // . | \ + // ----------------------------------------------------------------------*-------------------------------- + // + // In other words (in this case), we're recognizing that the second edit happened after where the first edit + // ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started + // that's the same as if we started at char 80 instead of 60. + // + // As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter + // than pusing the first edit forward to match the second, we'll push the second edit forward to match the + // first. + // + // In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange + // semantics: { { start: 10, length: 70 }, newLength: 60 } + // + // The math then works out as follows. + // If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the + // final result like so: + // + // { + // oldStart3: Min(oldStart1, oldStart2), + // oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)), + // newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)) + // } + + var oldStart1 = oldStartN; + var oldEnd1 = oldEndN; + var newEnd1 = newEndN; + + var oldStart2 = nextChange.span.start; + var oldEnd2 = textSpanEnd(nextChange.span); + var newEnd2 = oldStart2 + nextChange.newLength; + + oldStartN = Math.min(oldStart1, oldStart2); + oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)); + newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); + } + + return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN); + } } \ No newline at end of file diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 174b311e763..3659d8844a9 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -18,6 +18,8 @@ /// module FourSlash { + ts.disableIncrementalParsing = false; + // Represents a parsed source file with metadata export interface FourSlashFile { // The contents of the file (with markers, etc stripped out) @@ -697,7 +699,7 @@ module FourSlash { for (var i = 0; i < references.length; i++) { var reference = references[i]; - if (reference && reference.fileName === fileName && reference.textSpan.start() === start && reference.textSpan.end() === end) { + if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) { if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) { this.raiseError('verifyReferencesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + reference.isWriteAccess + ', expected: ' + isWriteAccess + '.'); } @@ -828,17 +830,17 @@ module FourSlash { } ranges = ranges.sort((r1, r2) => r1.start - r2.start); - references = references.sort((r1, r2) => r1.textSpan.start() - r2.textSpan.start()); + references = references.sort((r1, r2) => r1.textSpan.start - r2.textSpan.start); for (var i = 0, n = ranges.length; i < n; i++) { var reference = references[i]; var range = ranges[i]; - if (reference.textSpan.start() !== range.start || - reference.textSpan.end() !== range.end) { + if (reference.textSpan.start !== range.start || + ts.textSpanEnd(reference.textSpan) !== range.end) { this.raiseError(this.assertionMessage("Rename location", - "[" + reference.textSpan.start() + "," + reference.textSpan.end() + ")", + "[" + reference.textSpan.start + "," + ts.textSpanEnd(reference.textSpan) + ")", "[" + range.start + "," + range.end + ")")); } } @@ -978,10 +980,10 @@ module FourSlash { } var expectedRange = this.getRanges()[0]; - if (renameInfo.triggerSpan.start() !== expectedRange.start || - renameInfo.triggerSpan.end() !== expectedRange.end) { + if (renameInfo.triggerSpan.start !== expectedRange.start || + ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end) { this.raiseError("Expected triggerSpan [" + expectedRange.start + "," + expectedRange.end + "). Got [" + - renameInfo.triggerSpan.start() + "," + renameInfo.triggerSpan.end() + ") instead."); + renameInfo.triggerSpan.start + "," + ts.textSpanEnd(renameInfo.triggerSpan) + ") instead."); } } @@ -1012,7 +1014,7 @@ module FourSlash { private spanInfoToString(pos: number, spanInfo: ts.TextSpan, prefixString: string) { var resultString = "SpanInfo: " + JSON.stringify(spanInfo); if (spanInfo) { - var spanString = this.activeFile.content.substr(spanInfo.start(), spanInfo.length()); + var spanString = this.activeFile.content.substr(spanInfo.start, spanInfo.length); var spanLineMap = ts.computeLineStarts(spanString); for (var i = 0; i < spanLineMap.length; i++) { if (!i) { @@ -1020,7 +1022,7 @@ module FourSlash { } resultString += prefixString + spanString.substring(spanLineMap[i], spanLineMap[i + 1]); } - resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start()) + ") to (" + this.getLineColStringAtPosition(spanInfo.end()) + ")"; + resultString += "\n" + prefixString + ":=> (" + this.getLineColStringAtPosition(spanInfo.start) + ") to (" + this.getLineColStringAtPosition(ts.textSpanEnd(spanInfo)) + ")"; } return resultString; @@ -1223,16 +1225,24 @@ module FourSlash { var offset = this.currentCaretPosition; var ch = ""; + var checkCadence = (count >> 2) + 1 + for (var i = 0; i < count; i++) { // Make the edit this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset + 1, ch); this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch); - this.checkPostEditInvariants(); + + if (i % checkCadence === 0) { + this.checkPostEditInvariants(); + } // Handle post-keystroke formatting if (this.enableFormatting) { var edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); - offset += this.applyEdits(this.activeFile.fileName, edits, true); + if (edits.length) { + offset += this.applyEdits(this.activeFile.fileName, edits, true); + //this.checkPostEditInvariants(); + } } } @@ -1249,8 +1259,6 @@ module FourSlash { this.languageServiceShimHost.editScript(this.activeFile.fileName, start, start + length, text); this.updateMarkersForEdit(this.activeFile.fileName, start, start + length, text); this.checkPostEditInvariants(); - - this.checkPostEditInvariants(); } public deleteCharBehindMarker(count = 1) { @@ -1258,19 +1266,24 @@ module FourSlash { var offset = this.currentCaretPosition; var ch = ""; + var checkCadence = (count >> 2) + 1 for (var i = 0; i < count; i++) { offset--; // Make the edit this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset + 1, ch); this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch); - this.checkPostEditInvariants(); + + if (i % checkCadence === 0) { + this.checkPostEditInvariants(); + } // Handle post-keystroke formatting if (this.enableFormatting) { var edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); - offset += this.applyEdits(this.activeFile.fileName, edits, true); - this.checkPostEditInvariants(); + if (edits.length) { + offset += this.applyEdits(this.activeFile.fileName, edits, true); + } } } @@ -1295,9 +1308,11 @@ module FourSlash { // Enters lines of text at the current caret position, invoking // language service APIs to mimic Visual Studio's behavior // as much as possible - private typeHighFidelity(text: string, errorCadence = 5) { + private typeHighFidelity(text: string) { var offset = this.currentCaretPosition; var prevChar = ' '; + var checkCadence = (text.length >> 2) + 1; + for (var i = 0; i < text.length; i++) { // Make the edit var ch = text.charAt(i); @@ -1305,7 +1320,6 @@ module FourSlash { this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, offset); this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, ch); - this.checkPostEditInvariants(); offset++; if (ch === '(' || ch === ',') { @@ -1316,16 +1330,19 @@ module FourSlash { this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset); } - if (i % errorCadence === 0) { - this.languageService.getSyntacticDiagnostics(this.activeFile.fileName); - this.languageService.getSemanticDiagnostics(this.activeFile.fileName); + if (i % checkCadence === 0) { + this.checkPostEditInvariants(); + // this.languageService.getSyntacticDiagnostics(this.activeFile.fileName); + // this.languageService.getSemanticDiagnostics(this.activeFile.fileName); } // Handle post-keystroke formatting if (this.enableFormatting) { var edits = this.languageService.getFormattingEditsAfterKeystroke(this.activeFile.fileName, offset, ch, this.formatCodeOptions); - offset += this.applyEdits(this.activeFile.fileName, edits, true); - this.checkPostEditInvariants(); + if (edits.length) { + offset += this.applyEdits(this.activeFile.fileName, edits, true); + // this.checkPostEditInvariants(); + } } } @@ -1350,8 +1367,10 @@ module FourSlash { // Handle formatting if (this.enableFormatting) { var edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions); - offset += this.applyEdits(this.activeFile.fileName, edits, true); - this.checkPostEditInvariants(); + if (edits.length) { + offset += this.applyEdits(this.activeFile.fileName, edits, true); + this.checkPostEditInvariants(); + } } // Move the caret to wherever we ended up @@ -1365,7 +1384,7 @@ module FourSlash { var incrementalSourceFile = this.languageService.getSourceFile(this.activeFile.fileName); Utils.assertInvariants(incrementalSourceFile, /*parent:*/ undefined); - var incrementalSyntaxDiagnostics = JSON.stringify(Utils.convertDiagnostics(incrementalSourceFile.getSyntacticDiagnostics())); + var incrementalSyntaxDiagnostics = incrementalSourceFile.getSyntacticDiagnostics(); // Check syntactic structure var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); @@ -1373,32 +1392,10 @@ module FourSlash { var referenceSourceFile = ts.createLanguageServiceSourceFile( this.activeFile.fileName, createScriptSnapShot(content), ts.ScriptTarget.Latest, /*version:*/ "0", /*isOpen:*/ false, /*setNodeParents:*/ false); - var referenceSyntaxDiagnostics = JSON.stringify(Utils.convertDiagnostics(referenceSourceFile.getSyntacticDiagnostics())); - - if (incrementalSyntaxDiagnostics !== referenceSyntaxDiagnostics) { - this.raiseError('Mismatched incremental/reference syntactic diagnostics for file ' + this.activeFile.fileName + '.\n=== Incremental diagnostics ===\n' + incrementalSyntaxDiagnostics + '\n=== Reference Diagnostics ===\n' + referenceSyntaxDiagnostics); - } + var referenceSyntaxDiagnostics = referenceSourceFile.getSyntacticDiagnostics(); + Utils.assertDiagnosticsEquals(incrementalSyntaxDiagnostics, referenceSyntaxDiagnostics); Utils.assertStructuralEquals(incrementalSourceFile, referenceSourceFile); - - //if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { - // var compiler = new TypeScript.TypeScriptCompiler(); - // for (var i = 0; i < this.testData.files.length; i++) { - // snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); - // compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), ts.ByteOrderMark.None, 0, true); - // } - - // compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), ts.ByteOrderMark.None, 0, true); - - // for (var i = 0; i < this.testData.files.length; i++) { - // var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); - // var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); - - // if (incrSemanticErrs !== refSemanticErrs) { - // this.raiseError('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); - // } - // } - //} } private fixCaretPosition() { @@ -1416,14 +1413,14 @@ module FourSlash { // We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track // of the incremental offset from each edit to the next. Assumption is that these edit ranges don't overlap var runningOffset = 0; - edits = edits.sort((a, b) => a.span.start() - b.span.start()); + edits = edits.sort((a, b) => a.span.start - b.span.start); // Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters var snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName); var oldContent = snapshot.getText(0, snapshot.getLength()); for (var j = 0; j < edits.length; j++) { - this.languageServiceShimHost.editScript(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText); - this.updateMarkersForEdit(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText); - var change = (edits[j].span.start() - edits[j].span.end()) + edits[j].newText.length; + this.languageServiceShimHost.editScript(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText); + this.updateMarkersForEdit(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText); + var change = (edits[j].span.start - ts.textSpanEnd(edits[j].span)) + edits[j].newText.length; runningOffset += change; // TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150) // this.languageService.getScriptLexicalStructure(fileName); @@ -1500,7 +1497,7 @@ module FourSlash { var definition = definitions[definitionIndex]; this.openFile(definition.fileName); - this.currentCaretPosition = definition.textSpan.start(); + this.currentCaretPosition = definition.textSpan.start; } public verifyDefinitionLocationExists(negative: boolean) { @@ -1621,7 +1618,7 @@ module FourSlash { '\t Actual: undefined'); } - var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start(), span.end()); + var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start, ts.textSpanEnd(span)); if (actual !== text) { this.raiseError('verifyCurrentNameOrDottedNameSpanText\n' + '\tExpected: "' + text + '"\n' + @@ -1676,15 +1673,15 @@ module FourSlash { if (expectedSpan) { var expectedLength = expectedSpan.end - expectedSpan.start; - if (expectedSpan.start !== actualSpan.start() || expectedLength !== actualSpan.length()) { + if (expectedSpan.start !== actualSpan.start || expectedLength !== actualSpan.length) { this.raiseError("verifyClassifications failed - expected span of text to be " + "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " + - "{start=" + actualSpan.start() + ", length=" + actualSpan.length() + "}" + + "{start=" + actualSpan.start + ", length=" + actualSpan.length + "}" + jsonMismatchString()); } } - var actualText = this.activeFile.content.substr(actualSpan.start(), actualSpan.length()); + var actualText = this.activeFile.content.substr(actualSpan.start, actualSpan.length); if (expectedClassification.text !== actualText) { this.raiseError('verifyClassifications failed - expected classified text to be ' + expectedClassification.text + ', but was ' + @@ -1702,14 +1699,14 @@ module FourSlash { public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) { var actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, - new ts.TextSpan(0, this.activeFile.content.length)); + ts.createTextSpan(0, this.activeFile.content.length)); this.verifyClassifications(expected, actual); } public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) { - var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName, - new ts.TextSpan(0, this.activeFile.content.length)); + var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length)); this.verifyClassifications(expected, actual); } @@ -1726,8 +1723,8 @@ module FourSlash { for (var i = 0; i < spans.length; i++) { var expectedSpan = spans[i]; var actualSpan = actual[i]; - if (expectedSpan.start !== actualSpan.textSpan.start() || expectedSpan.end !== actualSpan.textSpan.end()) { - this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start() + ',' + actualSpan.textSpan.end() + ')'); + if (expectedSpan.start !== actualSpan.textSpan.start || expectedSpan.end !== ts.textSpanEnd(actualSpan.textSpan)) { + this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start + ',' + ts.textSpanEnd(actualSpan.textSpan) + ')'); } } } @@ -1743,10 +1740,10 @@ module FourSlash { for (var i = 0; i < spans.length; i++) { var expectedSpan = spans[i]; var actualComment = actual[i]; - var actualCommentSpan = new ts.TextSpan(actualComment.position, actualComment.message.length); + var actualCommentSpan = ts.createTextSpan(actualComment.position, actualComment.message.length); - if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) { - this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')'); + if (expectedSpan.start !== actualCommentSpan.start || expectedSpan.end !== ts.textSpanEnd(actualCommentSpan)) { + this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start + ',' + ts.textSpanEnd(actualCommentSpan) + ')'); } } } @@ -1761,12 +1758,12 @@ module FourSlash { } var actualMatchPosition = -1; - if (bracePosition === actual[0].start()) { - actualMatchPosition = actual[1].start(); - } else if (bracePosition === actual[1].start()) { - actualMatchPosition = actual[0].start(); + if (bracePosition === actual[0].start) { + actualMatchPosition = actual[1].start; + } else if (bracePosition === actual[1].start) { + actualMatchPosition = actual[0].start; } else { - this.raiseError('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() + ')'); + this.raiseError('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start + ',' + ts.textSpanEnd(actual[0]) + ') and (' + actual[1].start + ',' + ts.textSpanEnd(actual[1]) + ')'); } if (actualMatchPosition !== expectedMatchPosition) { @@ -2006,7 +2003,7 @@ module FourSlash { for (var i = 0; i < occurances.length; i++) { var occurance = occurances[i]; - if (occurance && occurance.fileName === fileName && occurance.textSpan.start() === start && occurance.textSpan.end() === end) { + if (occurance && occurance.fileName === fileName && occurance.textSpan.start === start && ts.textSpanEnd(occurance.textSpan) === end) { if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) { this.raiseError('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.'); } @@ -2590,4 +2587,4 @@ module FourSlash { fileName: fileName }; } -} +} diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 7e8acdab68d..bc66186d2d7 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -290,6 +290,29 @@ module Utils { } } + export function assertDiagnosticsEquals(array1: ts.Diagnostic[], array2: ts.Diagnostic[]) { + if (array1 === array2) { + return; + } + + assert(array1, "array1"); + assert(array2, "array2"); + + assert.equal(array1.length, array2.length, "array1.length !== array2.length"); + + for (var i = 0, n = array1.length; i < n; i++) { + var d1 = array1[i]; + var d2 = array2[i]; + + assert.equal(d1.start, d2.start, "d1.start !== d2.start"); + assert.equal(d1.length, d2.length, "d1.length !== d2.length"); + assert.equal(d1.messageText, d2.messageText, "d1.messageText !== d2.messageText"); + assert.equal(d1.category, d2.category, "d1.category !== d2.category"); + assert.equal(d1.code, d2.code, "d1.code !== d2.code"); + assert.equal(d1.isEarly, d2.isEarly, "d1.isEarly !== d2.isEarly"); + } + } + export function assertStructuralEquals(node1: ts.Node, node2: ts.Node) { if (node1 === node2) { return; @@ -1196,7 +1219,7 @@ module Harness { // Report global errors var globalErrors = diagnostics.filter(err => !err.filename); - globalErrors.forEach(err => outputErrorText(err)); + globalErrors.forEach(outputErrorText); // 'merge' the lines of each input file with any errors associated with it inputFiles.filter(f => f.content !== undefined).forEach(inputFile => { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 0aa1415cc99..97885bdd20e 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -32,8 +32,8 @@ module Harness.LanguageService { // Store edit range + new length of script this.editRanges.push({ length: this.content.length, - textChangeRange: new ts.TextChangeRange( - ts.TextSpan.fromBounds(minChar, limChar), newText.length) + textChangeRange: ts.createTextChangeRange( + ts.createTextSpanFromBounds(minChar, limChar), newText.length) }); // Update version # @@ -43,14 +43,14 @@ module Harness.LanguageService { public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): ts.TextChangeRange { if (startVersion === endVersion) { // No edits! - return ts.TextChangeRange.unchanged; + return ts.unchangedTextChangeRange; } var initialEditRangeIndex = this.editRanges.length - (this.version - startVersion); var lastEditRangeIndex = this.editRanges.length - (this.version - endVersion); var entries = this.editRanges.slice(initialEditRangeIndex, lastEditRangeIndex); - return ts.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange)); + return ts.collapseTextChangeRangesAcrossMultipleVersions(entries.map(e => e.textChangeRange)); } } @@ -87,7 +87,7 @@ module Harness.LanguageService { return null; } - return JSON.stringify({ span: { start: range.span().start(), length: range.span().length() }, newLength: range.newLength() }); + return JSON.stringify({ span: { start: range.span.start, length: range.span.length }, newLength: range.newLength }); } } @@ -126,7 +126,7 @@ module Harness.LanguageService { isOpen: boolean, textChangeRange: ts.TextChangeRange ): ts.SourceFile { - return document.update(scriptSnapshot, version, isOpen, textChangeRange); + return ts.updateLanguageServiceSourceFile(document, scriptSnapshot, version, isOpen, textChangeRange); } public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void { @@ -346,9 +346,9 @@ module Harness.LanguageService { for (var i = edits.length - 1; i >= 0; i--) { var edit = edits[i]; - var prefix = result.substring(0, edit.span.start()); + var prefix = result.substring(0, edit.span.start); var middle = edit.newText; - var suffix = result.substring(edit.span.end()); + var suffix = result.substring(ts.textSpanEnd(edit.span)); result = prefix + middle + suffix; } return result; @@ -367,7 +367,7 @@ module Harness.LanguageService { } var temp = mapEdits(edits).sort(function (a, b) { - var result = a.edit.span.start() - b.edit.span.start(); + var result = a.edit.span.start - b.edit.span.start; if (result === 0) result = a.index - b.index; return result; @@ -386,7 +386,7 @@ module Harness.LanguageService { } var nextEdit = temp[next].edit; - var gap = nextEdit.span.start() - currentEdit.span.end(); + var gap = nextEdit.span.start - ts.textSpanEnd(currentEdit.span); // non-overlapping edits if (gap >= 0) { @@ -398,7 +398,7 @@ module Harness.LanguageService { // overlapping edits: for now, we only support ignoring an next edit // entirely contained in the current edit. - if (currentEdit.span.end() >= nextEdit.span.end()) { + if (ts.textSpanEnd(currentEdit.span) >= ts.textSpanEnd(nextEdit.span)) { next++; continue; } diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 3a2cc2ad7e7..e49d035559b 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -38,7 +38,7 @@ module ts.BreakpointResolver { return spanInNode(tokenAtLocation); function textSpan(startNode: Node, endNode?: Node) { - return TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd()); + return createTextSpanFromBounds(startNode.getStart(), (endNode || startNode).getEnd()); } function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan { @@ -83,7 +83,7 @@ module ts.BreakpointResolver { switch (node.kind) { case SyntaxKind.VariableStatement: // Span on first variable declaration - return spanInVariableDeclaration((node).declarations[0]); + return spanInVariableDeclaration((node).declarationList.declarations[0]); case SyntaxKind.VariableDeclaration: case SyntaxKind.PropertyDeclaration: @@ -108,8 +108,6 @@ module ts.BreakpointResolver { return spanInFunctionBlock(node); } // Fall through - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: return spanInBlock(node); @@ -263,16 +261,16 @@ module ts.BreakpointResolver { function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan { // If declaration of for in statement, just set the span in parent - if (variableDeclaration.parent.kind === SyntaxKind.ForInStatement) { - return spanInNode(variableDeclaration.parent); + if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) { + return spanInNode(variableDeclaration.parent.parent); } - var isParentVariableStatement = variableDeclaration.parent.kind === SyntaxKind.VariableStatement; - var isDeclarationOfForStatement = variableDeclaration.parent.kind === SyntaxKind.ForStatement && contains((variableDeclaration.parent).declarations, variableDeclaration); + var isParentVariableStatement = variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement; + var isDeclarationOfForStatement = variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement && contains(((variableDeclaration.parent.parent).initializer).declarations, variableDeclaration); var declarations = isParentVariableStatement - ? (variableDeclaration.parent).declarations + ? (variableDeclaration.parent.parent).declarationList.declarations : isDeclarationOfForStatement - ? (variableDeclaration.parent).declarations + ? ((variableDeclaration.parent.parent).initializer).declarations : undefined; // Breakpoint is possible in variableDeclaration only if there is initialization @@ -376,12 +374,18 @@ module ts.BreakpointResolver { } function spanInForStatement(forStatement: ForStatement): TextSpan { - if (forStatement.declarations) { - return spanInNode(forStatement.declarations[0]); - } if (forStatement.initializer) { - return spanInNode(forStatement.initializer); + if (forStatement.initializer.kind === SyntaxKind.VariableDeclarationList) { + var variableDeclarationList = forStatement.initializer; + if (variableDeclarationList.declarations.length > 0) { + return spanInNode(variableDeclarationList.declarations[0]); + } + } + else { + return spanInNode(forStatement.initializer); + } } + if (forStatement.condition) { return textSpan(forStatement.condition); } @@ -429,9 +433,7 @@ module ts.BreakpointResolver { } // fall through. - case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: return spanInNode((node.parent).statements[(node.parent).statements.length - 1]);; case SyntaxKind.SwitchStatement: diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 823a5ff4e00..b5edf776d58 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -154,8 +154,6 @@ module ts.formatting { return body && body.kind === SyntaxKind.Block && rangeContainsRange((body).statements, node); case SyntaxKind.SourceFile: case SyntaxKind.Block: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: return rangeContainsRange((parent).statements, node); case SyntaxKind.CatchClause: @@ -875,7 +873,7 @@ module ts.formatting { } function newTextChange(start: number, len: number, newText: string): TextChange { - return { span: new TextSpan(start, len), newText } + return { span: createTextSpan(start, len), newText } } function recordDelete(start: number, len: number) { @@ -939,9 +937,6 @@ module ts.formatting { function isSomeBlock(kind: SyntaxKind): boolean { switch (kind) { case SyntaxKind.Block: - case SyntaxKind.Block: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: return true; } diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index bea74e529ff..9fcc787030d 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -525,8 +525,6 @@ module ts.formatting { case SyntaxKind.Block: case SyntaxKind.SwitchStatement: case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: return true; } @@ -580,9 +578,7 @@ module ts.formatting { case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.Block: - case SyntaxKind.TryBlock: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: case SyntaxKind.SwitchStatement: return true; @@ -603,7 +599,6 @@ module ts.formatting { // TODO // case SyntaxKind.ElseClause: case SyntaxKind.CatchClause: - case SyntaxKind.FinallyBlock: return true; default: diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index f6f5031d60e..ce240a95168 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -327,8 +327,6 @@ module ts.formatting { case SyntaxKind.EnumDeclaration: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.Block: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.TypeLiteral: @@ -404,7 +402,6 @@ module ts.formatting { case SyntaxKind.EnumDeclaration: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.Block: - case SyntaxKind.FinallyBlock: case SyntaxKind.ModuleBlock: case SyntaxKind.SwitchStatement: return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile); diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 29b2db72fc5..9051ee80399 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -44,7 +44,7 @@ module ts.NavigationBar { function visit(node: Node) { switch (node.kind) { case SyntaxKind.VariableStatement: - forEach((node).declarations, visit); + forEach((node).declarationList.declarations, visit); break; case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: @@ -462,8 +462,8 @@ module ts.NavigationBar { function getNodeSpan(node: Node) { return node.kind === SyntaxKind.SourceFile - ? TextSpan.fromBounds(node.getFullStart(), node.getEnd()) - : TextSpan.fromBounds(node.getStart(), node.getEnd()); + ? createTextSpanFromBounds(node.getFullStart(), node.getEnd()) + : createTextSpanFromBounds(node.getStart(), node.getEnd()); } function getTextOfNode(node: Node): string { diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index 5af69cd3626..0b39f54ca29 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -22,8 +22,8 @@ module ts { function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) { if (hintSpanNode && startElement && endElement) { var span: OutliningSpan = { - textSpan: TextSpan.fromBounds(startElement.pos, endElement.end), - hintSpan: TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end), + textSpan: createTextSpanFromBounds(startElement.pos, endElement.end), + hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end), bannerText: collapseText, autoCollapse: autoCollapse }; @@ -68,25 +68,41 @@ module ts { parent.kind === SyntaxKind.CatchClause) { addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + break; } - else { - // Block was a standalone block. In this case we want to only collapse - // the span of the block, independent of any parent span. - var span = TextSpan.fromBounds(n.getStart(), n.end); - elements.push({ - textSpan: span, - hintSpan: span, - bannerText: collapseText, - autoCollapse: autoCollapse(n) - }); + + if (parent.kind === SyntaxKind.TryStatement) { + // Could be the try-block, or the finally-block. + var tryStatement = parent; + if (tryStatement.tryBlock === n) { + addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + else if (tryStatement.finallyBlock === n) { + var finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); + if (finallyKeyword) { + addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n)); + break; + } + } + + // fall through. } + + // Block was a standalone block. In this case we want to only collapse + // the span of the block, independent of any parent span. + var span = createTextSpanFromBounds(n.getStart(), n.end); + elements.push({ + textSpan: span, + hintSpan: span, + bannerText: collapseText, + autoCollapse: autoCollapse(n) + }); break; } // Fallthrough. case SyntaxKind.ModuleBlock: - case SyntaxKind.TryBlock: - case SyntaxKind.FinallyBlock: var openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); var closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n)); diff --git a/src/services/services.ts b/src/services/services.ts index 67c55a8c829..f8070fa0531 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -63,10 +63,9 @@ module ts { export interface SourceFile { isOpen: boolean; version: string; + scriptSnapshot: IScriptSnapshot; - getScriptSnapshot(): IScriptSnapshot; getNamedDeclarations(): Declaration[]; - update(scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile; } /** @@ -365,7 +364,7 @@ module ts { // Get the cleaned js doc comment text from the declaration ts.forEach(getJsDocCommentTextRange( - declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent : declaration, sourceFileOfDeclaration), jsDocCommentTextRange => { + declaration.kind === SyntaxKind.VariableDeclaration ? declaration.parent.parent : declaration, sourceFileOfDeclaration), jsDocCommentTextRange => { var cleanedJsDocComment = getCleanedJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration); if (cleanedJsDocComment) { jsDocCommentParts.push.apply(jsDocCommentParts, cleanedJsDocComment); @@ -726,6 +725,7 @@ module ts { public _declarationBrand: any; public filename: string; public text: string; + public scriptSnapshot: IScriptSnapshot; public statements: NodeArray; public endOfFileToken: Node; @@ -736,6 +736,7 @@ module ts { public getPositionFromLineAndCharacter: (line: number, character: number) => number; public getLineStarts: () => number[]; public getSyntacticDiagnostics: () => Diagnostic[]; + public update: (newText: string, textChangeRange: TextChangeRange) => SourceFile; public amdDependencies: string[]; public amdModuleName: string; @@ -755,13 +756,8 @@ module ts { public languageVersion: ScriptTarget; public identifiers: Map; - private scriptSnapshot: IScriptSnapshot; private namedDeclarations: Declaration[]; - public getScriptSnapshot(): IScriptSnapshot { - return this.scriptSnapshot; - } - public getNamedDeclarations() { if (!this.namedDeclarations) { var sourceFile = this; @@ -810,6 +806,7 @@ module ts { // fall through case SyntaxKind.Constructor: case SyntaxKind.VariableStatement: + case SyntaxKind.VariableDeclarationList: case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: case SyntaxKind.ModuleBlock: @@ -847,35 +844,6 @@ module ts { return this.namedDeclarations; } - - public update(scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile { - if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) { - var oldText = this.scriptSnapshot; - var newText = scriptSnapshot; - - Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength()); - - if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { - var oldTextPrefix = oldText.getText(0, textChangeRange.span().start()); - var newTextPrefix = newText.getText(0, textChangeRange.span().start()); - Debug.assert(oldTextPrefix === newTextPrefix); - - var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength()); - var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength()); - Debug.assert(oldTextSuffix === newTextSuffix); - } - } - - return createLanguageServiceSourceFile(this.filename, scriptSnapshot, this.languageVersion, version, isOpen, /*setNodeParents:*/ true); - } - - public static createSourceFileObject(filename: string, scriptSnapshot: IScriptSnapshot, languageVersion: ScriptTarget, version: string, isOpen: boolean, setParentNodes: boolean) { - var newSourceFile = createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), languageVersion, setParentNodes); - newSourceFile.version = version; - newSourceFile.isOpen = isOpen; - newSourceFile.scriptSnapshot = scriptSnapshot; - return newSourceFile; - } } export interface Logger { @@ -949,301 +917,6 @@ module ts { dispose(): void; } - - export class TextSpan { - private _start: number; - private _length: number; - - /** - * Creates a TextSpan instance beginning with the position Start and having the Length - * specified with length. - */ - constructor(start: number, length: number) { - Debug.assert(start >= 0, "start"); - Debug.assert(length >= 0, "length"); - - this._start = start; - this._length = length; - } - - public toJSON(key: any): any { - return { start: this._start, length: this._length }; - } - - public start(): number { - return this._start; - } - - public length(): number { - return this._length; - } - - public end(): number { - return this._start + this._length; - } - - public isEmpty(): boolean { - return this._length === 0; - } - - /** - * Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less - * than End, otherwise false. - * @param position The position to check. - */ - public containsPosition(position: number): boolean { - return position >= this._start && position < this.end(); - } - - /** - * Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false. - * @param span The span to check. - */ - public containsTextSpan(span: TextSpan): boolean { - return span._start >= this._start && span.end() <= this.end(); - } - - /** - * Determines whether the given span overlaps this span. Two spans are considered to overlap - * if they have positions in common and neither is empty. Empty spans do not overlap with any - * other span. Returns true if the spans overlap, false otherwise. - * @param span The span to check. - */ - public overlapsWith(span: TextSpan): boolean { - var overlapStart = Math.max(this._start, span._start); - var overlapEnd = Math.min(this.end(), span.end()); - - return overlapStart < overlapEnd; - } - - /** - * Returns the overlap with the given span, or undefined if there is no overlap. - * @param span The span to check. - */ - public overlap(span: TextSpan): TextSpan { - var overlapStart = Math.max(this._start, span._start); - var overlapEnd = Math.min(this.end(), span.end()); - - if (overlapStart < overlapEnd) { - return TextSpan.fromBounds(overlapStart, overlapEnd); - } - - return undefined; - } - - /** - * Determines whether span intersects this span. Two spans are considered to - * intersect if they have positions in common or the end of one span - * coincides with the start of the other span. Returns true if the spans intersect, false otherwise. - * @param The span to check. - */ - public intersectsWithTextSpan(span: TextSpan): boolean { - return span._start <= this.end() && span.end() >= this._start; - } - - public intersectsWith(start: number, length: number): boolean { - var end = start + length; - return start <= this.end() && end >= this._start; - } - - /** - * Determines whether the given position intersects this span. - * A position is considered to intersect if it is between the start and - * end positions (inclusive) of this span. Returns true if the position intersects, false otherwise. - * @param position The position to check. - */ - public intersectsWithPosition(position: number): boolean { - return position <= this.end() && position >= this._start; - } - - /** - * Returns the intersection with the given span, or undefined if there is no intersection. - * @param span The span to check. - */ - public intersection(span: TextSpan): TextSpan { - var intersectStart = Math.max(this._start, span._start); - var intersectEnd = Math.min(this.end(), span.end()); - - if (intersectStart <= intersectEnd) { - return TextSpan.fromBounds(intersectStart, intersectEnd); - } - - return undefined; - } - - /** - * Creates a new TextSpan from the given start and end positions - * as opposed to a position and length. - */ - public static fromBounds(start: number, end: number): TextSpan { - Debug.assert(start >= 0); - Debug.assert(end - start >= 0); - return new TextSpan(start, end - start); - } - } - - export class TextChangeRange { - public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0); - - private _span: TextSpan; - private _newLength: number; - - /** - * Initializes a new instance of TextChangeRange. - */ - constructor(span: TextSpan, newLength: number) { - Debug.assert(newLength >= 0, "newLength"); - - this._span = span; - this._newLength = newLength; - } - - /** - * The span of text before the edit which is being changed - */ - public span(): TextSpan { - return this._span; - } - - /** - * Width of the span after the edit. A 0 here would represent a delete - */ - public newLength(): number { - return this._newLength; - } - - public newSpan(): TextSpan { - return new TextSpan(this.span().start(), this.newLength()); - } - - public isUnchanged(): boolean { - return this.span().isEmpty() && this.newLength() === 0; - } - - /** - * Called to merge all the changes that occurred across several versions of a script snapshot - * into a single change. i.e. if a user keeps making successive edits to a script we will - * have a text change from V1 to V2, V2 to V3, ..., Vn. - * - * This function will then merge those changes into a single change range valid between V1 and - * Vn. - */ - public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange { - if (changes.length === 0) { - return TextChangeRange.unchanged; - } - - if (changes.length === 1) { - return changes[0]; - } - - // We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd } - // as it makes things much easier to reason about. - var change0 = changes[0]; - - var oldStartN = change0.span().start(); - var oldEndN = change0.span().end(); - var newEndN = oldStartN + change0.newLength(); - - for (var i = 1; i < changes.length; i++) { - var nextChange = changes[i]; - - // Consider the following case: - // i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting - // at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }. - // i.e. the span starting at 30 with length 30 is increased to length 40. - // - // 0 10 20 30 40 50 60 70 80 90 100 - // ------------------------------------------------------------------------------------------------------- - // | / - // | /---- - // T1 | /---- - // | /---- - // | /---- - // ------------------------------------------------------------------------------------------------------- - // | \ - // | \ - // T2 | \ - // | \ - // | \ - // ------------------------------------------------------------------------------------------------------- - // - // Merging these turns out to not be too difficult. First, determining the new start of the change is trivial - // it's just the min of the old and new starts. i.e.: - // - // 0 10 20 30 40 50 60 70 80 90 100 - // ------------------------------------------------------------*------------------------------------------ - // | / - // | /---- - // T1 | /---- - // | /---- - // | /---- - // ----------------------------------------$-------------------$------------------------------------------ - // . | \ - // . | \ - // T2 . | \ - // . | \ - // . | \ - // ----------------------------------------------------------------------*-------------------------------- - // - // (Note the dots represent the newly inferrred start. - // Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the - // absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see - // which if the two $'s precedes the other, and we move that one forward until they line up. in this case that - // means: - // - // 0 10 20 30 40 50 60 70 80 90 100 - // --------------------------------------------------------------------------------*---------------------- - // | / - // | /---- - // T1 | /---- - // | /---- - // | /---- - // ------------------------------------------------------------$------------------------------------------ - // . | \ - // . | \ - // T2 . | \ - // . | \ - // . | \ - // ----------------------------------------------------------------------*-------------------------------- - // - // In other words (in this case), we're recognizing that the second edit happened after where the first edit - // ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started - // that's the same as if we started at char 80 instead of 60. - // - // As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter - // than pusing the first edit forward to match the second, we'll push the second edit forward to match the - // first. - // - // In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange - // semantics: { { start: 10, length: 70 }, newLength: 60 } - // - // The math then works out as follows. - // If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the - // final result like so: - // - // { - // oldStart3: Min(oldStart1, oldStart2), - // oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)), - // newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)) - // } - - var oldStart1 = oldStartN; - var oldEnd1 = oldEndN; - var newEnd1 = newEndN; - - var oldStart2 = nextChange.span().start(); - var oldEnd2 = nextChange.span().end(); - var newEnd2 = oldStart2 + nextChange.newLength(); - - oldStartN = Math.min(oldStart1, oldStart2); - oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)); - newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2)); - } - - return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN); - } - } export interface ClassifiedSpan { textSpan: TextSpan; @@ -1804,7 +1477,7 @@ module ts { public getChangeRange(filename: string, lastKnownVersion: string, oldScriptSnapshot: IScriptSnapshot): TextChangeRange { var currentVersion = this.getVersion(filename); if (lastKnownVersion === currentVersion) { - return TextChangeRange.unchanged; // "No changes" + return unchangedTextChangeRange; // "No changes" } var scriptSnapshot = this.getScriptSnapshot(filename); @@ -1837,25 +1510,17 @@ module ts { var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); var start = new Date().getTime(); - sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions().target, version, /*isOpen*/ true, /*setNodeParents:*/ true); + sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, ScriptTarget.Latest, version, /*isOpen*/ true, /*setNodeParents;*/ true); this.host.log("SyntaxTreeCache.Initialize: createSourceFile: " + (new Date().getTime() - start)); - - var start = new Date().getTime(); - this.host.log("SyntaxTreeCache.Initialize: fixupParentRefs : " + (new Date().getTime() - start)); } else if (this.currentFileVersion !== version) { var scriptSnapshot = this.hostCache.getScriptSnapshot(filename); - var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.getScriptSnapshot()); + var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.scriptSnapshot); var start = new Date().getTime(); - sourceFile = !editRange - ? createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions().target, version, /*isOpen*/ true, /*setNodeParents:*/ true) - : this.currentSourceFile.update(scriptSnapshot, version, /*isOpen*/ true, editRange); + sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, /*isOpen*/ true, editRange); this.host.log("SyntaxTreeCache.Initialize: updateSourceFile: " + (new Date().getTime() - start)); - - var start = new Date().getTime(); - this.host.log("SyntaxTreeCache.Initialize: fixupParentRefs : " + (new Date().getTime() - start)); } if (sourceFile) { @@ -1872,12 +1537,57 @@ module ts { } public getCurrentScriptSnapshot(filename: string): IScriptSnapshot { - return this.getCurrentSourceFile(filename).getScriptSnapshot(); + return this.getCurrentSourceFile(filename).scriptSnapshot; } } + function setSourceFileFields(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean) { + sourceFile.version = version; + sourceFile.isOpen = isOpen; + sourceFile.scriptSnapshot = scriptSnapshot; + } + export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, isOpen: boolean, setNodeParents: boolean): SourceFile { - return SourceFileObject.createSourceFileObject(filename, scriptSnapshot, scriptTarget, version, isOpen, setNodeParents); + var sourceFile = createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents); + setSourceFileFields(sourceFile, scriptSnapshot, version, isOpen); + return sourceFile; + } + + export var disableIncrementalParsing = true; + + export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile { + if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) { + var oldText = sourceFile.scriptSnapshot; + var newText = scriptSnapshot; + + Debug.assert((oldText.getLength() - textChangeRange.span.length + textChangeRange.newLength) === newText.getLength()); + + if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) { + var oldTextPrefix = oldText.getText(0, textChangeRange.span.start); + var newTextPrefix = newText.getText(0, textChangeRange.span.start); + Debug.assert(oldTextPrefix === newTextPrefix); + + var oldTextSuffix = oldText.getText(textSpanEnd(textChangeRange.span), oldText.getLength()); + var newTextSuffix = newText.getText(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.getLength()); + Debug.assert(oldTextSuffix === newTextSuffix); + } + } + + // If we were given a text change range, and our version or open-ness changed, then + // incrementally parse this file. + if (textChangeRange) { + if (version !== sourceFile.version || isOpen != sourceFile.isOpen) { + // Once incremental parsing is ready, then just call into this function. + if (!disableIncrementalParsing) { + var newSourceFile = sourceFile.update(scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); + setSourceFileFields(newSourceFile, scriptSnapshot, version, isOpen); + return newSourceFile; + } + } + } + + // Otherwise, just create a new source file. + return createLanguageServiceSourceFile(sourceFile.filename, scriptSnapshot, sourceFile.languageVersion, version, isOpen, /*setNodeParents:*/ true); } export function createDocumentRegistry(): DocumentRegistry { @@ -1955,11 +1665,7 @@ module ts { var entry = lookUp(bucket, filename); Debug.assert(entry !== undefined); - if (entry.sourceFile.isOpen === isOpen && entry.sourceFile.version === version) { - return entry.sourceFile; - } - - entry.sourceFile = entry.sourceFile.update(scriptSnapshot, version, isOpen, textChangeRange); + entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, isOpen, textChangeRange); return entry.sourceFile; } @@ -2369,7 +2075,7 @@ module ts { // new text buffer). var textChangeRange: TextChangeRange = null; if (sourceFile.isOpen && isOpen) { - textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.getScriptSnapshot()); + textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.scriptSnapshot); } sourceFile = documentRegistry.updateDocument(sourceFile, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange); @@ -2732,6 +2438,7 @@ module ts { switch (previousToken.kind) { case SyntaxKind.CommaToken: return containingNodeKind === SyntaxKind.VariableDeclaration || + containingNodeKind === SyntaxKind.VariableDeclarationList || containingNodeKind === SyntaxKind.VariableStatement || containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, | isFunction(containingNodeKind); @@ -2925,7 +2632,7 @@ module ts { else if (symbol.valueDeclaration && isConst(symbol.valueDeclaration)) { return ScriptElementKind.constElement; } - else if (forEach(symbol.declarations, declaration => isLet(declaration))) { + else if (forEach(symbol.declarations, isLet)) { return ScriptElementKind.letElement; } return isLocalVariableOrFunction(symbol) ? ScriptElementKind.localVariableElement : ScriptElementKind.variableElement; @@ -2983,11 +2690,12 @@ module ts { case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement; case SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement; case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement; - case SyntaxKind.VariableDeclaration: return isConst(node) - ? ScriptElementKind.constElement - : node.flags & NodeFlags.Let - ? ScriptElementKind.letElement - : ScriptElementKind.variableElement; + case SyntaxKind.VariableDeclaration: + return isConst(node) + ? ScriptElementKind.constElement + : isLet(node) + ? ScriptElementKind.letElement + : ScriptElementKind.variableElement; case SyntaxKind.FunctionDeclaration: return ScriptElementKind.functionElement; case SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement; case SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement; @@ -3168,7 +2876,7 @@ module ts { } if (symbolFlags & SymbolFlags.Enum) { addNewLineIfDisplayPartsExist(); - if (forEach(symbol.declarations, declaration => isConstEnumDeclaration(declaration))) { + if (forEach(symbol.declarations, isConstEnumDeclaration)) { displayParts.push(keywordPart(SyntaxKind.ConstKeyword)); displayParts.push(spacePart()); } @@ -3367,7 +3075,7 @@ module ts { return { kind: ScriptElementKind.unknown, kindModifiers: ScriptElementKindModifier.none, - textSpan: new TextSpan(node.getStart(), node.getWidth()), + textSpan: createTextSpan(node.getStart(), node.getWidth()), displayParts: typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)), documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined }; @@ -3381,7 +3089,7 @@ module ts { return { kind: displayPartsDocumentationsAndKind.symbolKind, kindModifiers: getSymbolModifiers(symbol), - textSpan: new TextSpan(node.getStart(), node.getWidth()), + textSpan: createTextSpan(node.getStart(), node.getWidth()), displayParts: displayPartsDocumentationsAndKind.displayParts, documentation: displayPartsDocumentationsAndKind.documentation }; @@ -3392,7 +3100,7 @@ module ts { function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo { return { fileName: node.getSourceFile().filename, - textSpan: TextSpan.fromBounds(node.getStart(), node.getEnd()), + textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()), kind: symbolKind, name: symbolName, containerKind: undefined, @@ -3469,7 +3177,7 @@ module ts { if (referenceFile) { return [{ fileName: referenceFile.filename, - textSpan: TextSpan.fromBounds(0, 0), + textSpan: createTextSpanFromBounds(0, 0), kind: ScriptElementKind.scriptElement, name: comment.filename, containerName: undefined, @@ -3557,13 +3265,17 @@ module ts { return getThrowOccurrences(node.parent); } break; - case SyntaxKind.TryKeyword: case SyntaxKind.CatchKeyword: - case SyntaxKind.FinallyKeyword: if (hasKind(parent(parent(node)), SyntaxKind.TryStatement)) { return getTryCatchFinallyOccurrences(node.parent.parent); } break; + case SyntaxKind.TryKeyword: + case SyntaxKind.FinallyKeyword: + if (hasKind(parent(node), SyntaxKind.TryStatement)) { + return getTryCatchFinallyOccurrences(node.parent); + } + break; case SyntaxKind.SwitchKeyword: if (hasKind(node.parent, SyntaxKind.SwitchStatement)) { return getSwitchCaseDefaultOccurrences(node.parent); @@ -3660,7 +3372,7 @@ module ts { if (shouldHighlightNextKeyword) { result.push({ fileName: filename, - textSpan: TextSpan.fromBounds(elseKeyword.getStart(), ifKeyword.end), + textSpan: createTextSpanFromBounds(elseKeyword.getStart(), ifKeyword.end), isWriteAccess: false }); i++; // skip the next keyword @@ -3797,7 +3509,8 @@ module ts { } if (tryStatement.finallyBlock) { - pushKeywordIf(keywords, tryStatement.finallyBlock.getFirstToken(), SyntaxKind.FinallyKeyword); + var finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); + pushKeywordIf(keywords, finallyKeyword, SyntaxKind.FinallyKeyword); } return map(keywords, getReferenceEntryFromNode); @@ -4352,7 +4065,7 @@ module ts { (findInComments && isInComment(position))) { result.push({ fileName: sourceFile.filename, - textSpan: new TextSpan(position, searchText.length), + textSpan: createTextSpan(position, searchText.length), isWriteAccess: false }); } @@ -4735,7 +4448,7 @@ module ts { return { fileName: node.getSourceFile().filename, - textSpan: TextSpan.fromBounds(start, end), + textSpan: createTextSpanFromBounds(start, end), isWriteAccess: isWriteAccess(node) }; } @@ -4791,7 +4504,7 @@ module ts { kindModifiers: getNodeModifiers(declaration), matchKind: MatchKind[matchKind], fileName: filename, - textSpan: TextSpan.fromBounds(declaration.getStart(), declaration.getEnd()), + textSpan: createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()), // TODO(jfreeman): What should be the containerName when the container has a computed name? containerName: container && container.name ? (container.name).text : "", containerKind: container && container.name ? getNodeKind(container) : "" @@ -5068,7 +4781,7 @@ module ts { } } - return TextSpan.fromBounds(nodeForStartPos.getStart(), node.getEnd()); + return createTextSpanFromBounds(nodeForStartPos.getStart(), node.getEnd()); } function getBreakpointStatementAtPosition(filename: string, position: number) { @@ -5138,14 +4851,14 @@ module ts { function processNode(node: Node) { // Only walk into nodes that intersect the requested span. - if (node && span.intersectsWith(node.getStart(), node.getWidth())) { + if (node && textSpanIntersectsWith(span, node.getStart(), node.getWidth())) { if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) { var symbol = typeInfoResolver.getSymbolAtLocation(node); if (symbol) { var type = classifySymbol(symbol, getMeaningFromLocation(node)); if (type) { result.push({ - textSpan: new TextSpan(node.getStart(), node.getWidth()), + textSpan: createTextSpan(node.getStart(), node.getWidth()), classificationType: type }); } @@ -5169,9 +4882,9 @@ module ts { function classifyComment(comment: CommentRange) { var width = comment.end - comment.pos; - if (span.intersectsWith(comment.pos, width)) { + if (textSpanIntersectsWith(span, comment.pos, width)) { result.push({ - textSpan: new TextSpan(comment.pos, width), + textSpan: createTextSpan(comment.pos, width), classificationType: ClassificationTypeNames.comment }); } @@ -5184,7 +4897,7 @@ module ts { var type = classifyTokenType(token); if (type) { result.push({ - textSpan: new TextSpan(token.getStart(), token.getWidth()), + textSpan: createTextSpan(token.getStart(), token.getWidth()), classificationType: type }); } @@ -5271,7 +4984,7 @@ module ts { function processElement(element: Node) { // Ignore nodes that don't intersect the original span to classify. - if (span.intersectsWith(element.getFullStart(), element.getFullWidth())) { + if (textSpanIntersectsWith(span, element.getFullStart(), element.getFullWidth())) { var children = element.getChildren(); for (var i = 0, n = children.length; i < n; i++) { var child = children[i]; @@ -5312,11 +5025,11 @@ module ts { var current = childNodes[i]; if (current.kind === matchKind) { - var range1 = new TextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); - var range2 = new TextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); + var range1 = createTextSpan(token.getStart(sourceFile), token.getWidth(sourceFile)); + var range2 = createTextSpan(current.getStart(sourceFile), current.getWidth(sourceFile)); // We want to order the braces when we return the result. - if (range1.start() < range2.start()) { + if (range1.start < range2.start) { result.push(range1, range2); } else { @@ -5564,7 +5277,7 @@ module ts { if (kind) { return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind, getSymbolModifiers(symbol), - new TextSpan(node.getStart(), node.getWidth())); + createTextSpan(node.getStart(), node.getWidth())); } } } diff --git a/src/services/shims.ts b/src/services/shims.ts index 8fce67025fb..3841d397a39 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -203,8 +203,8 @@ module ts { } var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded); - return new TextChangeRange( - new TextSpan(decoded.span.start, decoded.span.length), decoded.newLength); + return createTextChangeRange( + createTextSpan(decoded.span.start, decoded.span.length), decoded.newLength); } } @@ -391,7 +391,7 @@ module ts { return this.forwardJSONCall( "getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")", () => { - var classifications = this.languageService.getSyntacticClassifications(fileName, new TextSpan(start, length)); + var classifications = this.languageService.getSyntacticClassifications(fileName, createTextSpan(start, length)); return classifications; }); } @@ -400,7 +400,7 @@ module ts { return this.forwardJSONCall( "getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")", () => { - var classifications = this.languageService.getSemanticClassifications(fileName, new TextSpan(start, length)); + var classifications = this.languageService.getSemanticClassifications(fileName, createTextSpan(start, length)); return classifications; }); } diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index 408fe60a6cd..426bd732882 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -367,7 +367,7 @@ module ts.SignatureHelp { // but not including parentheses) var applicableSpanStart = argumentsList.getFullStart(); var applicableSpanEnd = skipTrivia(sourceFile.text, argumentsList.getEnd(), /*stopAfterLineBreak*/ false); - return new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); } function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression): TextSpan { @@ -391,7 +391,7 @@ module ts.SignatureHelp { } } - return new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); + return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart); } function getContainingArgumentInfo(node: Node): ArgumentListInfo { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 146ea141d76..10d00398160 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -271,7 +271,7 @@ module ts { } export function getNodeModifiers(node: Node): string { - var flags = node.flags; + var flags = getCombinedNodeFlags(node); var result: string[] = []; if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); diff --git a/tests/baselines/reference/FunctionDeclaration5_es6.errors.txt b/tests/baselines/reference/FunctionDeclaration5_es6.errors.txt index a2ac8381fe2..c68a6cb2057 100644 --- a/tests/baselines/reference/FunctionDeclaration5_es6.errors.txt +++ b/tests/baselines/reference/FunctionDeclaration5_es6.errors.txt @@ -1,13 +1,10 @@ -tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration5_es6.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration5_es6.ts(1,14): error TS1138: Parameter declaration expected. tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration5_es6.ts(1,14): error TS2304: Cannot find name 'yield'. tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration5_es6.ts(1,19): error TS1005: ';' expected. -==== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration5_es6.ts (4 errors) ==== +==== tests/cases/conformance/es6/functionDeclarations/FunctionDeclaration5_es6.ts (3 errors) ==== function*foo(yield) { - ~~~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~~~~~ !!! error TS1138: Parameter declaration expected. ~~~~~ diff --git a/tests/baselines/reference/VariableDeclaration10_es6.errors.txt b/tests/baselines/reference/VariableDeclaration10_es6.errors.txt index 91c071903c4..b7d4bf2f1c3 100644 --- a/tests/baselines/reference/VariableDeclaration10_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration10_es6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration10_es6.ts(1,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration10_es6.ts(1,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration10_es6.ts (1 errors) ==== let a: number = 1 - ~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration2_es6.errors.txt b/tests/baselines/reference/VariableDeclaration2_es6.errors.txt index 1ae59205204..0d8214f5420 100644 --- a/tests/baselines/reference/VariableDeclaration2_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration2_es6.errors.txt @@ -1,10 +1,10 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration2_es6.ts(1,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration2_es6.ts(1,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. tests/cases/conformance/es6/variableDeclarations/VariableDeclaration2_es6.ts(1,7): error TS1155: 'const' declarations must be initialized ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration2_es6.ts (2 errors) ==== const a - ~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. ~ !!! error TS1155: 'const' declarations must be initialized \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration3_es6.errors.txt b/tests/baselines/reference/VariableDeclaration3_es6.errors.txt index e563c4f3ea7..a3b09f70d2d 100644 --- a/tests/baselines/reference/VariableDeclaration3_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration3_es6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration3_es6.ts(1,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration3_es6.ts(1,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration3_es6.ts (1 errors) ==== const a = 1 - ~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration4_es6.errors.txt b/tests/baselines/reference/VariableDeclaration4_es6.errors.txt index 8bb7692fb5f..b4bb75b5658 100644 --- a/tests/baselines/reference/VariableDeclaration4_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration4_es6.errors.txt @@ -1,10 +1,10 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration4_es6.ts(1,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration4_es6.ts(1,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. tests/cases/conformance/es6/variableDeclarations/VariableDeclaration4_es6.ts(1,7): error TS1155: 'const' declarations must be initialized ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration4_es6.ts (2 errors) ==== const a: number - ~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. ~ !!! error TS1155: 'const' declarations must be initialized \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration5_es6.errors.txt b/tests/baselines/reference/VariableDeclaration5_es6.errors.txt index e55f5a26544..c72d423e460 100644 --- a/tests/baselines/reference/VariableDeclaration5_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration5_es6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration5_es6.ts(1,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration5_es6.ts(1,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration5_es6.ts (1 errors) ==== const a: number = 1 - ~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration7_es6.errors.txt b/tests/baselines/reference/VariableDeclaration7_es6.errors.txt index 5de31099e5b..83d12d463e6 100644 --- a/tests/baselines/reference/VariableDeclaration7_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration7_es6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration7_es6.ts(1,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration7_es6.ts(1,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration7_es6.ts (1 errors) ==== let a - ~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration8_es6.errors.txt b/tests/baselines/reference/VariableDeclaration8_es6.errors.txt index 5409c6657c1..e371c64c9a6 100644 --- a/tests/baselines/reference/VariableDeclaration8_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration8_es6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration8_es6.ts(1,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration8_es6.ts(1,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration8_es6.ts (1 errors) ==== let a = 1 - ~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/VariableDeclaration9_es6.errors.txt b/tests/baselines/reference/VariableDeclaration9_es6.errors.txt index 0a2a25858bb..4a1890d4694 100644 --- a/tests/baselines/reference/VariableDeclaration9_es6.errors.txt +++ b/tests/baselines/reference/VariableDeclaration9_es6.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/es6/variableDeclarations/VariableDeclaration9_es6.ts(1,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/conformance/es6/variableDeclarations/VariableDeclaration9_es6.ts(1,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/conformance/es6/variableDeclarations/VariableDeclaration9_es6.ts (1 errors) ==== let a: number - ~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/anonymousModules.errors.txt b/tests/baselines/reference/anonymousModules.errors.txt index eed6442692f..4893a0c80aa 100644 --- a/tests/baselines/reference/anonymousModules.errors.txt +++ b/tests/baselines/reference/anonymousModules.errors.txt @@ -1,29 +1,18 @@ tests/cases/compiler/anonymousModules.ts(1,1): error TS2304: Cannot find name 'module'. tests/cases/compiler/anonymousModules.ts(1,8): error TS1005: ';' expected. -tests/cases/compiler/anonymousModules.ts(2,2): error TS1129: Statement expected. -tests/cases/compiler/anonymousModules.ts(2,2): error TS1148: Cannot compile external modules unless the '--module' flag is provided. tests/cases/compiler/anonymousModules.ts(4,2): error TS2304: Cannot find name 'module'. tests/cases/compiler/anonymousModules.ts(4,9): error TS1005: ';' expected. -tests/cases/compiler/anonymousModules.ts(5,3): error TS1129: Statement expected. -tests/cases/compiler/anonymousModules.ts(5,14): error TS2395: Individual declarations in merged declaration bar must be all exported or all local. -tests/cases/compiler/anonymousModules.ts(6,2): error TS1128: Declaration or statement expected. -tests/cases/compiler/anonymousModules.ts(8,6): error TS2395: Individual declarations in merged declaration bar must be all exported or all local. tests/cases/compiler/anonymousModules.ts(10,2): error TS2304: Cannot find name 'module'. tests/cases/compiler/anonymousModules.ts(10,9): error TS1005: ';' expected. -tests/cases/compiler/anonymousModules.ts(13,1): error TS1128: Declaration or statement expected. -==== tests/cases/compiler/anonymousModules.ts (13 errors) ==== +==== tests/cases/compiler/anonymousModules.ts (6 errors) ==== module { ~~~~~~ !!! error TS2304: Cannot find name 'module'. ~ !!! error TS1005: ';' expected. export var foo = 1; - ~~~~~~ -!!! error TS1129: Statement expected. - ~~~~~~~~~~~~~~~~~~~ -!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. module { ~~~~~~ @@ -31,17 +20,9 @@ tests/cases/compiler/anonymousModules.ts(13,1): error TS1128: Declaration or sta ~ !!! error TS1005: ';' expected. export var bar = 1; - ~~~~~~ -!!! error TS1129: Statement expected. - ~~~ -!!! error TS2395: Individual declarations in merged declaration bar must be all exported or all local. } - ~ -!!! error TS1128: Declaration or statement expected. var bar = 2; - ~~~ -!!! error TS2395: Individual declarations in merged declaration bar must be all exported or all local. module { ~~~~~~ @@ -50,6 +31,4 @@ tests/cases/compiler/anonymousModules.ts(13,1): error TS1128: Declaration or sta !!! error TS1005: ';' expected. var x = bar; } - } - ~ -!!! error TS1128: Declaration or statement expected. \ No newline at end of file + } \ No newline at end of file diff --git a/tests/baselines/reference/bpSpan_const.baseline b/tests/baselines/reference/bpSpan_const.baseline index bee7d930955..176fb76be86 100644 --- a/tests/baselines/reference/bpSpan_const.baseline +++ b/tests/baselines/reference/bpSpan_const.baseline @@ -76,21 +76,21 @@ -------------------------------- 7 > export const cc1 = false; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (181 to 210) SpanInfo: {"start":185,"length":24} - >export const cc1 = false - >:=> (line 7, col 4) to (line 7, col 28) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (181 to 210) SpanInfo: {"start":192,"length":17} + >const cc1 = false + >:=> (line 7, col 11) to (line 7, col 28) -------------------------------- 8 > export const cc2: number = 23; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (211 to 245) SpanInfo: {"start":215,"length":29} - >export const cc2: number = 23 - >:=> (line 8, col 4) to (line 8, col 33) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (211 to 245) SpanInfo: {"start":222,"length":22} + >const cc2: number = 23 + >:=> (line 8, col 11) to (line 8, col 33) -------------------------------- 9 > export const cc3 = 0, cc4 :string = "", cc5 = null; - ~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (246 to 270) SpanInfo: {"start":250,"length":20} - >export const cc3 = 0 - >:=> (line 9, col 4) to (line 9, col 24) + ~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (246 to 270) SpanInfo: {"start":257,"length":13} + >const cc3 = 0 + >:=> (line 9, col 11) to (line 9, col 24) 9 > export const cc3 = 0, cc4 :string = "", cc5 = null; ~~~~~~~~~~~~~~~~~~ => Pos: (271 to 288) SpanInfo: {"start":272,"length":16} diff --git a/tests/baselines/reference/bpSpan_let.baseline b/tests/baselines/reference/bpSpan_let.baseline index dff12280a96..d9a3c2f8547 100644 --- a/tests/baselines/reference/bpSpan_let.baseline +++ b/tests/baselines/reference/bpSpan_let.baseline @@ -84,9 +84,9 @@ -------------------------------- 11 > export let ll2 = 0; - ~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (221 to 244) SpanInfo: {"start":225,"length":18} - >export let ll2 = 0 - >:=> (line 11, col 4) to (line 11, col 22) + ~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (221 to 244) SpanInfo: {"start":232,"length":11} + >let ll2 = 0 + >:=> (line 11, col 11) to (line 11, col 22) -------------------------------- 12 >} ~ => Pos: (245 to 245) SpanInfo: {"start":245,"length":1} diff --git a/tests/baselines/reference/bpSpan_module.baseline b/tests/baselines/reference/bpSpan_module.baseline index 14145512658..e544fc4c432 100644 --- a/tests/baselines/reference/bpSpan_module.baseline +++ b/tests/baselines/reference/bpSpan_module.baseline @@ -50,9 +50,9 @@ -------------------------------- 7 > export var x = 30; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (67 to 93) SpanInfo: {"start":75,"length":17} - >export var x = 30 - >:=> (line 7, col 8) to (line 7, col 25) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (67 to 93) SpanInfo: {"start":82,"length":10} + >var x = 30 + >:=> (line 7, col 15) to (line 7, col 25) -------------------------------- 8 > } @@ -172,15 +172,15 @@ -------------------------------- 25 > { - ~~~~~~ => Pos: (261 to 266) SpanInfo: {"start":275,"length":17} - >export var x = 30 - >:=> (line 26, col 8) to (line 26, col 25) + ~~~~~~ => Pos: (261 to 266) SpanInfo: {"start":282,"length":10} + >var x = 30 + >:=> (line 26, col 15) to (line 26, col 25) -------------------------------- 26 > export var x = 30; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (267 to 293) SpanInfo: {"start":275,"length":17} - >export var x = 30 - >:=> (line 26, col 8) to (line 26, col 25) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (267 to 293) SpanInfo: {"start":282,"length":10} + >var x = 30 + >:=> (line 26, col 15) to (line 26, col 25) -------------------------------- 27 > } diff --git a/tests/baselines/reference/bpSpan_variables.baseline b/tests/baselines/reference/bpSpan_variables.baseline index 1904c34b835..545118daf8d 100644 --- a/tests/baselines/reference/bpSpan_variables.baseline +++ b/tests/baselines/reference/bpSpan_variables.baseline @@ -58,15 +58,13 @@ -------------------------------- 9 > export var xx1; - ~~~~~~~~~~~~~~~~~~~~ => Pos: (119 to 138) SpanInfo: {"start":123,"length":14} - >export var xx1 - >:=> (line 9, col 4) to (line 9, col 18) + ~~~~~~~~~~~~~~~~~~~~ => Pos: (119 to 138) SpanInfo: undefined -------------------------------- 10 > export var xx2 = 10, xx3 = 10; - ~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (139 to 162) SpanInfo: {"start":143,"length":19} - >export var xx2 = 10 - >:=> (line 10, col 4) to (line 10, col 23) + ~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (139 to 162) SpanInfo: {"start":150,"length":12} + >var xx2 = 10 + >:=> (line 10, col 11) to (line 10, col 23) 10 > export var xx2 = 10, xx3 = 10; ~~~~~~~~~~~ => Pos: (163 to 173) SpanInfo: {"start":164,"length":8} @@ -75,14 +73,7 @@ -------------------------------- 11 > export var xx4, xx5; - ~~~~~~~~~~~~~~~~~~~ => Pos: (174 to 192) SpanInfo: {"start":178,"length":14} - >export var xx4 - >:=> (line 11, col 4) to (line 11, col 18) -11 > export var xx4, xx5; - - ~~~~~~ => Pos: (193 to 198) SpanInfo: {"start":194,"length":3} - >xx5 - >:=> (line 11, col 20) to (line 11, col 23) + ~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (174 to 198) SpanInfo: undefined -------------------------------- 12 >} ~ => Pos: (199 to 199) SpanInfo: {"start":199,"length":1} diff --git a/tests/baselines/reference/callSignaturesWithParameterInitializers2.errors.txt b/tests/baselines/reference/callSignaturesWithParameterInitializers2.errors.txt index 2d3dc55dcec..22f8a563e71 100644 --- a/tests/baselines/reference/callSignaturesWithParameterInitializers2.errors.txt +++ b/tests/baselines/reference/callSignaturesWithParameterInitializers2.errors.txt @@ -1,11 +1,12 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(4,14): error TS2371: A parameter initializer is only allowed in a function or constructor implementation. tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(11,9): error TS2371: A parameter initializer is only allowed in a function or constructor implementation. tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(20,5): error TS2300: Duplicate identifier 'foo'. +tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(20,9): error TS2371: A parameter initializer is only allowed in a function or constructor implementation. tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(20,15): error TS1005: '{' expected. tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts(21,5): error TS2300: Duplicate identifier 'foo'. -==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts (5 errors) ==== +==== tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWithParameterInitializers2.ts (6 errors) ==== // Optional parameters allow initializers only in implementation signatures // All the below declarations are errors @@ -32,6 +33,8 @@ tests/cases/conformance/types/objectTypeLiteral/callSignatures/callSignaturesWit foo(x = 1), // error ~~~ !!! error TS2300: Duplicate identifier 'foo'. + ~~~~~ +!!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. ~ !!! error TS1005: '{' expected. foo(x = 1) { }, // error diff --git a/tests/baselines/reference/conflictMarkerTrivia1.errors.txt b/tests/baselines/reference/conflictMarkerTrivia1.errors.txt index 06303378417..1448894a0ee 100644 --- a/tests/baselines/reference/conflictMarkerTrivia1.errors.txt +++ b/tests/baselines/reference/conflictMarkerTrivia1.errors.txt @@ -1,25 +1,25 @@ -tests/cases/compiler/conflictMarkerTrivia1.ts(2,1): error TS1184: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerTrivia1.ts(2,1): error TS1185: Merge conflict marker encountered. tests/cases/compiler/conflictMarkerTrivia1.ts(3,5): error TS2300: Duplicate identifier 'v'. -tests/cases/compiler/conflictMarkerTrivia1.ts(4,1): error TS1184: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerTrivia1.ts(4,1): error TS1185: Merge conflict marker encountered. tests/cases/compiler/conflictMarkerTrivia1.ts(5,5): error TS2300: Duplicate identifier 'v'. -tests/cases/compiler/conflictMarkerTrivia1.ts(6,1): error TS1184: Merge conflict marker encountered. +tests/cases/compiler/conflictMarkerTrivia1.ts(6,1): error TS1185: Merge conflict marker encountered. ==== tests/cases/compiler/conflictMarkerTrivia1.ts (5 errors) ==== class C { <<<<<<< HEAD - -!!! error TS1184: Merge conflict marker encountered. + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. v = 1; ~ !!! error TS2300: Duplicate identifier 'v'. ======= - -!!! error TS1184: Merge conflict marker encountered. + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. v = 2; ~ !!! error TS2300: Duplicate identifier 'v'. >>>>>>> Branch-a - -!!! error TS1184: Merge conflict marker encountered. + ~~~~~~~ +!!! error TS1185: Merge conflict marker encountered. } \ No newline at end of file diff --git a/tests/baselines/reference/constDeclarations-es5.errors.txt b/tests/baselines/reference/constDeclarations-es5.errors.txt index c928e6ae48e..d15535349ac 100644 --- a/tests/baselines/reference/constDeclarations-es5.errors.txt +++ b/tests/baselines/reference/constDeclarations-es5.errors.txt @@ -1,17 +1,17 @@ -tests/cases/compiler/constDeclarations-es5.ts(2,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/constDeclarations-es5.ts(3,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/constDeclarations-es5.ts(4,7): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/constDeclarations-es5.ts(2,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/constDeclarations-es5.ts(3,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/constDeclarations-es5.ts(4,1): error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/compiler/constDeclarations-es5.ts (3 errors) ==== const z7 = false; - ~~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. const z8: number = 23; - ~~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. const z9 = 0, z10 :string = "", z11 = null; - ~~ + ~~~~~ !!! error TS1154: 'const' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/dottedModuleName.errors.txt b/tests/baselines/reference/dottedModuleName.errors.txt index 462ce1dbce0..afb8b944355 100644 --- a/tests/baselines/reference/dottedModuleName.errors.txt +++ b/tests/baselines/reference/dottedModuleName.errors.txt @@ -1,14 +1,11 @@ -tests/cases/compiler/dottedModuleName.ts(3,18): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/compiler/dottedModuleName.ts(3,29): error TS1144: '{' or ';' expected. tests/cases/compiler/dottedModuleName.ts(3,33): error TS2304: Cannot find name 'x'. -==== tests/cases/compiler/dottedModuleName.ts (3 errors) ==== +==== tests/cases/compiler/dottedModuleName.ts (2 errors) ==== module M { export module N { export function f(x:number)=>2*x; - ~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~~ !!! error TS1144: '{' or ';' expected. ~ diff --git a/tests/baselines/reference/functionsWithModifiersInBlocks1.errors.txt b/tests/baselines/reference/functionsWithModifiersInBlocks1.errors.txt new file mode 100644 index 00000000000..94e246f8972 --- /dev/null +++ b/tests/baselines/reference/functionsWithModifiersInBlocks1.errors.txt @@ -0,0 +1,35 @@ +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(2,4): error TS1184: Modifiers cannot appear here. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(2,21): error TS2393: Duplicate function implementation. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(2,25): error TS1184: An implementation cannot be declared in ambient contexts. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(3,4): error TS1184: Modifiers cannot appear here. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(3,20): error TS2393: Duplicate function implementation. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(4,4): error TS1184: Modifiers cannot appear here. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(4,12): error TS1029: 'export' modifier must precede 'declare' modifier. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(4,28): error TS2393: Duplicate function implementation. +tests/cases/compiler/functionsWithModifiersInBlocks1.ts(4,32): error TS1184: An implementation cannot be declared in ambient contexts. + + +==== tests/cases/compiler/functionsWithModifiersInBlocks1.ts (9 errors) ==== + { + declare function f() { } + ~~~~~~~ +!!! error TS1184: Modifiers cannot appear here. + ~ +!!! error TS2393: Duplicate function implementation. + ~ +!!! error TS1184: An implementation cannot be declared in ambient contexts. + export function f() { } + ~~~~~~ +!!! error TS1184: Modifiers cannot appear here. + ~ +!!! error TS2393: Duplicate function implementation. + declare export function f() { } + ~~~~~~~ +!!! error TS1184: Modifiers cannot appear here. + ~~~~~~ +!!! error TS1029: 'export' modifier must precede 'declare' modifier. + ~ +!!! error TS2393: Duplicate function implementation. + ~ +!!! error TS1184: An implementation cannot be declared in ambient contexts. + } \ No newline at end of file diff --git a/tests/baselines/reference/innerModExport1.errors.txt b/tests/baselines/reference/innerModExport1.errors.txt index 25cc83104a8..b4f06cc998a 100644 --- a/tests/baselines/reference/innerModExport1.errors.txt +++ b/tests/baselines/reference/innerModExport1.errors.txt @@ -1,11 +1,8 @@ tests/cases/compiler/innerModExport1.ts(5,5): error TS2304: Cannot find name 'module'. tests/cases/compiler/innerModExport1.ts(5,12): error TS1005: ';' expected. -tests/cases/compiler/innerModExport1.ts(7,9): error TS1129: Statement expected. -tests/cases/compiler/innerModExport1.ts(14,5): error TS1148: Cannot compile external modules unless the '--module' flag is provided. -tests/cases/compiler/innerModExport1.ts(17,1): error TS1128: Declaration or statement expected. -==== tests/cases/compiler/innerModExport1.ts (5 errors) ==== +==== tests/cases/compiler/innerModExport1.ts (2 errors) ==== module Outer { // inner mod 1 @@ -17,8 +14,6 @@ tests/cases/compiler/innerModExport1.ts(17,1): error TS1128: Declaration or stat !!! error TS1005: ';' expected. var non_export_var = 0; export var export_var = 1; - ~~~~~~ -!!! error TS1129: Statement expected. function NonExportFunc() { return 0; } @@ -26,12 +21,8 @@ tests/cases/compiler/innerModExport1.ts(17,1): error TS1128: Declaration or stat } export var outer_var_export = 0; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. export function outerFuncExport() { return 0; } } - ~ -!!! error TS1128: Declaration or statement expected. Outer.ExportFunc(); \ No newline at end of file diff --git a/tests/baselines/reference/innerModExport2.errors.txt b/tests/baselines/reference/innerModExport2.errors.txt index 1456e976372..52a9d01c997 100644 --- a/tests/baselines/reference/innerModExport2.errors.txt +++ b/tests/baselines/reference/innerModExport2.errors.txt @@ -1,12 +1,11 @@ tests/cases/compiler/innerModExport2.ts(5,5): error TS2304: Cannot find name 'module'. tests/cases/compiler/innerModExport2.ts(5,12): error TS1005: ';' expected. -tests/cases/compiler/innerModExport2.ts(7,9): error TS1129: Statement expected. -tests/cases/compiler/innerModExport2.ts(15,5): error TS1148: Cannot compile external modules unless the '--module' flag is provided. -tests/cases/compiler/innerModExport2.ts(18,1): error TS1128: Declaration or statement expected. +tests/cases/compiler/innerModExport2.ts(7,20): error TS2395: Individual declarations in merged declaration export_var must be all exported or all local. +tests/cases/compiler/innerModExport2.ts(13,9): error TS2395: Individual declarations in merged declaration export_var must be all exported or all local. tests/cases/compiler/innerModExport2.ts(20,7): error TS2339: Property 'NonExportFunc' does not exist on type 'typeof Outer'. -==== tests/cases/compiler/innerModExport2.ts (6 errors) ==== +==== tests/cases/compiler/innerModExport2.ts (5 errors) ==== module Outer { // inner mod 1 @@ -18,23 +17,21 @@ tests/cases/compiler/innerModExport2.ts(20,7): error TS2339: Property 'NonExport !!! error TS1005: ';' expected. var non_export_var = 0; export var export_var = 1; - ~~~~~~ -!!! error TS1129: Statement expected. + ~~~~~~~~~~ +!!! error TS2395: Individual declarations in merged declaration export_var must be all exported or all local. function NonExportFunc() { return 0; } export function ExportFunc() { return 0; } } var export_var: number; + ~~~~~~~~~~ +!!! error TS2395: Individual declarations in merged declaration export_var must be all exported or all local. export var outer_var_export = 0; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. export function outerFuncExport() { return 0; } } - ~ -!!! error TS1128: Declaration or statement expected. Outer.NonExportFunc(); ~~~~~~~~~~~~~ diff --git a/tests/baselines/reference/letDeclarations-es5-1.errors.txt b/tests/baselines/reference/letDeclarations-es5-1.errors.txt index f0430585a3b..f8b5cf629d2 100644 --- a/tests/baselines/reference/letDeclarations-es5-1.errors.txt +++ b/tests/baselines/reference/letDeclarations-es5-1.errors.txt @@ -1,27 +1,27 @@ -tests/cases/compiler/letDeclarations-es5-1.ts(1,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5-1.ts(2,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5-1.ts(3,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5-1.ts(4,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5-1.ts(5,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5-1.ts(6,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5-1.ts(1,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5-1.ts(2,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5-1.ts(3,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5-1.ts(4,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5-1.ts(5,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5-1.ts(6,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/compiler/letDeclarations-es5-1.ts (6 errors) ==== let l1; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l2: number; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l3, l4, l5 :string, l6; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l7 = false; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l8: number = 23; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l9 = 0, l10 :string = "", l11 = null; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/letDeclarations-es5.errors.txt b/tests/baselines/reference/letDeclarations-es5.errors.txt index 34bd93dba3c..27d526f03ea 100644 --- a/tests/baselines/reference/letDeclarations-es5.errors.txt +++ b/tests/baselines/reference/letDeclarations-es5.errors.txt @@ -1,40 +1,40 @@ -tests/cases/compiler/letDeclarations-es5.ts(2,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(3,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(4,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(6,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(7,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(8,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(10,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. -tests/cases/compiler/letDeclarations-es5.ts(12,9): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(2,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(3,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(4,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(6,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(7,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(8,1): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(10,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. +tests/cases/compiler/letDeclarations-es5.ts(12,5): error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. ==== tests/cases/compiler/letDeclarations-es5.ts (8 errors) ==== let l1; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l2: number; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l3, l4, l5 :string, l6; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l7 = false; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l8: number = 23; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. let l9 = 0, l10 :string = "", l11 = null; - ~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. for(let l11 in {}) { } - ~~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. for(let l12 = 0; l12 < 9; l12++) { } - ~~~ + ~~~ !!! error TS1153: 'let' declarations are only available when targeting ECMAScript 6 and higher. \ No newline at end of file diff --git a/tests/baselines/reference/modifiersOnInterfaceIndexSignature1.errors.txt b/tests/baselines/reference/modifiersOnInterfaceIndexSignature1.errors.txt new file mode 100644 index 00000000000..b325710a9f0 --- /dev/null +++ b/tests/baselines/reference/modifiersOnInterfaceIndexSignature1.errors.txt @@ -0,0 +1,9 @@ +tests/cases/compiler/modifiersOnInterfaceIndexSignature1.ts(2,3): error TS1145: Modifiers not permitted on index signature members. + + +==== tests/cases/compiler/modifiersOnInterfaceIndexSignature1.ts (1 errors) ==== + interface I { + public [a: string]: number; + ~~~~~~ +!!! error TS1145: Modifiers not permitted on index signature members. + } \ No newline at end of file diff --git a/tests/baselines/reference/noCatchBlock.js.map b/tests/baselines/reference/noCatchBlock.js.map index dccc7798c92..149a2167f46 100644 --- a/tests/baselines/reference/noCatchBlock.js.map +++ b/tests/baselines/reference/noCatchBlock.js.map @@ -1,2 +1,2 @@ //// [noCatchBlock.js.map] -{"version":3,"file":"noCatchBlock.js","sourceRoot":"","sources":["noCatchBlock.ts"],"names":[],"mappings":"AACA,IAAA,CAAC;AAED,CAAC;QAAC,CAAC;AAEH,CAAC"} \ No newline at end of file +{"version":3,"file":"noCatchBlock.js","sourceRoot":"","sources":["noCatchBlock.ts"],"names":[],"mappings":"AACA,IAAI,CAAC;AAEL,CAAC;QAAS,CAAC;AAEX,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/noCatchBlock.sourcemap.txt b/tests/baselines/reference/noCatchBlock.sourcemap.txt index 8d5a67339f6..18cb0d5a479 100644 --- a/tests/baselines/reference/noCatchBlock.sourcemap.txt +++ b/tests/baselines/reference/noCatchBlock.sourcemap.txt @@ -14,17 +14,17 @@ sourceFile:noCatchBlock.ts 3 > ^ 1 > > -2 > -3 > t +2 >try +3 > { 1 >Emitted(1, 1) Source(2, 1) + SourceIndex(0) -2 >Emitted(1, 5) Source(2, 1) + SourceIndex(0) -3 >Emitted(1, 6) Source(2, 2) + SourceIndex(0) +2 >Emitted(1, 5) Source(2, 5) + SourceIndex(0) +3 >Emitted(1, 6) Source(2, 6) + SourceIndex(0) --- >>>} 1 > 2 >^ 3 > ^^^^^^^^^-> -1 >ry { +1 > > // ... > 2 >} @@ -34,16 +34,16 @@ sourceFile:noCatchBlock.ts >>>finally { 1->^^^^^^^^ 2 > ^ -1-> -2 > f -1->Emitted(3, 9) Source(4, 3) + SourceIndex(0) -2 >Emitted(3, 10) Source(4, 4) + SourceIndex(0) +1-> finally +2 > { +1->Emitted(3, 9) Source(4, 11) + SourceIndex(0) +2 >Emitted(3, 10) Source(4, 12) + SourceIndex(0) --- >>>} 1 > 2 >^ 3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> -1 >inally { +1 > > // N.B. No 'catch' block > 2 >} diff --git a/tests/baselines/reference/objectLiteralMemberWithModifiers1.errors.txt b/tests/baselines/reference/objectLiteralMemberWithModifiers1.errors.txt new file mode 100644 index 00000000000..9e739194f54 --- /dev/null +++ b/tests/baselines/reference/objectLiteralMemberWithModifiers1.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/objectLiteralMemberWithModifiers1.ts(1,11): error TS1184: Modifiers cannot appear here. + + +==== tests/cases/compiler/objectLiteralMemberWithModifiers1.ts (1 errors) ==== + var v = { public foo() { } } + ~~~~~~ +!!! error TS1184: Modifiers cannot appear here. \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralMemberWithModifiers1.js b/tests/baselines/reference/objectLiteralMemberWithModifiers1.js new file mode 100644 index 00000000000..8b8c76be518 --- /dev/null +++ b/tests/baselines/reference/objectLiteralMemberWithModifiers1.js @@ -0,0 +1,6 @@ +//// [objectLiteralMemberWithModifiers1.ts] +var v = { public foo() { } } + +//// [objectLiteralMemberWithModifiers1.js] +var v = { foo: function () { +} }; diff --git a/tests/baselines/reference/objectLiteralMemberWithModifiers2.errors.txt b/tests/baselines/reference/objectLiteralMemberWithModifiers2.errors.txt new file mode 100644 index 00000000000..9fe5365f7da --- /dev/null +++ b/tests/baselines/reference/objectLiteralMemberWithModifiers2.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/objectLiteralMemberWithModifiers2.ts(1,11): error TS1184: Modifiers cannot appear here. +tests/cases/compiler/objectLiteralMemberWithModifiers2.ts(1,22): error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement. + + +==== tests/cases/compiler/objectLiteralMemberWithModifiers2.ts (2 errors) ==== + var v = { public get foo() { } } + ~~~~~~ +!!! error TS1184: Modifiers cannot appear here. + ~~~ +!!! error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement. \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralMemberWithModifiers2.js b/tests/baselines/reference/objectLiteralMemberWithModifiers2.js new file mode 100644 index 00000000000..fd8e0a68430 --- /dev/null +++ b/tests/baselines/reference/objectLiteralMemberWithModifiers2.js @@ -0,0 +1,6 @@ +//// [objectLiteralMemberWithModifiers2.ts] +var v = { public get foo() { } } + +//// [objectLiteralMemberWithModifiers2.js] +var v = { get foo() { +} }; diff --git a/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt b/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt new file mode 100644 index 00000000000..b10ba701143 --- /dev/null +++ b/tests/baselines/reference/objectLiteralMemberWithQuestionMark1.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts(1,14): error TS1112: A class member cannot be declared optional. + + +==== tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts (1 errors) ==== + var v = { foo?() { } } + ~ +!!! error TS1112: A class member cannot be declared optional. \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralMemberWithoutBlock1.errors.txt b/tests/baselines/reference/objectLiteralMemberWithoutBlock1.errors.txt new file mode 100644 index 00000000000..fa5fb104c82 --- /dev/null +++ b/tests/baselines/reference/objectLiteralMemberWithoutBlock1.errors.txt @@ -0,0 +1,7 @@ +tests/cases/compiler/objectLiteralMemberWithoutBlock1.ts(1,16): error TS1005: '{' expected. + + +==== tests/cases/compiler/objectLiteralMemberWithoutBlock1.ts (1 errors) ==== + var v = { foo(); } + ~ +!!! error TS1005: '{' expected. \ No newline at end of file diff --git a/tests/baselines/reference/objectTypesWithOptionalProperties2.errors.txt b/tests/baselines/reference/objectTypesWithOptionalProperties2.errors.txt index 227df7111c5..761fba18b15 100644 --- a/tests/baselines/reference/objectTypesWithOptionalProperties2.errors.txt +++ b/tests/baselines/reference/objectTypesWithOptionalProperties2.errors.txt @@ -2,12 +2,10 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(4,9): error TS1131: Property or signature expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(8,8): error TS1005: ';' expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(8,9): error TS1131: Property or signature expected. -tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(12,5): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(12,8): error TS1144: '{' or ';' expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(12,9): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(16,8): error TS1005: ';' expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(16,9): error TS1131: Property or signature expected. -tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(20,5): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(20,8): error TS1144: '{' or ';' expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(20,9): error TS1068: Unexpected token. A constructor, method, accessor, or property was expected. tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(25,8): error TS1005: '{' expected. @@ -15,7 +13,7 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts(26,1): error TS1005: ':' expected. -==== tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts (15 errors) ==== +==== tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWithOptionalProperties2.ts (13 errors) ==== // Illegal attempts to define optional methods var a: { @@ -36,8 +34,6 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith class C { x()?: number; // error - ~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~ !!! error TS1144: '{' or ';' expected. ~ @@ -54,8 +50,6 @@ tests/cases/conformance/types/objectTypeLiteral/methodSignatures/objectTypesWith class C2 { x()?: T; // error - ~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~ !!! error TS1144: '{' or ';' expected. ~ diff --git a/tests/baselines/reference/parserAccessors10.errors.txt b/tests/baselines/reference/parserAccessors10.errors.txt index 39b96651485..ac552b55c6a 100644 --- a/tests/baselines/reference/parserAccessors10.errors.txt +++ b/tests/baselines/reference/parserAccessors10.errors.txt @@ -1,15 +1,12 @@ -tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts(2,10): error TS1005: ':' expected. -tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts(2,10): error TS2304: Cannot find name 'get'. -tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts(2,14): error TS1005: ',' expected. +tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts(2,3): error TS1184: Modifiers cannot appear here. +tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts(2,14): error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement. -==== tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts (3 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/Accessors/parserAccessors10.ts (2 errors) ==== var v = { public get foo() { } - ~~~ -!!! error TS1005: ':' expected. - ~~~ -!!! error TS2304: Cannot find name 'get'. + ~~~~~~ +!!! error TS1184: Modifiers cannot appear here. ~~~ -!!! error TS1005: ',' expected. +!!! error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement. }; \ No newline at end of file diff --git a/tests/baselines/reference/parserAccessors10.js b/tests/baselines/reference/parserAccessors10.js new file mode 100644 index 00000000000..f1bed41edee --- /dev/null +++ b/tests/baselines/reference/parserAccessors10.js @@ -0,0 +1,10 @@ +//// [parserAccessors10.ts] +var v = { + public get foo() { } +}; + +//// [parserAccessors10.js] +var v = { + get foo() { + } +}; diff --git a/tests/baselines/reference/parserComputedPropertyName5.errors.txt b/tests/baselines/reference/parserComputedPropertyName5.errors.txt index 39c5daa0622..f0dd056fdf9 100644 --- a/tests/baselines/reference/parserComputedPropertyName5.errors.txt +++ b/tests/baselines/reference/parserComputedPropertyName5.errors.txt @@ -1,19 +1,7 @@ -tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts(1,18): error TS1005: ':' expected. -tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts(1,18): error TS2304: Cannot find name 'get'. -tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts(1,23): error TS2304: Cannot find name 'e'. -tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts(1,28): error TS1005: ',' expected. -tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts(1,32): error TS1128: Declaration or statement expected. +tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts(1,22): error TS9002: Computed property names are not currently supported. -==== tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts (5 errors) ==== +==== tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName5.ts (1 errors) ==== var v = { public get [e]() { } }; - ~~~ -!!! error TS1005: ':' expected. - ~~~ -!!! error TS2304: Cannot find name 'get'. - ~ -!!! error TS2304: Cannot find name 'e'. - ~ -!!! error TS1005: ',' expected. - ~ -!!! error TS1128: Declaration or statement expected. \ No newline at end of file + ~~~ +!!! error TS9002: Computed property names are not currently supported. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction1.errors.txt b/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction1.errors.txt index 0e2c2b9d12a..4f4c37c78be 100644 --- a/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction1.errors.txt +++ b/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction1.errors.txt @@ -1,10 +1,7 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction1.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction1.ts(1,14): error TS1144: '{' or ';' expected. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction1.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction1.ts (1 errors) ==== function f() => 4; - ~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~~ !!! error TS1144: '{' or ';' expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction2.errors.txt b/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction2.errors.txt index a1e251798c2..0a075c960b6 100644 --- a/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction2.errors.txt +++ b/tests/baselines/reference/parserErrantEqualsGreaterThanAfterFunction2.errors.txt @@ -1,13 +1,10 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction2.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction2.ts(1,15): error TS2304: Cannot find name 'A'. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction2.ts(1,18): error TS1144: '{' or ';' expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction2.ts(1,21): error TS2304: Cannot find name 'p'. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction2.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserErrantEqualsGreaterThanAfterFunction2.ts (3 errors) ==== function f(p: A) => p; - ~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~ !!! error TS2304: Cannot find name 'A'. ~~ diff --git a/tests/baselines/reference/parserErrorRecovery_ParameterList6.errors.txt b/tests/baselines/reference/parserErrorRecovery_ParameterList6.errors.txt index 5da6749a288..61ad2fb175f 100644 --- a/tests/baselines/reference/parserErrorRecovery_ParameterList6.errors.txt +++ b/tests/baselines/reference/parserErrorRecovery_ParameterList6.errors.txt @@ -1,14 +1,11 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList6.ts(2,12): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList6.ts(2,23): error TS1110: Type expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList6.ts(2,28): error TS1003: Identifier expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList6.ts(3,1): error TS1128: Declaration or statement expected. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList6.ts (4 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/ParameterLists/parserErrorRecovery_ParameterList6.ts (3 errors) ==== class Foo { public banana (x: break) { } - ~~~~~~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. ~~~~~ !!! error TS1110: Type expected. ~ diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock1.errors.txt b/tests/baselines/reference/parserModifierOnStatementInBlock1.errors.txt index c24bc0997c6..5fa104a0e83 100644 --- a/tests/baselines/reference/parserModifierOnStatementInBlock1.errors.txt +++ b/tests/baselines/reference/parserModifierOnStatementInBlock1.errors.txt @@ -1,16 +1,15 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock1.ts(1,1): error TS1148: Cannot compile external modules unless the '--module' flag is provided. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock1.ts(2,4): error TS1129: Statement expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock1.ts(3,1): error TS1128: Declaration or statement expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock1.ts(2,4): error TS1184: Modifiers cannot appear here. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock1.ts (3 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock1.ts (2 errors) ==== export function foo() { ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. export var x = this; + ~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ -!!! error TS1129: Statement expected. +!!! error TS1184: Modifiers cannot appear here. } ~ -!!! error TS1128: Declaration or statement expected. +!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. \ No newline at end of file diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock2.errors.txt b/tests/baselines/reference/parserModifierOnStatementInBlock2.errors.txt index accdc0b062a..d863bf7143e 100644 --- a/tests/baselines/reference/parserModifierOnStatementInBlock2.errors.txt +++ b/tests/baselines/reference/parserModifierOnStatementInBlock2.errors.txt @@ -1,13 +1,13 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,4): error TS2304: Cannot find name 'declare'. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,12): error TS1005: ';' expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,4): error TS1184: Modifiers cannot appear here. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts(2,18): error TS1039: Initializers are not allowed in ambient contexts. ==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock2.ts (2 errors) ==== { declare var x = this; ~~~~~~~ -!!! error TS2304: Cannot find name 'declare'. - ~~~ -!!! error TS1005: ';' expected. +!!! error TS1184: Modifiers cannot appear here. + ~ +!!! error TS1039: Initializers are not allowed in ambient contexts. } \ No newline at end of file diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock3.errors.txt b/tests/baselines/reference/parserModifierOnStatementInBlock3.errors.txt index ebb793783a2..5bc5a49670e 100644 --- a/tests/baselines/reference/parserModifierOnStatementInBlock3.errors.txt +++ b/tests/baselines/reference/parserModifierOnStatementInBlock3.errors.txt @@ -1,17 +1,17 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock3.ts(1,1): error TS1148: Cannot compile external modules unless the '--module' flag is provided. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock3.ts(2,4): error TS1129: Statement expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock3.ts(4,1): error TS1128: Declaration or statement expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock3.ts(2,4): error TS1184: Modifiers cannot appear here. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock3.ts (3 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock3.ts (2 errors) ==== export function foo() { ~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. export function bar() { + ~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ -!!! error TS1129: Statement expected. +!!! error TS1184: Modifiers cannot appear here. } + ~~~~ } ~ -!!! error TS1128: Declaration or statement expected. +!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. \ No newline at end of file diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock4.errors.txt b/tests/baselines/reference/parserModifierOnStatementInBlock4.errors.txt index b84f88c0b9a..4fc38af7d5d 100644 --- a/tests/baselines/reference/parserModifierOnStatementInBlock4.errors.txt +++ b/tests/baselines/reference/parserModifierOnStatementInBlock4.errors.txt @@ -1,18 +1,11 @@ -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts(2,4): error TS1129: Statement expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts(2,4): error TS1148: Cannot compile external modules unless the '--module' flag is provided. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts(4,1): error TS1128: Declaration or statement expected. +tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts(2,4): error TS1184: Modifiers cannot appear here. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts (3 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserModifierOnStatementInBlock4.ts (1 errors) ==== { export function bar() { ~~~~~~ -!!! error TS1129: Statement expected. - ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1184: Modifiers cannot appear here. } - ~~~~ -!!! error TS1148: Cannot compile external modules unless the '--module' flag is provided. } - ~ -!!! error TS1128: Declaration or statement expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserModifierOnStatementInBlock4.js b/tests/baselines/reference/parserModifierOnStatementInBlock4.js new file mode 100644 index 00000000000..82d2475a689 --- /dev/null +++ b/tests/baselines/reference/parserModifierOnStatementInBlock4.js @@ -0,0 +1,13 @@ +//// [parserModifierOnStatementInBlock4.ts] +{ + export function bar() { + } +} + + +//// [parserModifierOnStatementInBlock4.js] +{ + function bar() { + } + exports.bar = bar; +} diff --git a/tests/baselines/reference/parserSkippedTokens16.errors.txt b/tests/baselines/reference/parserSkippedTokens16.errors.txt index 7359611ef08..fc3565e9786 100644 --- a/tests/baselines/reference/parserSkippedTokens16.errors.txt +++ b/tests/baselines/reference/parserSkippedTokens16.errors.txt @@ -2,14 +2,13 @@ tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.t tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(1,6): error TS1005: ';' expected. tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(1,8): error TS2304: Cannot find name 'Bar'. tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(1,12): error TS1005: ';' expected. -tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(2,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(2,22): error TS1127: Invalid character. tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(3,3): error TS1109: Expression expected. tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(6,5): error TS1138: Parameter declaration expected. tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts(8,14): error TS1109: Expression expected. -==== tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts (9 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.ts (8 errors) ==== foo(): Bar { } ~~~ !!! error TS2304: Cannot find name 'foo'. @@ -20,8 +19,6 @@ tests/cases/conformance/parser/ecmascript5/SkippedTokens/parserSkippedTokens16.t ~ !!! error TS1005: ';' expected. function Foo () # { } - ~~~ -!!! error TS2391: Function implementation is missing or not immediately following the declaration. !!! error TS1127: Invalid character. 4+:5 diff --git a/tests/baselines/reference/privateIndexer2.errors.txt b/tests/baselines/reference/privateIndexer2.errors.txt index 5208b0908ee..8d3c1ec1e6d 100644 --- a/tests/baselines/reference/privateIndexer2.errors.txt +++ b/tests/baselines/reference/privateIndexer2.errors.txt @@ -1,32 +1,21 @@ -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,13): error TS1005: ':' expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,15): error TS1005: ',' expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,17): error TS2304: Cannot find name 'string'. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,24): error TS1005: ',' expected. +tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,15): error TS1005: ']' expected. +tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,23): error TS1005: ',' expected. +tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,24): error TS1136: Property assignment expected. tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(4,32): error TS1005: ':' expected. tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(5,1): error TS1128: Declaration or statement expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,5): error TS1131: Property or signature expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,5): error TS2304: Cannot find name 'private'. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,14): error TS1005: ']' expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,16): error TS2304: Cannot find name 'string'. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,22): error TS1005: ';' expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,23): error TS1128: Declaration or statement expected. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(8,25): error TS2304: Cannot find name 'string'. -tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(9,1): error TS1128: Declaration or statement expected. -==== tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts (14 errors) ==== +==== tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts (5 errors) ==== // private indexers not allowed var x = { private [x: string]: string; - ~ -!!! error TS1005: ':' expected. ~ +!!! error TS1005: ']' expected. + ~ !!! error TS1005: ',' expected. - ~~~~~~ -!!! error TS2304: Cannot find name 'string'. ~ -!!! error TS1005: ',' expected. +!!! error TS1136: Property assignment expected. ~ !!! error TS1005: ':' expected. } @@ -35,20 +24,4 @@ tests/cases/conformance/classes/indexMemberDeclarations/privateIndexer2.ts(9,1): var y: { private[x: string]: string; - ~~~~~~~ -!!! error TS1131: Property or signature expected. - ~~~~~~~ -!!! error TS2304: Cannot find name 'private'. - ~ -!!! error TS1005: ']' expected. - ~~~~~~ -!!! error TS2304: Cannot find name 'string'. - ~ -!!! error TS1005: ';' expected. - ~ -!!! error TS1128: Declaration or statement expected. - ~~~~~~ -!!! error TS2304: Cannot find name 'string'. - } - ~ -!!! error TS1128: Declaration or statement expected. \ No newline at end of file + } \ No newline at end of file diff --git a/tests/baselines/reference/promiseChaining.js b/tests/baselines/reference/promiseChaining.js index 1d0962d30db..20961542b22 100644 --- a/tests/baselines/reference/promiseChaining.js +++ b/tests/baselines/reference/promiseChaining.js @@ -19,7 +19,7 @@ var Chain = (function () { Chain.prototype.then = function (cb) { var result = cb(this.value); // should get a fresh type parameter which each then call - var z = this.then(function (x) { return result; }).then(function (x) { return "abc"; }).then(function (x) { return x.length; }) /*number*/; // No error + var z = this.then(function (x) { return result; }).then(function (x) { return "abc"; }).then(function (x) { return x.length; }); // No error return new Chain(result); }; return Chain; diff --git a/tests/baselines/reference/promiseChaining1.js b/tests/baselines/reference/promiseChaining1.js index 9dc167f2db6..ee79d3268ba 100644 --- a/tests/baselines/reference/promiseChaining1.js +++ b/tests/baselines/reference/promiseChaining1.js @@ -19,7 +19,7 @@ var Chain2 = (function () { Chain2.prototype.then = function (cb) { var result = cb(this.value); // should get a fresh type parameter which each then call - var z = this.then(function (x) { return result; }).then(function (x) { return "abc"; }).then(function (x) { return x.length; }) /*number*/; // Should error on "abc" because it is not a Function + var z = this.then(function (x) { return result; }).then(function (x) { return "abc"; }).then(function (x) { return x.length; }); // Should error on "abc" because it is not a Function return new Chain2(result); }; return Chain2; diff --git a/tests/baselines/reference/restElementWithInitializer1.errors.txt b/tests/baselines/reference/restElementWithInitializer1.errors.txt index 6cee9d5286a..aa23192c7bc 100644 --- a/tests/baselines/reference/restElementWithInitializer1.errors.txt +++ b/tests/baselines/reference/restElementWithInitializer1.errors.txt @@ -1,9 +1,9 @@ -tests/cases/conformance/es6/destructuring/restElementWithInitializer1.ts(2,11): error TS1185: A rest element cannot have an initializer. +tests/cases/conformance/es6/destructuring/restElementWithInitializer1.ts(2,11): error TS1186: A rest element cannot have an initializer. ==== tests/cases/conformance/es6/destructuring/restElementWithInitializer1.ts (1 errors) ==== var a: number[]; var [...x = a] = a; // Error, rest element cannot have initializer ~ -!!! error TS1185: A rest element cannot have an initializer. +!!! error TS1186: A rest element cannot have an initializer. \ No newline at end of file diff --git a/tests/baselines/reference/sourceMap-SkippedNode.js.map b/tests/baselines/reference/sourceMap-SkippedNode.js.map index cdcdc804634..77340424640 100644 --- a/tests/baselines/reference/sourceMap-SkippedNode.js.map +++ b/tests/baselines/reference/sourceMap-SkippedNode.js.map @@ -1,2 +1,2 @@ //// [sourceMap-SkippedNode.js.map] -{"version":3,"file":"sourceMap-SkippedNode.js","sourceRoot":"","sources":["sourceMap-SkippedNode.ts"],"names":[],"mappings":"AAAA,IAAA,CAAC;AAED,CAAC;QAAC,CAAC;AAEH,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMap-SkippedNode.js","sourceRoot":"","sources":["sourceMap-SkippedNode.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC;AAEL,CAAC;QAAS,CAAC;AAEX,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMap-SkippedNode.sourcemap.txt b/tests/baselines/reference/sourceMap-SkippedNode.sourcemap.txt index 531a666ade0..f68320a531f 100644 --- a/tests/baselines/reference/sourceMap-SkippedNode.sourcemap.txt +++ b/tests/baselines/reference/sourceMap-SkippedNode.sourcemap.txt @@ -13,17 +13,17 @@ sourceFile:sourceMap-SkippedNode.ts 2 >^^^^ 3 > ^ 1 > -2 > -3 > t +2 >try +3 > { 1 >Emitted(1, 1) Source(1, 1) + SourceIndex(0) -2 >Emitted(1, 5) Source(1, 1) + SourceIndex(0) -3 >Emitted(1, 6) Source(1, 2) + SourceIndex(0) +2 >Emitted(1, 5) Source(1, 5) + SourceIndex(0) +3 >Emitted(1, 6) Source(1, 6) + SourceIndex(0) --- >>>} 1 > 2 >^ 3 > ^^^^^^^^^-> -1 >ry { +1 > >// ... > 2 >} @@ -33,16 +33,16 @@ sourceFile:sourceMap-SkippedNode.ts >>>finally { 1->^^^^^^^^ 2 > ^ -1-> -2 > f -1->Emitted(3, 9) Source(3, 3) + SourceIndex(0) -2 >Emitted(3, 10) Source(3, 4) + SourceIndex(0) +1-> finally +2 > { +1->Emitted(3, 9) Source(3, 11) + SourceIndex(0) +2 >Emitted(3, 10) Source(3, 12) + SourceIndex(0) --- >>>} 1 > 2 >^ 3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> -1 >inally { +1 > >// N.B. No 'catch' block > 2 >} diff --git a/tests/baselines/reference/sourceMapValidationStatements.js.map b/tests/baselines/reference/sourceMapValidationStatements.js.map index 8eb99944914..7bf883de6c3 100644 --- a/tests/baselines/reference/sourceMapValidationStatements.js.map +++ b/tests/baselines/reference/sourceMapValidationStatements.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationStatements.js.map] -{"version":3,"file":"sourceMapValidationStatements.js","sourceRoot":"","sources":["sourceMapValidationStatements.ts"],"names":["f"],"mappings":"AAAA,SAAS,CAAC;IACNA,IAAIA,CAACA,CAACA;IACNA,IAAIA,CAACA,GAAGA,CAACA,CAACA;IACVA,GAAGA,CAACA,CAACA,GAAGA,CAACA,CAACA,GAAGA,CAACA,EAAEA,CAACA,GAAGA,EAAEA,EAAEA,CAACA,EAAEA,EAAEA,CAACA;QAC1BA,CAACA,IAAIA,CAACA,CAACA;QACPA,CAACA,IAAIA,CAACA,CAACA;IACXA,CAACA;IACDA,EAAEA,CAACA,CAACA,CAACA,GAAGA,EAAEA,CAACA,CAACA,CAACA;QACTA,CAACA,IAAIA,CAACA,CAACA;IACXA,CAACA;IAACA,IAAIA,CAACA,CAACA;QACJA,CAACA,IAAIA,EAAEA,CAACA;QACRA,CAACA,EAAEA,CAACA;IACRA,CAACA;IACDA,IAAIA,CAACA,GAAGA;QACJA,CAACA;QACDA,CAACA;QACDA,CAACA;KACJA,CAACA;IACFA,IAAIA,GAAGA,GAAGA;QACNA,CAACA,EAAEA,CAACA;QACJA,CAACA,EAAEA,OAAOA;KACbA,CAACA;IACFA,GAAGA,CAACA,CAACA,GAAGA,CAACA,CAACA,IAAIA,CAACA,CAACA,CAACA,CAACA;QACdA,GAAGA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA,CAACA,CAACA;QACbA,IAAIA,CAACA,GAAGA,EAAEA,CAACA;IACfA,CAACA;IACDA,IAAAA,CAACA;QACGA,GAAGA,CAACA,CAACA,GAAGA,MAAMA,CAACA;IACnBA,CAAEA;IAAAA,KAAKA,CAACA,CAACA,CAACA,CAACA,CAACA,CAACA;QACTA,EAAEA,CAACA,CAACA,GAAGA,CAACA,CAACA,GAAGA,EAAEA,CAACA,CAACA,CAACA;YACbA,GAAGA,CAACA,CAACA,GAAGA,EAAEA,CAACA;QACfA,CAACA;QAACA,IAAIA,CAACA,CAACA;YACJA,GAAGA,CAACA,CAACA,GAAGA,KAAKA,CAACA;QAClBA,CAACA;IACLA,CAACA;IACDA,IAAAA,CAACA;QACGA,MAAMA,IAAIA,KAAKA,EAAEA,CAACA;IACtBA,CAAEA;IAAAA,KAAKA,CAACA,CAACA,EAAEA,CAACA,CAACA,CAACA;QACVA,IAAIA,CAACA,GAAGA,EAAEA,CAACA;IACfA,CAACA;YAACA,CAACA;QACCA,CAACA,GAAGA,EAAEA,CAACA;IACXA,CAACA;IACDA,MAAMA,GAAGA,EAAEA,CAACA;QACRA,CAACA,GAAGA,CAACA,CAACA;QACNA,CAACA,GAAGA,EAAEA,CAACA;IACXA,CAACA;IACDA,MAAMA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA,CAACA,CAACA;QACZA,KAAKA,CAACA,EAAEA,CAACA;YACLA,CAACA,EAAEA,CAACA;YACJA,KAAKA,CAACA;QAEVA,CAACA;QACDA,KAAKA,CAACA,EAAEA,CAACA;YACLA,CAACA,EAAEA,CAACA;YACJA,KAAKA,CAACA;QAEVA,CAACA;QACDA,SAASA,CAACA;YACNA,CAACA,IAAIA,CAACA,CAACA;YACPA,CAACA,GAAGA,EAAEA,CAACA;YACPA,KAAKA,CAACA;QAEVA,CAACA;IACLA,CAACA;IACDA,OAAOA,CAACA,GAAGA,EAAEA,EAAEA,CAACA;QACZA,CAACA,EAAEA,CAACA;IACRA,CAACA;IACDA,GAAGA,CAACA;QACAA,CAACA,EAAEA,CAACA;IACRA,CAACA,QAAQA,CAACA,GAAGA,CAACA,EAACA;IACfA,CAACA,GAAGA,CAACA,CAACA;IACNA,IAAIA,CAACA,GAAGA,CAACA,CAACA,IAAIA,CAACA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,CAACA;IACjCA,CAACA,CAACA,IAAIA,CAACA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,CAACA;IACzBA,CAACA,KAAKA,CAACA,CAACA;IACRA,CAACA,GAAGA,CAACA,GAAGA,EAAEA,CAACA;IACXA,IAAIA,CAACA,GAAGA,CAACA,CAACA;IACVA,MAAMA,CAACA;AACXA,CAACA;AACD,IAAI,CAAC,GAAG;IACJ,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC,CAAC;AACF,CAAC,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationStatements.js","sourceRoot":"","sources":["sourceMapValidationStatements.ts"],"names":["f"],"mappings":"AAAA,SAAS,CAAC;IACNA,IAAIA,CAACA,CAACA;IACNA,IAAIA,CAACA,GAAGA,CAACA,CAACA;IACVA,GAAGA,CAACA,CAACA,GAAGA,CAACA,CAACA,GAAGA,CAACA,EAAEA,CAACA,GAAGA,EAAEA,EAAEA,CAACA,EAAEA,EAAEA,CAACA;QAC1BA,CAACA,IAAIA,CAACA,CAACA;QACPA,CAACA,IAAIA,CAACA,CAACA;IACXA,CAACA;IACDA,EAAEA,CAACA,CAACA,CAACA,GAAGA,EAAEA,CAACA,CAACA,CAACA;QACTA,CAACA,IAAIA,CAACA,CAACA;IACXA,CAACA;IAACA,IAAIA,CAACA,CAACA;QACJA,CAACA,IAAIA,EAAEA,CAACA;QACRA,CAACA,EAAEA,CAACA;IACRA,CAACA;IACDA,IAAIA,CAACA,GAAGA;QACJA,CAACA;QACDA,CAACA;QACDA,CAACA;KACJA,CAACA;IACFA,IAAIA,GAAGA,GAAGA;QACNA,CAACA,EAAEA,CAACA;QACJA,CAACA,EAAEA,OAAOA;KACbA,CAACA;IACFA,GAAGA,CAACA,CAACA,GAAGA,CAACA,CAACA,IAAIA,CAACA,CAACA,CAACA,CAACA;QACdA,GAAGA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA,CAACA,CAACA;QACbA,IAAIA,CAACA,GAAGA,EAAEA,CAACA;IACfA,CAACA;IACDA,IAAIA,CAACA;QACDA,GAAGA,CAACA,CAACA,GAAGA,MAAMA,CAACA;IACnBA,CAAEA;IAAAA,KAAKA,CAACA,CAACA,CAACA,CAACA,CAACA,CAACA;QACTA,EAAEA,CAACA,CAACA,GAAGA,CAACA,CAACA,GAAGA,EAAEA,CAACA,CAACA,CAACA;YACbA,GAAGA,CAACA,CAACA,GAAGA,EAAEA,CAACA;QACfA,CAACA;QAACA,IAAIA,CAACA,CAACA;YACJA,GAAGA,CAACA,CAACA,GAAGA,KAAKA,CAACA;QAClBA,CAACA;IACLA,CAACA;IACDA,IAAIA,CAACA;QACDA,MAAMA,IAAIA,KAAKA,EAAEA,CAACA;IACtBA,CAAEA;IAAAA,KAAKA,CAACA,CAACA,EAAEA,CAACA,CAACA,CAACA;QACVA,IAAIA,CAACA,GAAGA,EAAEA,CAACA;IACfA,CAACA;YAASA,CAACA;QACPA,CAACA,GAAGA,EAAEA,CAACA;IACXA,CAACA;IACDA,MAAMA,GAAGA,EAAEA,CAACA;QACRA,CAACA,GAAGA,CAACA,CAACA;QACNA,CAACA,GAAGA,EAAEA,CAACA;IACXA,CAACA;IACDA,MAAMA,CAACA,CAACA,GAAGA,CAACA,CAACA,CAACA,CAACA,CAACA;QACZA,KAAKA,CAACA,EAAEA,CAACA;YACLA,CAACA,EAAEA,CAACA;YACJA,KAAKA,CAACA;QAEVA,CAACA;QACDA,KAAKA,CAACA,EAAEA,CAACA;YACLA,CAACA,EAAEA,CAACA;YACJA,KAAKA,CAACA;QAEVA,CAACA;QACDA,SAASA,CAACA;YACNA,CAACA,IAAIA,CAACA,CAACA;YACPA,CAACA,GAAGA,EAAEA,CAACA;YACPA,KAAKA,CAACA;QAEVA,CAACA;IACLA,CAACA;IACDA,OAAOA,CAACA,GAAGA,EAAEA,EAAEA,CAACA;QACZA,CAACA,EAAEA,CAACA;IACRA,CAACA;IACDA,GAAGA,CAACA;QACAA,CAACA,EAAEA,CAACA;IACRA,CAACA,QAAQA,CAACA,GAAGA,CAACA,EAACA;IACfA,CAACA,GAAGA,CAACA,CAACA;IACNA,IAAIA,CAACA,GAAGA,CAACA,CAACA,IAAIA,CAACA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,CAACA;IACjCA,CAACA,CAACA,IAAIA,CAACA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,GAAGA,CAACA,CAACA;IACzBA,CAACA,KAAKA,CAACA,CAACA;IACRA,CAACA,GAAGA,CAACA,GAAGA,EAAEA,CAACA;IACXA,IAAIA,CAACA,GAAGA,CAACA,CAACA;IACVA,MAAMA,CAACA;AACXA,CAACA;AACD,IAAI,CAAC,GAAG;IACJ,IAAI,CAAC,GAAG,EAAE,CAAC;IACX,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC,CAAC;AACF,CAAC,EAAE,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt b/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt index ef7aef275c0..586063c7c12 100644 --- a/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationStatements.sourcemap.txt @@ -501,11 +501,11 @@ sourceFile:sourceMapValidationStatements.ts 4 > ^^^^^^^^^^^^^^^-> 1-> > -2 > -3 > t +2 > try +3 > { 1->Emitted(28, 5) Source(27, 5) + SourceIndex(0) name (f) -2 >Emitted(28, 9) Source(27, 5) + SourceIndex(0) name (f) -3 >Emitted(28, 10) Source(27, 6) + SourceIndex(0) name (f) +2 >Emitted(28, 9) Source(27, 9) + SourceIndex(0) name (f) +3 >Emitted(28, 10) Source(27, 10) + SourceIndex(0) name (f) --- >>> obj.q = "ohhh"; 1->^^^^^^^^ @@ -515,7 +515,7 @@ sourceFile:sourceMapValidationStatements.ts 5 > ^^^ 6 > ^^^^^^ 7 > ^ -1->ry { +1-> > 2 > obj 3 > . @@ -706,11 +706,11 @@ sourceFile:sourceMapValidationStatements.ts 4 > ^^^^^^^^^^^^^^^^^^-> 1-> > -2 > -3 > t +2 > try +3 > { 1->Emitted(39, 5) Source(36, 5) + SourceIndex(0) name (f) -2 >Emitted(39, 9) Source(36, 5) + SourceIndex(0) name (f) -3 >Emitted(39, 10) Source(36, 6) + SourceIndex(0) name (f) +2 >Emitted(39, 9) Source(36, 9) + SourceIndex(0) name (f) +3 >Emitted(39, 10) Source(36, 10) + SourceIndex(0) name (f) --- >>> throw new Error(); 1->^^^^^^^^ @@ -719,7 +719,7 @@ sourceFile:sourceMapValidationStatements.ts 4 > ^^^^^ 5 > ^^ 6 > ^ -1->ry { +1-> > 2 > throw 3 > new @@ -805,10 +805,10 @@ sourceFile:sourceMapValidationStatements.ts 1->^^^^^^^^^^^^ 2 > ^ 3 > ^^^-> -1-> -2 > f -1->Emitted(45, 13) Source(40, 7) + SourceIndex(0) name (f) -2 >Emitted(45, 14) Source(40, 8) + SourceIndex(0) name (f) +1-> finally +2 > { +1->Emitted(45, 13) Source(40, 15) + SourceIndex(0) name (f) +2 >Emitted(45, 14) Source(40, 16) + SourceIndex(0) name (f) --- >>> y = 70; 1->^^^^^^^^ @@ -816,7 +816,7 @@ sourceFile:sourceMapValidationStatements.ts 3 > ^^^ 4 > ^^ 5 > ^ -1->inally { +1-> > 2 > y 3 > = diff --git a/tests/baselines/reference/sourceMapValidationTryCatchFinally.js.map b/tests/baselines/reference/sourceMapValidationTryCatchFinally.js.map index 89716807538..46506410856 100644 --- a/tests/baselines/reference/sourceMapValidationTryCatchFinally.js.map +++ b/tests/baselines/reference/sourceMapValidationTryCatchFinally.js.map @@ -1,2 +1,2 @@ //// [sourceMapValidationTryCatchFinally.js.map] -{"version":3,"file":"sourceMapValidationTryCatchFinally.js","sourceRoot":"","sources":["sourceMapValidationTryCatchFinally.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,EAAE,CAAC;AACX,IAAA,CAAC;IACG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAE;AAAA,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACT,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;QAAC,CAAC;IACC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AACf,CAAC;AACD,IAAA,CAAC;IAEG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,IAAI,KAAK,EAAE,CAAC;AACtB,CACA;AAAA,KAAK,CAAC,CAAC,CAAC,CAAC,CACT,CAAC;IACG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;QACD,CAAC;IAEG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AACf,CAAC"} \ No newline at end of file +{"version":3,"file":"sourceMapValidationTryCatchFinally.js","sourceRoot":"","sources":["sourceMapValidationTryCatchFinally.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,EAAE,CAAC;AACX,IAAI,CAAC;IACD,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAE;AAAA,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACT,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;QAAS,CAAC;IACP,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AACf,CAAC;AACD,IACA,CAAC;IACG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,IAAI,KAAK,EAAE,CAAC;AACtB,CACA;AAAA,KAAK,CAAC,CAAC,CAAC,CAAC,CACT,CAAC;IACG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;QAED,CAAC;IACG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AACf,CAAC"} \ No newline at end of file diff --git a/tests/baselines/reference/sourceMapValidationTryCatchFinally.sourcemap.txt b/tests/baselines/reference/sourceMapValidationTryCatchFinally.sourcemap.txt index 25dee4fbc45..d625e74c262 100644 --- a/tests/baselines/reference/sourceMapValidationTryCatchFinally.sourcemap.txt +++ b/tests/baselines/reference/sourceMapValidationTryCatchFinally.sourcemap.txt @@ -35,11 +35,11 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 4 > ^^^^^^^^^^-> 1 > > -2 > -3 > t +2 >try +3 > { 1 >Emitted(2, 1) Source(2, 1) + SourceIndex(0) -2 >Emitted(2, 5) Source(2, 1) + SourceIndex(0) -3 >Emitted(2, 6) Source(2, 2) + SourceIndex(0) +2 >Emitted(2, 5) Source(2, 5) + SourceIndex(0) +3 >Emitted(2, 6) Source(2, 6) + SourceIndex(0) --- >>> x = x + 1; 1->^^^^ @@ -49,7 +49,7 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 5 > ^^^ 6 > ^ 7 > ^ -1->ry { +1-> > 2 > x 3 > = @@ -140,10 +140,10 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 1->^^^^^^^^ 2 > ^ 3 > ^^^^^^^-> -1-> -2 > f -1->Emitted(8, 9) Source(6, 3) + SourceIndex(0) -2 >Emitted(8, 10) Source(6, 4) + SourceIndex(0) +1-> finally +2 > { +1->Emitted(8, 9) Source(6, 11) + SourceIndex(0) +2 >Emitted(8, 10) Source(6, 12) + SourceIndex(0) --- >>> x = x * 10; 1->^^^^ @@ -153,7 +153,7 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 5 > ^^^ 6 > ^^ 7 > ^ -1->inally { +1-> > 2 > x 3 > = @@ -186,11 +186,12 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 4 > ^^^^^^^^^^-> 1-> > -2 > -3 > t +2 >try + > +3 > { 1->Emitted(11, 1) Source(9, 1) + SourceIndex(0) -2 >Emitted(11, 5) Source(9, 1) + SourceIndex(0) -3 >Emitted(11, 6) Source(9, 2) + SourceIndex(0) +2 >Emitted(11, 5) Source(10, 1) + SourceIndex(0) +3 >Emitted(11, 6) Source(10, 2) + SourceIndex(0) --- >>> x = x + 1; 1->^^^^ @@ -201,8 +202,7 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 6 > ^ 7 > ^ 8 > ^^^^^^^^^-> -1->ry - >{ +1-> > 2 > x 3 > = @@ -317,10 +317,11 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 2 > ^ 3 > ^^^^^^^-> 1-> + >finally > -2 > f -1->Emitted(18, 9) Source(18, 1) + SourceIndex(0) -2 >Emitted(18, 10) Source(18, 2) + SourceIndex(0) +2 > { +1->Emitted(18, 9) Source(19, 1) + SourceIndex(0) +2 >Emitted(18, 10) Source(19, 2) + SourceIndex(0) --- >>> x = x * 10; 1->^^^^ @@ -330,8 +331,7 @@ sourceFile:sourceMapValidationTryCatchFinally.ts 5 > ^^^ 6 > ^^ 7 > ^ -1->inally - >{ +1-> > 2 > x 3 > = diff --git a/tests/cases/compiler/functionsWithModifiersInBlocks1.ts b/tests/cases/compiler/functionsWithModifiersInBlocks1.ts new file mode 100644 index 00000000000..2a03d962ffb --- /dev/null +++ b/tests/cases/compiler/functionsWithModifiersInBlocks1.ts @@ -0,0 +1,5 @@ +{ + declare function f() { } + export function f() { } + declare export function f() { } +} \ No newline at end of file diff --git a/tests/cases/compiler/modifiersOnInterfaceIndexSignature1.ts b/tests/cases/compiler/modifiersOnInterfaceIndexSignature1.ts new file mode 100644 index 00000000000..ba5eebbefc9 --- /dev/null +++ b/tests/cases/compiler/modifiersOnInterfaceIndexSignature1.ts @@ -0,0 +1,3 @@ +interface I { + public [a: string]: number; +} \ No newline at end of file diff --git a/tests/cases/compiler/objectLiteralMemberWithModifiers1.ts b/tests/cases/compiler/objectLiteralMemberWithModifiers1.ts new file mode 100644 index 00000000000..6bdc9476fb8 --- /dev/null +++ b/tests/cases/compiler/objectLiteralMemberWithModifiers1.ts @@ -0,0 +1 @@ +var v = { public foo() { } } \ No newline at end of file diff --git a/tests/cases/compiler/objectLiteralMemberWithModifiers2.ts b/tests/cases/compiler/objectLiteralMemberWithModifiers2.ts new file mode 100644 index 00000000000..0bfa0a20521 --- /dev/null +++ b/tests/cases/compiler/objectLiteralMemberWithModifiers2.ts @@ -0,0 +1 @@ +var v = { public get foo() { } } \ No newline at end of file diff --git a/tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts b/tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts new file mode 100644 index 00000000000..0529c717d16 --- /dev/null +++ b/tests/cases/compiler/objectLiteralMemberWithQuestionMark1.ts @@ -0,0 +1 @@ +var v = { foo?() { } } \ No newline at end of file diff --git a/tests/cases/compiler/objectLiteralMemberWithoutBlock1.ts b/tests/cases/compiler/objectLiteralMemberWithoutBlock1.ts new file mode 100644 index 00000000000..7f930a5dfde --- /dev/null +++ b/tests/cases/compiler/objectLiteralMemberWithoutBlock1.ts @@ -0,0 +1 @@ +var v = { foo(); } \ No newline at end of file diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts index 50a112f4625..346a102faa8 100644 --- a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts @@ -11,7 +11,7 @@ ////var a2, a/*varName4*/ - +debugger; test.markers().forEach((m) => { goTo.position(m.position, m.fileName); verify.completionListIsEmpty(); diff --git a/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts b/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts new file mode 100644 index 00000000000..803d6bf66ce --- /dev/null +++ b/tests/cases/fourslash/deleteModifierBeforeVarStatement1.ts @@ -0,0 +1,64 @@ +/// + +//// +//// +//// ///////////////////////////// +//// /// Windows Script Host APIS +//// ///////////////////////////// +//// +//// declare var ActiveXObject: { new (s: string): any; }; +//// +//// interface ITextWriter { +//// WriteLine(s): void; +//// } +//// +//// declare var WScript: { +//// Echo(s): void; +//// StdErr: ITextWriter; +//// Arguments: { length: number; Item(): string; }; +//// ScriptFullName: string; +//// Quit(): number; +//// } +//// + + +goTo.file(0); + +// : +// : |--- go here +// 1: +// 2: +goTo.position(0); + +// : +// : |--- delete "\n\n///..." +// 1: +// 2: +debugger; +edit.deleteAtCaret(100); + + +// 12: +// : |--- go here +// 13: declare var WScript: { +// 14: Echo(s): void; +goTo.position(198); + +// 12: +// : |--- delete "declare..." +// 13: declare var WScript: { +// 14: Echo(s): void; +edit.deleteAtCaret(16); + + +// 9: StdErr: ITextWriter; +// : |--- go here +// 10: Arguments: { length: number; Item(): string; }; +// 11: ScriptFullName: string; +goTo.position(198); + +// 9: StdErr: ITextWriter; +// : |--- insert "Item(): string; " +// 10: Arguments: { length: number; Item(): string; }; +// 11: ScriptFullName: string; +edit.insert("Item(): string; "); diff --git a/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts b/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts index 9037b6f8029..db0f792880e 100644 --- a/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts +++ b/tests/cases/fourslash/getOccurrencesTryCatchFinally.ts @@ -16,7 +16,7 @@ ////[|fina/*3*/lly|] { ////} - +debugger; for (var i = 1; i <= test.markers().length; i++) { goTo.marker("" + i); verify.occurrencesAtPositionCount(3); diff --git a/tests/cases/fourslash/incrementalParsingInsertIntoMethod1.ts b/tests/cases/fourslash/incrementalParsingInsertIntoMethod1.ts new file mode 100644 index 00000000000..930c0511ffb --- /dev/null +++ b/tests/cases/fourslash/incrementalParsingInsertIntoMethod1.ts @@ -0,0 +1,13 @@ +/// + +////class C { +//// public foo1() { } +//// public foo2() { +//// return 1/*1*/; +//// } +//// public foo3() { } +////} + +debugger; +goTo.marker("1"); +edit.insert(" + 1"); \ No newline at end of file diff --git a/tests/cases/fourslash/navigateItemsLet.ts b/tests/cases/fourslash/navigateItemsLet.ts index dc399522703..8a82d042738 100644 --- a/tests/cases/fourslash/navigateItemsLet.ts +++ b/tests/cases/fourslash/navigateItemsLet.ts @@ -1,10 +1,10 @@ /// -////{| "itemName": "c", "kind": "let", "parentName": "" |}let c = 10; -////function foo() { -//// {| "itemName": "d", "kind": "let", "parentName": "foo" |}let d = 10; -////} - +////{| "itemName": "c", "kind": "let", "parentName": "" |}let c = 10; +////function foo() { +//// {| "itemName": "d", "kind": "let", "parentName": "foo" |}let d = 10; +////} +debugger; test.markers().forEach(marker => { verify.navigationItemsListContains( marker.data.itemName, diff --git a/tests/cases/fourslash/navigationItemsExactMatch2.ts b/tests/cases/fourslash/navigationItemsExactMatch2.ts index 8f934dcc3c3..adf8e69761e 100644 --- a/tests/cases/fourslash/navigationItemsExactMatch2.ts +++ b/tests/cases/fourslash/navigationItemsExactMatch2.ts @@ -17,7 +17,7 @@ ////function distance2(distanceParam1): void { //// var distanceLocal1; ////} - +debugger; goTo.marker("file1"); verify.navigationItemsListCount(2, "point", "exact"); verify.navigationItemsListCount(5, "distance", "prefix"); diff --git a/tests/cases/fourslash/quickInfoDisplayPartsConst.ts b/tests/cases/fourslash/quickInfoDisplayPartsConst.ts index 62295017dfc..8871a6cc15e 100644 --- a/tests/cases/fourslash/quickInfoDisplayPartsConst.ts +++ b/tests/cases/fourslash/quickInfoDisplayPartsConst.ts @@ -22,6 +22,7 @@ /////*15*/h(10); /////*16*/h("hello"); +debugger; var marker = 0; function verifyConst(name: string, typeDisplay: ts.SymbolDisplayPart[], optionalNameDisplay?: ts.SymbolDisplayPart[], optionalKindModifiers?: string) { marker++; diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index e89f35aa93f..a3875cf8e8c 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -2,11 +2,13 @@ /// module ts { + ts.disableIncrementalParsing = false; + function withChange(text: IScriptSnapshot, start: number, length: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { var contents = text.getText(0, text.getLength()); var newContents = contents.substr(0, start) + newText + contents.substring(start + length); - return { text: ScriptSnapshot.fromString(newContents), textChangeRange: new TextChangeRange(new TextSpan(start, length), newText.length) } + return { text: ScriptSnapshot.fromString(newContents), textChangeRange: createTextChangeRange(createTextSpan(start, length), newText.length) } } function withInsert(text: IScriptSnapshot, start: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } { @@ -18,7 +20,27 @@ module ts { } function createTree(text: IScriptSnapshot, version: string) { - return createLanguageServiceSourceFile(/*fileName:*/ "", text, ScriptTarget.ES5, version, /*isOpen:*/ true, /*setNodeParents:*/ true) + return createLanguageServiceSourceFile(/*fileName:*/ "", text, ScriptTarget.Latest, version, /*isOpen:*/ true, /*setNodeParents:*/ true) + } + + function assertSameDiagnostics(file1: SourceFile, file2: SourceFile) { + var diagnostics1 = file1.getSyntacticDiagnostics(); + var diagnostics2 = file2.getSyntacticDiagnostics(); + + assert.equal(diagnostics1.length, diagnostics2.length, "diagnostics1.length !== diagnostics2.length"); + for (var i = 0, n = diagnostics1.length; i < n; i++) { + var d1 = diagnostics1[i]; + var d2 = diagnostics2[i]; + + assert.equal(d1.file, file1, "d1.file !== file1"); + assert.equal(d2.file, file2, "d2.file !== file2"); + assert.equal(d1.start, d2.start, "d1.start !== d2.start"); + assert.equal(d1.length, d2.length, "d1.length !== d2.length"); + assert.equal(d1.messageText, d2.messageText, "d1.messageText !== d2.messageText"); + assert.equal(d1.category, d2.category, "d1.category !== d2.category"); + assert.equal(d1.code, d2.code, "d1.code !== d2.code"); + assert.equal(d1.isEarly, d2.isEarly, "d1.isEarly !== d2.isEarly"); + } } // NOTE: 'reusedElements' is the expected count of elements reused from the old tree to the new @@ -35,15 +57,21 @@ module ts { Utils.assertInvariants(newTree, /*parent:*/ undefined); // Create a tree for the new text, in an incremental fashion. - var incrementalNewTree = oldTree.update(newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange); + var incrementalNewTree = updateLanguageServiceSourceFile(oldTree, newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange); Utils.assertInvariants(incrementalNewTree, /*parent:*/ undefined); // We should get the same tree when doign a full or incremental parse. Utils.assertStructuralEquals(newTree, incrementalNewTree); + // We should also get the exact same set of diagnostics. + assertSameDiagnostics(newTree, incrementalNewTree); + // There should be no reused nodes between two trees that are fully parsed. assert.isTrue(reusedElements(oldTree, newTree) === 0); + assert.equal(newTree.filename, incrementalNewTree.filename, "newTree.filename !== incrementalNewTree.filename"); + assert.equal(newTree.text, incrementalNewTree.text, "newTree.filename !== incrementalNewTree.filename"); + if (expectedReusedElements !== -1) { var actualReusedCount = reusedElements(oldTree, incrementalNewTree); assert.equal(actualReusedCount, expectedReusedElements, actualReusedCount + " !== " + expectedReusedElements); @@ -110,7 +138,7 @@ module ts { var semicolonIndex = source.indexOf(";"); var newTextAndChange = withInsert(oldText, semicolonIndex, " + 1"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 8); }); it('Deleting from method',() => { @@ -126,7 +154,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withDelete(oldText, index, "+ 1".length); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 8); }); it('Regular expression 1',() => { @@ -146,7 +174,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, semicolonIndex, "/"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it('Comment 1',() => { @@ -184,7 +212,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, index, "*"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it('Parameter 1',() => { @@ -199,7 +227,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, semicolonIndex, " + 1"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 8); }); it('Type member 1',() => { @@ -210,7 +238,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, index, "?"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 14); }); it('Enum element 1',() => { @@ -221,7 +249,7 @@ module ts { var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withChange(oldText, index, 2, "+"); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 21); }); it('Strict mode 1',() => { @@ -518,7 +546,7 @@ module ts { var index = source.lastIndexOf(";"); var newTextAndChange = withDelete(oldText, index, 1); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); }); it('Edit after empty type parameter list',() => { @@ -552,7 +580,7 @@ var o2 = { set Foo(val:number) { } };"; var index = source.indexOf("set"); var newTextAndChange = withInsert(oldText, index, "public "); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 6); }); it('Insert parameter ahead of parameter',() => { @@ -568,7 +596,7 @@ constructor(name) { }\ var index = source.indexOf("100"); var newTextAndChange = withInsert(oldText, index, "'1', "); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 5); }); it('Insert declare modifier before module',() => { @@ -581,7 +609,7 @@ module m3 { }\ var index = 0; var newTextAndChange = withInsert(oldText, index, "declare "); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 3); }); it('Insert function above arrow function with comment',() => { @@ -637,9 +665,100 @@ module m3 { }\ var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, 0, ""); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 7); + }); + + it('Class to interface',() => { + var source = "class A { public M1() { } public M2() { } public M3() { } p1 = 0; p2 = 0; p3 = 0 }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "class".length, "interface"); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); }); + it('Interface to class',() => { + var source = "interface A { M1?(); M2?(); M3?(); p1?; p2?; p3? }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "interface".length, "class"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Surrounding function declarations with block',() => { + debugger; + var source = "declare function F1() { } export function F2() { } declare export function F3() { }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withInsert(oldText, 0, "{"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 9); + }); + + it('Removing block around function declarations',() => { + var source = "{ declare function F1() { } export function F2() { } declare export function F3() { }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withDelete(oldText, 0, "{".length); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Moving methods from class to object literal',() => { + var source = "class C { public A() { } public B() { } public C() { } }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "class C".length, "var v ="); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Moving methods from object literal to class',() => { + var source = "var v = { public A() { } public B() { } public C() { } }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "var v =".length, "class C"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); + }); + + it('Moving index signatures from class to interface',() => { + var source = "class C { public [a: number]: string; public [a: number]: string; public [a: number]: string }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "class".length, "interface"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 18); + }); + + it('Moving index signatures from interface to class',() => { + var source = "interface C { public [a: number]: string; public [a: number]: string; public [a: number]: string }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "interface".length, "class"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 18); + }); + + it('Moving accessors from class to object literal',() => { + var source = "class C { public get A() { } public get B() { } public get C() { } }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "class C".length, "var v ="); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 0); + }); + + it('Moving accessors from object literal to class',() => { + var source = "var v = { public get A() { } public get B() { } public get C() { } }" + + var oldText = ScriptSnapshot.fromString(source); + var newTextAndChange = withChange(oldText, 0, "var v =".length, "class C"); + + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 4); + }); + // Simulated typing tests. it('Type extends clause 1',() => {