diff --git a/bin/tsc.js b/bin/tsc.js index 98e690a82e0..af5f939a80d 100644 --- a/bin/tsc.js +++ b/bin/tsc.js @@ -1532,6 +1532,7 @@ var ts; TypeFormatFlags[TypeFormatFlags["None"] = 0x00000000] = "None"; TypeFormatFlags[TypeFormatFlags["WriteArrayAsGenericType"] = 0x00000001] = "WriteArrayAsGenericType"; TypeFormatFlags[TypeFormatFlags["UseTypeOfFunction"] = 0x00000002] = "UseTypeOfFunction"; + TypeFormatFlags[TypeFormatFlags["NoTruncation"] = 0x00000004] = "NoTruncation"; })(ts.TypeFormatFlags || (ts.TypeFormatFlags = {})); var TypeFormatFlags = ts.TypeFormatFlags; (function (SymbolAccessibility) { @@ -1959,6 +1960,8 @@ var ts; } ts.getLocaleSpecificMessage = getLocaleSpecificMessage; function createFileDiagnostic(file, start, length, message) { + Debug.assert(start >= 0, "start must be non-negative, is " + start); + Debug.assert(length >= 0, "length must be non-negative, is " + length); var text = getLocaleSpecificMessage(message.key); if (arguments.length > 4) { text = formatStringFromArgs(text, arguments, 4); @@ -2002,6 +2005,8 @@ var ts; } ts.chainDiagnosticMessages = chainDiagnosticMessages; function flattenDiagnosticChain(file, start, length, diagnosticChain, newLine) { + Debug.assert(start >= 0, "start must be non-negative, is " + start); + Debug.assert(length >= 0, "length must be non-negative, is " + length); var code = diagnosticChain.code; var category = diagnosticChain.category; var messageText = ""; @@ -2257,6 +2262,7 @@ var ts; AssertionLevel[AssertionLevel["VeryAggressive"] = 3] = "VeryAggressive"; })(ts.AssertionLevel || (ts.AssertionLevel = {})); var AssertionLevel = ts.AssertionLevel; + var Debug; (function (Debug) { var currentAssertionLevel = 0 /* None */; function shouldAssert(level) { @@ -2277,8 +2283,7 @@ var ts; Debug.assert(false, message); } Debug.fail = fail; - })(ts.Debug || (ts.Debug = {})); - var Debug = ts.Debug; + })(Debug = ts.Debug || (ts.Debug = {})); })(ts || (ts = {})); var sys = (function () { function getWScriptSystem() { @@ -2544,7 +2549,7 @@ var ts; function createDiagnosticForNode(node, message, arg0, arg1, arg2) { node = getErrorSpanForNode(node); var file = getSourceFileOfNode(node); - var start = ts.skipTrivia(file.text, node.pos); + var start = node.kind === 111 /* Missing */ ? node.pos : ts.skipTrivia(file.text, node.pos); var length = node.end - start; return ts.createFileDiagnostic(file, start, length, message, arg0, arg1, arg2); } @@ -4735,10 +4740,11 @@ var ts; parseExpected(88 /* VarKeyword */); node.declarations = parseVariableDeclarationList(flags, false); parseSemicolon(); + finishNode(node); if (!node.declarations.length && file.syntacticErrors.length === errorCountBeforeVarStatement) { grammarErrorOnNode(node, ts.Diagnostics.Variable_declaration_list_cannot_be_empty); } - return finishNode(node); + return node; } function parseFunctionDeclaration(pos, flags) { var node = createNode(167 /* FunctionDeclaration */, pos); @@ -8476,6 +8482,7 @@ var ts; var typeCount = 0; var emptyArray = []; var emptySymbols = {}; + var compilerOptions = program.getCompilerOptions(); var checker = { getProgram: function () { return program; }, getDiagnostics: getDiagnostics, @@ -9186,7 +9193,7 @@ var ts; } return symbol.name; } - if (enclosingDeclaration && !(symbol.flags & (ts.SymbolFlags.PropertyOrAccessor | ts.SymbolFlags.Signature | 4096 /* Constructor */ | 2048 /* Method */ | 262144 /* TypeParameter */))) { + if (enclosingDeclaration && !(symbol.flags & 262144 /* TypeParameter */)) { var symbolName; while (symbol) { var isFirstName = !symbolName; @@ -9215,17 +9222,25 @@ var ts; function writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, writer) { writer.write(symbolToString(symbol, enclosingDeclaration, meaning)); } - function createSingleLineTextWriter() { + function createSingleLineTextWriter(maxLength) { var result = ""; - return { - write: function (s) { + var overflow = false; + function write(s) { + if (!overflow) { result += s; - }, + if (result.length > maxLength) { + result = result.substr(0, maxLength - 3) + "..."; + overflow = true; + } + } + } + return { + write: write, writeSymbol: function (symbol, enclosingDeclaration, meaning) { writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, this); }, writeLine: function () { - result += " "; + write(" "); }, increaseIndent: function () { }, @@ -9237,7 +9252,8 @@ var ts; }; } function typeToString(type, enclosingDeclaration, flags) { - var stringWriter = createSingleLineTextWriter(); + var maxLength = compilerOptions.noErrorTruncation || flags & 4 /* NoTruncation */ ? undefined : 100; + var stringWriter = createSingleLineTextWriter(maxLength); writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter); return stringWriter.getText(); } @@ -9567,7 +9583,7 @@ var ts; checkImplicitAny(type); return type; function checkImplicitAny(type) { - if (!fullTypeCheck || !program.getCompilerOptions().noImplicitAny) { + if (!fullTypeCheck || !compilerOptions.noImplicitAny) { return; } if (getInnermostTypeOfNestedArrayTypes(type) !== anyType) { @@ -9651,7 +9667,7 @@ var ts; type = getReturnTypeFromBody(getter); } else { - if (program.getCompilerOptions().noImplicitAny) { + if (compilerOptions.noImplicitAny) { error(setter, ts.Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbol.name); } type = anyType; @@ -11813,7 +11829,7 @@ var ts; if (stringIndexType) { return stringIndexType; } - if (program.getCompilerOptions().noImplicitAny && objectType !== anyType) { + if (compilerOptions.noImplicitAny && objectType !== anyType) { error(node, ts.Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); } return anyType; @@ -11884,17 +11900,6 @@ var ts; }); return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferentiallyTypeExpession(expr, contextualType, contextualMapper) { - var type = checkExpressionWithContextualType(expr, contextualType, contextualMapper); - var signature = getSingleCallSignature(type); - if (signature && signature.typeParameters) { - var contextualSignature = getSingleCallSignature(contextualType); - if (contextualSignature && !contextualSignature.typeParameters) { - type = getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper)); - } - } - return type; - } function inferTypeArguments(signature, args, excludeArgument) { var typeParameters = signature.typeParameters; var context = createInferenceContext(typeParameters); @@ -11902,14 +11907,14 @@ var ts; for (var i = 0; i < args.length; i++) { if (!excludeArgument || excludeArgument[i] === undefined) { var parameterType = getTypeAtPosition(signature, i); - inferTypes(context, inferentiallyTypeExpession(args[i], parameterType, mapper), parameterType); + inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType); } } if (excludeArgument) { for (var i = 0; i < args.length; i++) { if (excludeArgument[i] === false) { var parameterType = getTypeAtPosition(signature, i); - inferTypes(context, inferentiallyTypeExpession(args[i], parameterType, mapper), parameterType); + inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType); } } } @@ -12067,7 +12072,7 @@ var ts; if (node.kind === 133 /* NewExpression */) { var declaration = signature.declaration; if (declaration && (declaration.kind !== 117 /* Constructor */ && declaration.kind !== 121 /* ConstructSignature */)) { - if (program.getCompilerOptions().noImplicitAny) { + if (compilerOptions.noImplicitAny) { error(node, ts.Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); } return anyType; @@ -12106,7 +12111,7 @@ var ts; if (func.body.kind !== 168 /* FunctionBlock */) { var unwidenedType = checkAndMarkExpression(func.body, contextualMapper); var widenedType = getWidenedType(unwidenedType); - if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { + if (fullTypeCheck && compilerOptions.noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { error(func, ts.Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeToString(widenedType)); } return widenedType; @@ -12119,7 +12124,7 @@ var ts; return unknownType; } var widenedType = getWidenedType(commonType); - if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { + if (fullTypeCheck && compilerOptions.noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { var typeName = typeToString(widenedType); if (func.name) { error(func, ts.Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type, ts.identifierToString(func.name), typeName); @@ -12455,6 +12460,22 @@ var ts; return result; } function checkExpression(node, contextualMapper) { + var type = checkExpressionNode(node, contextualMapper); + if (contextualMapper && contextualMapper !== identityMapper) { + var signature = getSingleCallSignature(type); + if (signature && signature.typeParameters) { + var contextualType = getContextualType(node); + if (contextualType) { + var contextualSignature = getSingleCallSignature(contextualType); + if (contextualSignature && !contextualSignature.typeParameters) { + type = getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper)); + } + } + } + } + return type; + } + function checkExpressionNode(node, contextualMapper) { switch (node.kind) { case 55 /* Identifier */: return checkIdentifier(node); @@ -12565,7 +12586,7 @@ var ts; checkCollisionWithCapturedThisVariable(node, node.name); checkCollistionWithRequireExportsInGeneratedCode(node, node.name); checkCollisionWithArgumentsInGeneratedCode(node); - if (program.getCompilerOptions().noImplicitAny && !node.type) { + if (compilerOptions.noImplicitAny && !node.type) { switch (node.kind) { case 121 /* ConstructSignature */: error(node, ts.Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); @@ -12976,7 +12997,7 @@ var ts; if (node.type && !isAccessor(node.kind)) { checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } - if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && !node.body && !node.type) { + if (fullTypeCheck && compilerOptions.noImplicitAny && !node.body && !node.type) { if (!isPrivateWithinAmbient(node)) { var typeName = typeToString(anyType); if (node.name) { @@ -14273,7 +14294,7 @@ var ts; return target !== unknownSymbol && ((target.flags & ts.SymbolFlags.Value) !== 0); } function shouldEmitDeclarations() { - return program.getCompilerOptions().declaration && !program.getDiagnostics().length && !getDiagnostics().length; + return compilerOptions.declaration && !program.getDiagnostics().length && !getDiagnostics().length; } function isReferencedImportDeclaration(node) { var symbol = getSymbolOfNode(node); diff --git a/bin/typescriptServices.js b/bin/typescriptServices.js index 0e520a2b447..1efb6d232e3 100644 --- a/bin/typescriptServices.js +++ b/bin/typescriptServices.js @@ -1532,6 +1532,7 @@ var ts; TypeFormatFlags[TypeFormatFlags["None"] = 0x00000000] = "None"; TypeFormatFlags[TypeFormatFlags["WriteArrayAsGenericType"] = 0x00000001] = "WriteArrayAsGenericType"; TypeFormatFlags[TypeFormatFlags["UseTypeOfFunction"] = 0x00000002] = "UseTypeOfFunction"; + TypeFormatFlags[TypeFormatFlags["NoTruncation"] = 0x00000004] = "NoTruncation"; })(ts.TypeFormatFlags || (ts.TypeFormatFlags = {})); var TypeFormatFlags = ts.TypeFormatFlags; (function (SymbolAccessibility) { @@ -1959,6 +1960,8 @@ var ts; } ts.getLocaleSpecificMessage = getLocaleSpecificMessage; function createFileDiagnostic(file, start, length, message) { + Debug.assert(start >= 0, "start must be non-negative, is " + start); + Debug.assert(length >= 0, "length must be non-negative, is " + length); var text = getLocaleSpecificMessage(message.key); if (arguments.length > 4) { text = formatStringFromArgs(text, arguments, 4); @@ -2002,6 +2005,8 @@ var ts; } ts.chainDiagnosticMessages = chainDiagnosticMessages; function flattenDiagnosticChain(file, start, length, diagnosticChain, newLine) { + Debug.assert(start >= 0, "start must be non-negative, is " + start); + Debug.assert(length >= 0, "length must be non-negative, is " + length); var code = diagnosticChain.code; var category = diagnosticChain.category; var messageText = ""; @@ -2349,7 +2354,7 @@ var ts; function createDiagnosticForNode(node, message, arg0, arg1, arg2) { node = getErrorSpanForNode(node); var file = getSourceFileOfNode(node); - var start = ts.skipTrivia(file.text, node.pos); + var start = node.kind === 111 /* Missing */ ? node.pos : ts.skipTrivia(file.text, node.pos); var length = node.end - start; return ts.createFileDiagnostic(file, start, length, message, arg0, arg1, arg2); } @@ -4540,10 +4545,11 @@ var ts; parseExpected(88 /* VarKeyword */); node.declarations = parseVariableDeclarationList(flags, false); parseSemicolon(); + finishNode(node); if (!node.declarations.length && file.syntacticErrors.length === errorCountBeforeVarStatement) { grammarErrorOnNode(node, ts.Diagnostics.Variable_declaration_list_cannot_be_empty); } - return finishNode(node); + return node; } function parseFunctionDeclaration(pos, flags) { var node = createNode(167 /* FunctionDeclaration */, pos); @@ -8281,6 +8287,7 @@ var ts; var typeCount = 0; var emptyArray = []; var emptySymbols = {}; + var compilerOptions = program.getCompilerOptions(); var checker = { getProgram: function () { return program; }, getDiagnostics: getDiagnostics, @@ -8991,7 +8998,7 @@ var ts; } return symbol.name; } - if (enclosingDeclaration && !(symbol.flags & (ts.SymbolFlags.PropertyOrAccessor | ts.SymbolFlags.Signature | 4096 /* Constructor */ | 2048 /* Method */ | 262144 /* TypeParameter */))) { + if (enclosingDeclaration && !(symbol.flags & 262144 /* TypeParameter */)) { var symbolName; while (symbol) { var isFirstName = !symbolName; @@ -9020,17 +9027,25 @@ var ts; function writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, writer) { writer.write(symbolToString(symbol, enclosingDeclaration, meaning)); } - function createSingleLineTextWriter() { + function createSingleLineTextWriter(maxLength) { var result = ""; - return { - write: function (s) { + var overflow = false; + function write(s) { + if (!overflow) { result += s; - }, + if (result.length > maxLength) { + result = result.substr(0, maxLength - 3) + "..."; + overflow = true; + } + } + } + return { + write: write, writeSymbol: function (symbol, enclosingDeclaration, meaning) { writeSymbolToTextWriter(symbol, enclosingDeclaration, meaning, this); }, writeLine: function () { - result += " "; + write(" "); }, increaseIndent: function () { }, @@ -9042,7 +9057,8 @@ var ts; }; } function typeToString(type, enclosingDeclaration, flags) { - var stringWriter = createSingleLineTextWriter(); + var maxLength = compilerOptions.noErrorTruncation || flags & 4 /* NoTruncation */ ? undefined : 100; + var stringWriter = createSingleLineTextWriter(maxLength); writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter); return stringWriter.getText(); } @@ -9372,7 +9388,7 @@ var ts; checkImplicitAny(type); return type; function checkImplicitAny(type) { - if (!fullTypeCheck || !program.getCompilerOptions().noImplicitAny) { + if (!fullTypeCheck || !compilerOptions.noImplicitAny) { return; } if (getInnermostTypeOfNestedArrayTypes(type) !== anyType) { @@ -9456,7 +9472,7 @@ var ts; type = getReturnTypeFromBody(getter); } else { - if (program.getCompilerOptions().noImplicitAny) { + if (compilerOptions.noImplicitAny) { error(setter, ts.Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbol.name); } type = anyType; @@ -11618,7 +11634,7 @@ var ts; if (stringIndexType) { return stringIndexType; } - if (program.getCompilerOptions().noImplicitAny && objectType !== anyType) { + if (compilerOptions.noImplicitAny && objectType !== anyType) { error(node, ts.Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type); } return anyType; @@ -11689,17 +11705,6 @@ var ts; }); return getSignatureInstantiation(signature, getInferredTypes(context)); } - function inferentiallyTypeExpession(expr, contextualType, contextualMapper) { - var type = checkExpressionWithContextualType(expr, contextualType, contextualMapper); - var signature = getSingleCallSignature(type); - if (signature && signature.typeParameters) { - var contextualSignature = getSingleCallSignature(contextualType); - if (contextualSignature && !contextualSignature.typeParameters) { - type = getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper)); - } - } - return type; - } function inferTypeArguments(signature, args, excludeArgument) { var typeParameters = signature.typeParameters; var context = createInferenceContext(typeParameters); @@ -11707,14 +11712,14 @@ var ts; for (var i = 0; i < args.length; i++) { if (!excludeArgument || excludeArgument[i] === undefined) { var parameterType = getTypeAtPosition(signature, i); - inferTypes(context, inferentiallyTypeExpession(args[i], parameterType, mapper), parameterType); + inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType); } } if (excludeArgument) { for (var i = 0; i < args.length; i++) { if (excludeArgument[i] === false) { var parameterType = getTypeAtPosition(signature, i); - inferTypes(context, inferentiallyTypeExpession(args[i], parameterType, mapper), parameterType); + inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType); } } } @@ -11872,7 +11877,7 @@ var ts; if (node.kind === 133 /* NewExpression */) { var declaration = signature.declaration; if (declaration && (declaration.kind !== 117 /* Constructor */ && declaration.kind !== 121 /* ConstructSignature */)) { - if (program.getCompilerOptions().noImplicitAny) { + if (compilerOptions.noImplicitAny) { error(node, ts.Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type); } return anyType; @@ -11911,7 +11916,7 @@ var ts; if (func.body.kind !== 168 /* FunctionBlock */) { var unwidenedType = checkAndMarkExpression(func.body, contextualMapper); var widenedType = getWidenedType(unwidenedType); - if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { + if (fullTypeCheck && compilerOptions.noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { error(func, ts.Diagnostics.Function_expression_which_lacks_return_type_annotation_implicitly_has_an_0_return_type, typeToString(widenedType)); } return widenedType; @@ -11924,7 +11929,7 @@ var ts; return unknownType; } var widenedType = getWidenedType(commonType); - if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { + if (fullTypeCheck && compilerOptions.noImplicitAny && widenedType !== commonType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) { var typeName = typeToString(widenedType); if (func.name) { error(func, ts.Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type, ts.identifierToString(func.name), typeName); @@ -12260,6 +12265,22 @@ var ts; return result; } function checkExpression(node, contextualMapper) { + var type = checkExpressionNode(node, contextualMapper); + if (contextualMapper && contextualMapper !== identityMapper) { + var signature = getSingleCallSignature(type); + if (signature && signature.typeParameters) { + var contextualType = getContextualType(node); + if (contextualType) { + var contextualSignature = getSingleCallSignature(contextualType); + if (contextualSignature && !contextualSignature.typeParameters) { + type = getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper)); + } + } + } + } + return type; + } + function checkExpressionNode(node, contextualMapper) { switch (node.kind) { case 55 /* Identifier */: return checkIdentifier(node); @@ -12370,7 +12391,7 @@ var ts; checkCollisionWithCapturedThisVariable(node, node.name); checkCollistionWithRequireExportsInGeneratedCode(node, node.name); checkCollisionWithArgumentsInGeneratedCode(node); - if (program.getCompilerOptions().noImplicitAny && !node.type) { + if (compilerOptions.noImplicitAny && !node.type) { switch (node.kind) { case 121 /* ConstructSignature */: error(node, ts.Diagnostics.Construct_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type); @@ -12781,7 +12802,7 @@ var ts; if (node.type && !isAccessor(node.kind)) { checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type)); } - if (fullTypeCheck && program.getCompilerOptions().noImplicitAny && !node.body && !node.type) { + if (fullTypeCheck && compilerOptions.noImplicitAny && !node.body && !node.type) { if (!isPrivateWithinAmbient(node)) { var typeName = typeToString(anyType); if (node.name) { @@ -14078,7 +14099,7 @@ var ts; return target !== unknownSymbol && ((target.flags & ts.SymbolFlags.Value) !== 0); } function shouldEmitDeclarations() { - return program.getCompilerOptions().declaration && !program.getDiagnostics().length && !getDiagnostics().length; + return compilerOptions.declaration && !program.getDiagnostics().length && !getDiagnostics().length; } function isReferencedImportDeclaration(node) { var symbol = getSymbolOfNode(node); diff --git a/package.json b/package.json index dd1c6276a2b..6b1d991cca6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "typescript", "author": "Microsoft Corp.", "homepage": "http://typescriptlang.org/", - "version": "1.0.1", + "version": "1.1.0", "licenses": [ { "type": "Apache License 2.0", diff --git a/scripts/importDefinitelyTypedTests.ts b/scripts/importDefinitelyTypedTests.ts index caa6be0063a..f33ba1dd525 100644 --- a/scripts/importDefinitelyTypedTests.ts +++ b/scripts/importDefinitelyTypedTests.ts @@ -33,44 +33,44 @@ function importDefinitelyTypedTest(testCaseName: string, testFiles: string[], re fs.mkdirSync(testDirectoryPath); child_process.exec(cmd, { - maxBuffer: 1 * 1024 * 1024, - cwd: testDirectoryPath - }, (error, stdout, stderr) => { - //console.log("importing " + testCaseName + " ..."); - //console.log(cmd); - - if (error) { - console.log("importing " + testCaseName + " ..."); - console.log(cmd); - console.log("==> error " + JSON.stringify(error)); - console.log("==> stdout " + String(stdout)); - console.log("==> stderr " + String(stderr)); - console.log("\r\n"); - return; - } - - // copy generated file to output location - var outputFilePath = path.join(testDirectoryPath, "iocapture0.json"); - var testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json"); - copyFileSync(outputFilePath, testCasePath); - - //console.log("output generated at: " + outputFilePath); - - if (!fs.existsSync(testCasePath)) { - throw new Error("could not find test case at: " + testCasePath); - } - else { - fs.unlinkSync(outputFilePath); - fs.rmdirSync(testDirectoryPath); - //console.log("testcase generated at: " + testCasePath); - //console.log("Done."); - } - //console.log("\r\n"); - - }) - .on('error', function (error) { - console.log("==> error " + JSON.stringify(error)); - console.log("\r\n"); + maxBuffer: 1 * 1024 * 1024, + cwd: testDirectoryPath + }, (error, stdout, stderr) => { + console.log("importing " + testCaseName + " ..."); + console.log(cmd); + + if (error) { + console.log("importing " + testCaseName + " ..."); + console.log(cmd); + console.log("==> error " + JSON.stringify(error)); + console.log("==> stdout " + String(stdout)); + console.log("==> stderr " + String(stderr)); + console.log("\r\n"); + return; + } + + // copy generated file to output location + var outputFilePath = path.join(testDirectoryPath, "iocapture0.json"); + var testCasePath = path.join(rwcTestPath, "DefinitelyTyped_" + testCaseName + ".json"); + copyFileSync(outputFilePath, testCasePath); + + //console.log("output generated at: " + outputFilePath); + + if (!fs.existsSync(testCasePath)) { + throw new Error("could not find test case at: " + testCasePath); + } + else { + fs.unlinkSync(outputFilePath); + fs.rmdirSync(testDirectoryPath); + //console.log("testcase generated at: " + testCasePath); + //console.log("Done."); + } + //console.log("\r\n"); + + }) + .on('error', function (error) { + console.log("==> error " + JSON.stringify(error)); + console.log("\r\n"); }); } @@ -79,7 +79,8 @@ function importDefinitelyTypedTests(definitelyTypedRoot: string): void { if (err) throw err; subDirectorys - .filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) >= 0) + .filter(d => ["_infrastructure", "node_modules", ".git"].indexOf(d) < 0) + .filter(i => i.indexOf("sipml") >=0 ) .filter(i => fs.statSync(path.join(definitelyTypedRoot, i)).isDirectory()) .forEach(d => { var directoryPath = path.join(definitelyTypedRoot, d); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c96b2edc5b1..da03c9fb611 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -102,6 +102,7 @@ module ts { var globalBooleanType: ObjectType; var globalRegExpType: ObjectType; + var tupleTypes: Map = {}; var stringLiteralTypes: Map = {}; var emitExtends = false; @@ -413,7 +414,7 @@ module ts { } } - function getFullyQualifiedName(symbol: Symbol) { + function getFullyQualifiedName(symbol: Symbol): string { return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol); } @@ -649,15 +650,14 @@ module ts { } function isOptionalProperty(propertySymbol: Symbol): boolean { - if (propertySymbol.flags & SymbolFlags.Prototype) { - return false; - } // class C { // constructor(public x?) { } // } // // x is an optional parameter, but it is a required property. - return (propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark) && propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter; + return propertySymbol.valueDeclaration && + propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark && + propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter; } function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T { @@ -995,6 +995,9 @@ module ts { else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) { writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Type); } + else if (type.flags & TypeFlags.Tuple) { + writeTupleType(type); + } else if (type.flags & TypeFlags.Anonymous) { writeAnonymousType(type, allowFunctionOrConstructorTypeLiteral); } @@ -1007,6 +1010,15 @@ module ts { } } + function writeTypeList(types: Type[]) { + for (var i = 0; i < types.length; i++) { + if (i > 0) { + writer.write(", "); + } + writeType(types[i], /*allowFunctionOrConstructorTypeLiteral*/ true); + } + } + function writeTypeReference(type: TypeReference) { if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { // If we are writing array element type the arrow style signatures are not allowed as @@ -1017,16 +1029,17 @@ module ts { else { writer.writeSymbol(type.target.symbol, enclosingDeclaration, SymbolFlags.Type); writer.write("<"); - for (var i = 0; i < type.typeArguments.length; i++) { - if (i > 0) { - writer.write(", "); - } - writeType(type.typeArguments[i], /*allowFunctionOrConstructorTypeLiteral*/ true); - } + writeTypeList(type.typeArguments); writer.write(">"); } } + function writeTupleType(type: TupleType) { + writer.write("["); + writeTypeList(type.elementTypes); + writer.write("]"); + } + function writeAnonymousType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) { // Always use 'typeof T' for type of class, enum, and module objects if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { @@ -1354,10 +1367,14 @@ module ts { } // Use the type of the initializer expression if one is present if (declaration.initializer) { - var unwidenedType = checkAndMarkExpression(declaration.initializer); - var type = getWidenedType(unwidenedType); - if (type !== unwidenedType) { - checkImplicitAny(type); + var type = checkAndMarkExpression(declaration.initializer); + // Widening of property assignments is handled by checkObjectLiteral, exclude them here + if (declaration.kind !== SyntaxKind.PropertyAssignment) { + var unwidenedType = type; + type = getWidenedType(type); + if (type !== unwidenedType) { + checkImplicitAny(type); + } } return type; } @@ -1416,6 +1433,12 @@ module ts { } else if (links.type === resolvingType) { links.type = anyType; + if (compilerOptions.noImplicitAny) { + var diagnostic = (symbol.valueDeclaration).type ? + Diagnostics._0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation : + Diagnostics._0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer; + error(symbol.valueDeclaration, diagnostic, symbolToString(symbol)); + } } return links.type; } @@ -1471,7 +1494,7 @@ module ts { // Otherwise, fall back to 'any'. else { if (compilerOptions.noImplicitAny) { - error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbol.name); + error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol)); } type = anyType; @@ -1485,6 +1508,10 @@ module ts { } else if (links.type === resolvingType) { links.type = anyType; + if (compilerOptions.noImplicitAny) { + var getter = getDeclarationOfKind(symbol, SyntaxKind.GetAccessor); + error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol)); + } } } @@ -1548,7 +1575,7 @@ module ts { function hasBaseType(type: InterfaceType, checkBase: InterfaceType) { return check(type); - function check(type: InterfaceType) { + function check(type: InterfaceType): boolean { var target = getTargetType(type); return target === checkBase || forEach(target.baseTypes, check); } @@ -1818,6 +1845,23 @@ module ts { return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)]; } + function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable { + var members: SymbolTable = {}; + for (var i = 0; i < memberTypes.length; i++) { + var symbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i); + symbol.type = memberTypes[i]; + members[i] = symbol; + } + return members; + } + + function resolveTupleTypeMembers(type: TupleType) { + var arrayType = resolveObjectTypeMembers(createArrayType(getBestCommonType(type.elementTypes))); + var members = createTupleTypeMemberSymbols(type.elementTypes); + addInheritedMembers(members, arrayType.properties); + setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType); + } + function resolveAnonymousTypeMembers(type: ObjectType) { var symbol = type.symbol; if (symbol.flags & SymbolFlags.TypeLiteral) { @@ -1863,6 +1907,9 @@ module ts { else if (type.flags & TypeFlags.Anonymous) { resolveAnonymousTypeMembers(type); } + else if (type.flags & TypeFlags.Tuple) { + resolveTupleTypeMembers(type); + } else { resolveTypeReferenceMembers(type); } @@ -2032,6 +2079,15 @@ module ts { } else if (signature.resolvedReturnType === resolvingType) { signature.resolvedReturnType = anyType; + if (compilerOptions.noImplicitAny) { + var declaration = signature.declaration; + if (declaration.name) { + error(declaration.name, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, identifierToString(declaration.name)); + } + else { + error(declaration, Diagnostics.Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions); + } + } } return signature.resolvedReturnType; } @@ -2218,7 +2274,7 @@ module ts { if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) { var typeParameters = (type).typeParameters; if (node.typeArguments && node.typeArguments.length === typeParameters.length) { - type = createTypeReference(type, map(node.typeArguments, t => getTypeFromTypeNode(t))); + type = createTypeReference(type, map(node.typeArguments, getTypeFromTypeNode)); } else { error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length); @@ -2304,6 +2360,24 @@ module ts { return links.resolvedType; } + function createTupleType(elementTypes: Type[]) { + var id = getTypeListId(elementTypes); + var type = tupleTypes[id]; + if (!type) { + type = tupleTypes[id] = createObjectType(TypeFlags.Tuple); + type.elementTypes = elementTypes; + } + return type; + } + + function getTypeFromTupleTypeNode(node: TupleTypeNode): Type { + var links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode)); + } + return links.resolvedType; + } + function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type { var links = getNodeLinks(node); if (!links.resolvedType) { @@ -2348,6 +2422,8 @@ module ts { return getTypeFromTypeQueryNode(node); case SyntaxKind.ArrayType: return getTypeFromArrayTypeNode(node); + case SyntaxKind.TupleType: + return getTypeFromTupleTypeNode(node); case SyntaxKind.TypeLiteral: return getTypeFromTypeLiteralNode(node); // This function assumes that an identifier or qualified name is a type expression @@ -2509,6 +2585,9 @@ module ts { if (type.flags & TypeFlags.Reference) { return createTypeReference((type).target, instantiateList((type).typeArguments, mapper, instantiateType)); } + if (type.flags & TypeFlags.Tuple) { + return createTupleType(instantiateList((type).elementTypes, mapper, instantiateType)); + } } return type; } @@ -3159,7 +3238,6 @@ module ts { while (isArrayType(type)) { type = (type).typeArguments[0]; } - return type; } @@ -3308,9 +3386,9 @@ module ts { inferFromTypes(sourceTypes[i], targetTypes[i]); } } - else if (source.flags & TypeFlags.ObjectType && (target.flags & TypeFlags.Reference || (target.flags & TypeFlags.Anonymous) && - target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) { - // If source is an object type, and target is a type reference, the type of a method, or a type literal, infer from members + else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) || + (target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) { + // If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members if (!isInProcess(source, target) && isWithinDepthLimit(source, sourceStack) && isWithinDepthLimit(target, targetStack)) { if (depth === 0) { sourceStack = []; @@ -3468,29 +3546,6 @@ module ts { return getTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol)); } - function getThisContainer(node: Node): Node { - while (true) { - node = node.parent; - if (!node) { - return node; - } - switch (node.kind) { - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.Property: - case SyntaxKind.Method: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.SourceFile: - case SyntaxKind.ArrowFunction: - return node; - } - } - } - function captureLexicalThis(node: Node, container: Node): void { var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined; getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis; @@ -3503,11 +3558,14 @@ module ts { } function checkThisExpression(node: Node): Type { - var container = getThisContainer(node); + // Stop at the first arrow function so that we can + // tell whether 'this' needs to be captured. + var container = getThisContainer(node, /* includeArrowFunctions */ true); var needToCaptureLexicalThis = false; - // skip arrow functions - while (container.kind === SyntaxKind.ArrowFunction) { - container = getThisContainer(container); + + // Now skip arrow functions to get the "real" owner of 'this'. + if (container.kind === SyntaxKind.ArrowFunction) { + container = getThisContainer(container, /* includeArrowFunctions */ false); needToCaptureLexicalThis = true; } @@ -3681,6 +3739,10 @@ module ts { return undefined; } + // In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer + // expression is the type of the variable, parameter or property. In a parameter declaration of a contextually + // typed function expression, the contextual type of an initializer expression is the contextual type of the + // parameter. function getContextualTypeForInitializerExpression(node: Expression): Type { var declaration = node.parent; if (node === declaration.initializer) { @@ -3712,6 +3774,7 @@ module ts { return undefined; } + // In a typed function call, an argument expression is contextually typed by the type of the corresponding parameter. function getContextualTypeForArgument(node: Expression): Type { var callExpression = node.parent; var argIndex = indexOf(callExpression.arguments, node); @@ -3726,11 +3789,14 @@ module ts { var binaryExpression = node.parent; var operator = binaryExpression.operator; if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) { + // In an assignment expression, the right operand is contextually typed by the type of the left operand. if (node === binaryExpression.right) { return checkExpression(binaryExpression.left); } } else if (operator === SyntaxKind.BarBarToken) { + // When an || expression has a contextual type, the operands are contextually typed by that type. When an || + // expression has no contextual type, the right operand is contextually typed by the type of the left operand. var type = getContextualType(binaryExpression); if (!type && node === binaryExpression.right) { type = checkExpression(binaryExpression.left); @@ -3740,6 +3806,9 @@ module ts { return undefined; } + // In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of + // the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one + // exists. Otherwise, it is the type of the string index signature in T, if one exists. function getContextualTypeForPropertyExpression(node: Expression): Type { var declaration = node.parent; var objectLiteral = declaration.parent; @@ -3755,17 +3824,31 @@ module ts { return undefined; } + // In an array literal contextually typed by a type T, the contextual type of an element expression at index N is + // the type of the property with the numeric name N in T, if one exists. Otherwise, it is the type of the numeric + // index signature in T, if one exists. function getContextualTypeForElementExpression(node: Expression): Type { var arrayLiteral = node.parent; var type = getContextualType(arrayLiteral); - return type ? getIndexTypeOfType(type, IndexKind.Number) : undefined; + if (type) { + var index = indexOf(arrayLiteral.elements, node); + var prop = getPropertyOfType(type, "" + index); + if (prop) { + return getTypeOfSymbol(prop); + } + return getIndexTypeOfType(type, IndexKind.Number); + } + return undefined; } + // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. function getContextualTypeForConditionalOperand(node: Expression): Type { var conditional = node.parent; return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined; } + // Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily + // be "pushed" onto a node using the contextualType property. function getContextualType(node: Expression): Type { if (node.contextualType) { return node.contextualType; @@ -3817,17 +3900,26 @@ module ts { } function checkArrayLiteral(node: ArrayLiteral, contextualMapper?: TypeMapper): Type { + var contextualType = getContextualType(node); + var elements = node.elements; var elementTypes: Type[] = []; - forEach(node.elements, element => { - if (element.kind !== SyntaxKind.OmittedExpression) { - var type = checkExpression(element, contextualMapper); - if (!contains(elementTypes, type)) elementTypes.push(type); + var isTupleLiteral: boolean = false; + for (var i = 0; i < elements.length; i++) { + if (contextualType && getPropertyOfType(contextualType, "" + i)) { + isTupleLiteral = true; } - }); - var contextualType = isInferentialContext(contextualMapper) ? undefined : getContextualType(node); - var contextualElementType = contextualType && getIndexTypeOfType(contextualType, IndexKind.Number); - var elementType = getBestCommonType(elementTypes, contextualElementType, true); - if (!elementType) elementType = elementTypes.length ? emptyObjectType : undefinedType; + var element = elements[i]; + var type = element.kind !== SyntaxKind.OmittedExpression ? checkExpression(element, contextualMapper) : undefinedType; + elementTypes.push(type); + } + if (isTupleLiteral) { + return createTupleType(elementTypes); + } + var contextualElementType = contextualType && !isInferentialContext(contextualMapper) ? getIndexTypeOfType(contextualType, IndexKind.Number) : undefined; + var elementType = getBestCommonType(uniqueElements(elementTypes), contextualElementType, true); + if (!elementType) { + elementType = elements.length ? emptyObjectType : undefinedType; + } return createArrayType(elementType); } @@ -3895,12 +3987,14 @@ module ts { } } + // If a symbol is a synthesized symbol with no value declaration, we assume it is a property. Example of this are the synthesized + // '.prototype' property as well as synthesized tuple index properties. function getDeclarationKindFromSymbol(s: Symbol) { - return s.flags & SymbolFlags.Prototype ? SyntaxKind.Property : s.valueDeclaration.kind; + return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.Property; } function getDeclarationFlagsFromSymbol(s: Symbol) { - return s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : s.valueDeclaration.flags; + return s.valueDeclaration ? s.valueDeclaration.flags : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0; } function checkPropertyAccess(node: PropertyAccess) { @@ -4407,37 +4501,6 @@ module ts { return voidType; } - // WARNING: This has the same semantics as the forEach family of functions, - // in that traversal terminates in the event that 'visitor' supplies a truthy value. - function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T { - - return traverse(body); - - function traverse(node: Node): T { - switch (node.kind) { - case SyntaxKind.ReturnStatement: - return visitor(node); - case SyntaxKind.Block: - case SyntaxKind.FunctionBlock: - case SyntaxKind.IfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.WithStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - case SyntaxKind.LabelledStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.TryBlock: - case SyntaxKind.CatchBlock: - case SyntaxKind.FinallyBlock: - return forEachChild(node, traverse); - } - } - } - /// Returns a set of types relating to every return expression relating to a function block. function checkAndAggregateReturnExpressionTypes(body: Block, contextualMapper?: TypeMapper): Type[] { var aggregatedTypes: Type[] = []; @@ -5199,7 +5262,11 @@ module ts { } function checkArrayType(node: ArrayTypeNode) { - getTypeFromArrayTypeNode(node); + checkSourceElement(node.elementType); + } + + function checkTupleType(node: TupleTypeNode) { + forEach(node.elementTypes, checkSourceElement); } function isPrivateWithinAmbient(node: Node): boolean { @@ -5856,17 +5923,6 @@ module ts { // TODO: Check that target label is valid } - function getContainingFunction(node: Node): SignatureDeclaration { - while (true) { - node = node.parent; - if (!node || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.ArrowFunction || node.kind === SyntaxKind.Method || node.kind === SyntaxKind.Constructor || - node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) { - return node; - } - } - } - function checkReturnStatement(node: ReturnStatement) { if (node.expression && !(getNodeLinks(node.expression).flags & NodeCheckFlags.TypeChecked)) { var func = getContainingFunction(node); @@ -5921,7 +5977,7 @@ module ts { }); } - function checkLabelledStatement(node: LabelledStatement) { + function checkLabeledStatement(node: LabeledStatement) { checkSourceElement(node.statement); } @@ -6459,6 +6515,8 @@ module ts { return checkTypeLiteral(node); case SyntaxKind.ArrayType: return checkArrayType(node); + case SyntaxKind.TupleType: + return checkTupleType(node); case SyntaxKind.FunctionDeclaration: return checkFunctionDeclaration(node); case SyntaxKind.Block: @@ -6489,8 +6547,8 @@ module ts { return checkWithStatement(node); case SyntaxKind.SwitchStatement: return checkSwitchStatement(node); - case SyntaxKind.LabelledStatement: - return checkLabelledStatement(node); + case SyntaxKind.LabeledStatement: + return checkLabeledStatement(node); case SyntaxKind.ThrowStatement: return checkThrowStatement(node); case SyntaxKind.TryStatement: @@ -6569,7 +6627,7 @@ module ts { case SyntaxKind.SwitchStatement: case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: - case SyntaxKind.LabelledStatement: + case SyntaxKind.LabeledStatement: case SyntaxKind.ThrowStatement: case SyntaxKind.TryStatement: case SyntaxKind.TryBlock: @@ -6645,7 +6703,7 @@ module ts { // Language service support function getNodeAtPosition(sourceFile: SourceFile, position: number): Node { - function findChildAtPosition(parent: Node) { + function findChildAtPosition(parent: Node): Node { var child = forEachChild(parent, node => { if (position >= node.pos && position <= node.end && position >= getTokenPosOfNode(node)) { return findChildAtPosition(node); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index c549231eacc..28a0a7bb6a3 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -19,8 +19,7 @@ module ts { export function contains(array: T[], value: T): boolean { if (array) { - var len = array.length; - for (var i = 0; i < len; i++) { + for (var i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return true; } @@ -31,8 +30,7 @@ module ts { export function indexOf(array: T[], value: T): number { if (array) { - var len = array.length; - for (var i = 0; i < len; i++) { + for (var i = 0, len = array.length; i < len; i++) { if (array[i] === value) { return i; } @@ -42,9 +40,8 @@ module ts { } export function filter(array: T[], f: (x: T) => boolean): T[] { - var result: T[]; if (array) { - result = []; + var result: T[] = []; for (var i = 0, len = array.length; i < len; i++) { var item = array[i]; if (f(item)) { @@ -56,11 +53,9 @@ module ts { } export function map(array: T[], f: (x: T) => U): U[] { - var result: U[]; if (array) { - result = []; - var len = array.length; - for (var i = 0; i < len; i++) { + var result: U[] = []; + for (var i = 0, len = array.length; i < len; i++) { result.push(f(array[i])); } } @@ -73,6 +68,17 @@ module ts { return array1.concat(array2); } + export function uniqueElements(array: T[]): T[] { + if (array) { + var result: T[] = []; + for (var i = 0, len = array.length; i < len; i++) { + var item = array[i]; + if (!contains(result, item)) result.push(item); + } + } + return result; + } + export function sum(array: any[], prop: string): number { var result = 0; for (var i = 0; i < array.length; i++) { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index aa1b793f6ac..04dbafc254e 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -84,6 +84,7 @@ module ts { An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." }, An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." }, Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." }, + A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." }, Variable_declaration_list_cannot_be_empty: { code: 1123, category: DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." }, Digit_expected: { code: 1124, category: DiagnosticCategory.Error, key: "Digit expected." }, Hexadecimal_digit_expected: { code: 1125, category: DiagnosticCategory.Error, key: "Hexadecimal digit expected." }, @@ -390,6 +391,10 @@ module ts { Object_literal_s_property_0_implicitly_has_an_1_type: { code: 7018, category: DiagnosticCategory.Error, key: "Object literal's property '{0}' implicitly has an '{1}' type." }, Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." }, Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7020, category: DiagnosticCategory.Error, key: "Call signature, which lacks return-type annotation, implicitly has an 'any' return type." }, + _0_implicitly_has_type_any_because_it_is_referenced_directly_or_indirectly_in_its_own_type_annotation: { code: 7021, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation." }, + _0_implicitly_has_type_any_because_it_is_does_not_have_a_type_annotation_and_is_referenced_directly_or_indirectly_in_its_own_initializer: { code: 7022, category: DiagnosticCategory.Error, key: "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer." }, + _0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7023, category: DiagnosticCategory.Error, key: "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, + Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." }, You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." }, }; } \ No newline at end of file diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index eef8da8c857..6c78ec6bd5d 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -327,6 +327,10 @@ "category": "Error", "code": 1121 }, + "A tuple type element list cannot be empty.": { + "category": "Error", + "code": 1122 + }, "Variable declaration list cannot be empty.": { "category": "Error", "code": 1123 @@ -1557,6 +1561,22 @@ "category": "Error", "code": 7020 }, + "'{0}' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation.": { + "category": "Error", + "code": 7021 + }, + "'{0}' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer.": { + "category": "Error", + "code": 7022 + }, + "'{0}' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": { + "category": "Error", + "code": 7023 + }, + "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.": { + "category": "Error", + "code": 7024 + }, "You cannot rename this element.": { "category": "Error", "code": 8000 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6b18ad4c133..1b1f184c5ee 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -781,8 +781,8 @@ module ts { case SyntaxKind.ContinueStatement: case SyntaxKind.ExportAssignment: return false; - case SyntaxKind.LabelledStatement: - return (node.parent).label === node; + case SyntaxKind.LabeledStatement: + return (node.parent).label === node; case SyntaxKind.CatchBlock: return (node.parent).variable === node; } @@ -1200,7 +1200,7 @@ module ts { write(";"); } - function emitLabelledStatement(node: LabelledStatement) { + function emitLabelledStatement(node: LabeledStatement) { emit(node.label); write(": "); emit(node.statement); @@ -1973,7 +1973,7 @@ module ts { } } - function emitNode(node: Node) { + function emitNode(node: Node): void { if (!node) { return; } @@ -2071,8 +2071,8 @@ module ts { case SyntaxKind.CaseClause: case SyntaxKind.DefaultClause: return emitCaseOrDefaultClause(node); - case SyntaxKind.LabelledStatement: - return emitLabelledStatement(node); + case SyntaxKind.LabeledStatement: + return emitLabelledStatement(node); case SyntaxKind.ThrowStatement: return emitThrowStatement(node); case SyntaxKind.TryStatement: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a79b90f5bbe..5aa333f4c84 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -228,6 +228,8 @@ module ts { return children((node).members); case SyntaxKind.ArrayType: return child((node).elementType); + case SyntaxKind.TupleType: + return children((node).elementTypes); case SyntaxKind.ArrayLiteral: return children((node).elements); case SyntaxKind.ObjectLiteral: @@ -305,9 +307,9 @@ module ts { case SyntaxKind.DefaultClause: return child((node).expression) || children((node).statements); - case SyntaxKind.LabelledStatement: - return child((node).label) || - child((node).statement); + case SyntaxKind.LabeledStatement: + return child((node).label) || + child((node).statement); case SyntaxKind.ThrowStatement: return child((node).expression); case SyntaxKind.TryStatement: @@ -350,6 +352,107 @@ module ts { } } + // Warning: This has the same semantics as the forEach family of functions, + // in that traversal terminates in the event that 'visitor' supplies a truthy value. + export function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T { + + return traverse(body); + + function traverse(node: Node): T { + switch (node.kind) { + case SyntaxKind.ReturnStatement: + return visitor(node); + case SyntaxKind.Block: + case SyntaxKind.FunctionBlock: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + case SyntaxKind.LabeledStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.TryBlock: + case SyntaxKind.CatchBlock: + case SyntaxKind.FinallyBlock: + return forEachChild(node, traverse); + } + } + } + + export function isAnyFunction(node: Node): boolean { + if (node) { + switch (node.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.Method: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + return true; + } + } + + return false; + } + + export function getContainingFunction(node: Node): SignatureDeclaration { + while (true) { + node = node.parent; + if (!node || isAnyFunction(node)) { + return node; + } + } + } + + export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case SyntaxKind.ArrowFunction: + if (!includeArrowFunctions) { + continue; + } + // Fall through + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.SourceFile: + return node; + } + } + } + + export function getSuperContainer(node: Node): Node { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return node; + } + } + } + export function hasRestParameters(s: SignatureDeclaration): boolean { return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0; } @@ -445,6 +548,7 @@ module ts { Parameters, // Parameters in parameter list TypeParameters, // Type parameters in type parameter list TypeArguments, // Type arguments in type argument list + TupleElementTypes, // Element types in tuple element type list Count // Number of parsing contexts } @@ -472,6 +576,7 @@ module ts { case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected; case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected; case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected; + case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected; } }; @@ -940,6 +1045,7 @@ module ts { case ParsingContext.Parameters: return isParameter(); case ParsingContext.TypeArguments: + case ParsingContext.TupleElementTypes: return isType(); } @@ -975,6 +1081,7 @@ module ts { // Tokens other than ')' are here for better error recovery return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken; case ParsingContext.ArrayLiteralMembers: + case ParsingContext.TupleElementTypes: return token === SyntaxKind.CloseBracketToken; case ParsingContext.Parameters: // Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery @@ -1495,6 +1602,17 @@ module ts { return finishNode(node); } + function parseTupleType(): TupleTypeNode { + var node = createNode(SyntaxKind.TupleType); + var startTokenPos = scanner.getTokenPos(); + var startErrorCount = file.syntacticErrors.length; + node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + if (!node.elementTypes.length && file.syntacticErrors.length === startErrorCount) { + grammarErrorAtPos(startTokenPos, scanner.getStartPos() - startTokenPos, Diagnostics.A_tuple_type_element_list_cannot_be_empty); + } + return finishNode(node); + } + function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode { var node = createNode(SyntaxKind.TypeLiteral); var member = createNode(signatureKind); @@ -1525,6 +1643,8 @@ module ts { return parseTypeQuery(); case SyntaxKind.OpenBraceToken: return parseTypeLiteral(); + case SyntaxKind.OpenBracketToken: + return parseTupleType(); case SyntaxKind.OpenParenToken: case SyntaxKind.LessThanToken: return parseFunctionType(SyntaxKind.CallSignature); @@ -1548,6 +1668,7 @@ module ts { case SyntaxKind.VoidKeyword: case SyntaxKind.TypeOfKeyword: case SyntaxKind.OpenBraceToken: + case SyntaxKind.OpenBracketToken: case SyntaxKind.LessThanToken: case SyntaxKind.NewKeyword: return true; @@ -2724,8 +2845,8 @@ module ts { return isIdentifier() && lookAhead(() => nextToken() === SyntaxKind.ColonToken); } - function parseLabelledStatement(): LabelledStatement { - var node = createNode(SyntaxKind.LabelledStatement); + function parseLabelledStatement(): LabeledStatement { + var node = createNode(SyntaxKind.LabeledStatement); node.label = parseIdentifier(); parseExpected(SyntaxKind.ColonToken); @@ -3458,7 +3579,7 @@ module ts { return finishNode(node); } - function isDeclaration() { + function isDeclaration(): boolean { switch (token) { case SyntaxKind.VarKeyword: case SyntaxKind.FunctionKeyword: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b460b1eb0ce..69556897979 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -149,6 +149,7 @@ module ts { TypeQuery, TypeLiteral, ArrayType, + TupleType, // Expression ArrayLiteral, ObjectLiteral, @@ -183,7 +184,7 @@ module ts { SwitchStatement, CaseClause, DefaultClause, - LabelledStatement, + LabeledStatement, ThrowStatement, TryStatement, TryBlock, @@ -219,8 +220,8 @@ module ts { FirstFutureReservedWord = ImplementsKeyword, LastFutureReservedWord = YieldKeyword, FirstTypeNode = TypeReference, - LastTypeNode = ArrayType, - FirstPunctuation= OpenBraceToken, + LastTypeNode = TupleType, + FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken, FirstToken = EndOfFileToken, LastToken = StringKeyword @@ -322,6 +323,10 @@ module ts { elementType: TypeNode; } + export interface TupleTypeNode extends TypeNode { + elementTypes: NodeArray; + } + export interface StringLiteralTypeNode extends TypeNode { text: string; } @@ -461,7 +466,7 @@ module ts { statements: NodeArray; } - export interface LabelledStatement extends Statement { + export interface LabeledStatement extends Statement { label: Identifier; statement: Statement; } @@ -805,13 +810,14 @@ module ts { Class = 0x00000400, // Class Interface = 0x00000800, // Interface Reference = 0x00001000, // Generic type reference - Anonymous = 0x00002000, // Anonymous - FromSignature = 0x00004000, // Created for signature assignment check + Tuple = 0x00002000, // Tuple + Anonymous = 0x00004000, // Anonymous + FromSignature = 0x00008000, // Created for signature assignment check Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null, StringLike = String | StringLiteral, NumberLike = Number | Enum, - ObjectType = Class | Interface | Reference | Anonymous + ObjectType = Class | Interface | Reference | Tuple | Anonymous } // Properties common to all types @@ -864,6 +870,11 @@ module ts { openReferenceChecks: Map; // Open type reference check cache } + export interface TupleType extends ObjectType { + elementTypes: Type[]; // Element types + baseArrayType: TypeReference; // Array where T is best common type of element types + } + // Resolved object type export interface ResolvedObjectType extends ObjectType { members: SymbolTable; // Properties by name diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index c571a7d9f94..0bcea9367e4 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1428,6 +1428,46 @@ module FourSlash { Harness.IO.log(this.getNameOrDottedNameSpan(pos)); } + private verifyClassifications(expected: { classificationType: string; text: string }[], actual: ts.ClassifiedSpan[]) { + if (actual.length !== expected.length) { + throw new Error('verifySyntacticClassification failed - expected total classifications to be ' + expected.length + ', but was ' + actual.length); + } + + for (var i = 0; i < expected.length; i++) { + var expectedClassification = expected[i]; + var actualClassification = actual[i]; + + var expectedType: string = (ts.ClassificationTypeNames)[expectedClassification.classificationType]; + if (expectedType !== actualClassification.classificationType) { + throw new Error('verifySyntacticClassification failed - expected classifications type to be ' + + expectedType + ', but was ' + + actualClassification.classificationType); + } + + var actualSpan = actualClassification.textSpan; + var actualText = this.activeFile.content.substr(actualSpan.start(), actualSpan.length()); + if (expectedClassification.text !== actualText) { + throw new Error('verifySyntacticClassification failed - expected classificatied text to be ' + + expectedClassification.text + ', but was ' + + actualText); + } + } + } + + public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) { + var actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, + new TypeScript.TextSpan(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 TypeScript.TextSpan(0, this.activeFile.content.length)); + + this.verifyClassifications(expected, actual); + } + public verifyOutliningSpans(spans: TextSpan[]) { this.taoInvalidReason = 'verifyOutliningSpans NYI'; diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index 8fac5e45dab..3b5d8cd3fff 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -67,8 +67,8 @@ class TypeWriterWalker { case ts.SyntaxKind.ContinueStatement: case ts.SyntaxKind.BreakStatement: return (parent).label === identifier; - case ts.SyntaxKind.LabelledStatement: - return (parent).label === identifier; + case ts.SyntaxKind.LabeledStatement: + return (parent).label === identifier; } return false; } diff --git a/src/services/services.ts b/src/services/services.ts index d7edb4349bb..7447e56df86 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -76,7 +76,7 @@ module ts { var scanner: Scanner = createScanner(ScriptTarget.ES5); - var emptyArray: any [] = []; + var emptyArray: any[] = []; function createNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags, parent?: Node): NodeObject { var node = new (getNodeConstructor(kind))(); @@ -260,7 +260,7 @@ module ts { getProperty(propertyName: string): Symbol { return this.checker.getPropertyOfType(this, propertyName); } - getApparentProperties(): Symbol[]{ + getApparentProperties(): Symbol[] { return this.checker.getAugmentedPropertiesOfApparentType(this); } getCallSignatures(): Signature[] { @@ -303,7 +303,7 @@ module ts { } } - var incrementalParse: IncrementalParse = TypeScript.IncrementalParser.parse; + var incrementalParse: IncrementalParse = TypeScript.IncrementalParser.parse; class SourceFileObject extends NodeObject implements SourceFile { public filename: string; @@ -363,7 +363,7 @@ module ts { public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile { // See if we are currently holding onto a syntax tree. We may not be because we're // either a closed file, or we've just been lazy and haven't had to create the syntax - // tree yet. Access the field instead of the method so we don't accidently realize + // tree yet. Access the field instead of the method so we don't accidentally realize // the old syntax tree. var oldSyntaxTree = this.syntaxTree; @@ -431,6 +431,9 @@ module ts { getSemanticDiagnostics(fileName: string): Diagnostic[]; getCompilerOptionsDiagnostics(): Diagnostic[]; + getSyntacticClassifications(fileName: string, span: TypeScript.TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TypeScript.TextSpan): ClassifiedSpan[]; + getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo; getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; @@ -468,6 +471,32 @@ module ts { dispose(): void; } + export class ClassificationTypeNames { + public static comment = "comment"; + public static identifier = "identifier"; + public static keyword = "keyword"; + public static numericLiteral = "number"; + public static operator = "operator"; + public static stringLiteral = "string"; + public static whiteSpace = "whitespace"; + public static text = "text"; + + public static punctuation = "punctuation"; + + public static className = "class name"; + public static enumName = "enum name"; + public static interfaceName = "interface name"; + public static moduleName = "module name"; + public static typeParameterName = "type parameter name"; + } + + export class ClassifiedSpan { + constructor(public textSpan: TypeScript.TextSpan, + public classificationType: string) { + + } + } + export class NavigationBarItem { constructor(public text: string, public kind: string, @@ -1277,8 +1306,8 @@ module ts { /// Helpers function getTargetLabel(referenceNode: Node, labelName: string): Identifier { while (referenceNode) { - if (referenceNode.kind === SyntaxKind.LabelledStatement && (referenceNode).label.text === labelName) { - return (referenceNode).label; + if (referenceNode.kind === SyntaxKind.LabeledStatement && (referenceNode).label.text === labelName) { + return (referenceNode).label; } referenceNode = referenceNode.parent; } @@ -1293,8 +1322,22 @@ module ts { function isLabelOfLabeledStatement(node: Node): boolean { return node.kind === SyntaxKind.Identifier && - node.parent.kind === SyntaxKind.LabelledStatement && - (node.parent).label === node; + node.parent.kind === SyntaxKind.LabeledStatement && + (node.parent).label === node; + } + + /** + * Whether or not a 'node' is preceded by a label of the given string. + * Note: 'node' cannot be a SourceFile. + */ + function isLabeledBy(node: Node, labelName: string) { + for (var owner = node.parent; owner.kind === SyntaxKind.LabeledStatement; owner = owner.parent) { + if ((owner).label.text === labelName) { + return true; + } + } + + return false; } function isLabelName(node: Node): boolean { @@ -1313,20 +1356,6 @@ module ts { return node.parent.kind === SyntaxKind.NewExpression && (node.parent).func === node; } - function isAnyFunction(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ArrowFunction: - case SyntaxKind.Method: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.Constructor: - return true; - } - return false; - } - function isNameOfFunctionDeclaration(node: Node): boolean { return node.kind === SyntaxKind.Identifier && isAnyFunction(node.parent) && (node.parent).name === node; @@ -1364,11 +1393,19 @@ module ts { } enum SearchMeaning { + None = 0x0, Value = 0x1, Type = 0x2, Namespace = 0x4 } + enum BreakContinueSearchType { + None = 0x0, + Unlabeled = 0x1, + Labeled = 0x2, + All = Unlabeled | Labeled + } + // A cache of completion entries for keywords, these do not change between sessions var keywordCompletions:CompletionEntry[] = []; for (var i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) { @@ -1386,7 +1423,7 @@ module ts { var program: Program; // this checker is used to answer all LS questions except errors var typeInfoResolver: TypeChecker; - // the sole purpose of this checkes is to reutrn semantic diagnostics + // the sole purpose of this check is to return semantic diagnostics // creation is deferred - use getFullTypeCheckChecker to get instance var fullTypeCheckChecker_doNotAccessDirectly: TypeChecker; var useCaseSensitivefilenames = false; @@ -1530,7 +1567,7 @@ module ts { sourceFile = documentRegistry.acquireDocument(filename, compilationSettings, scriptSnapshot, version, isOpen); } - // Remeber the new sourceFile + // Remember the new sourceFile sourceFilesByName[filename] = sourceFile; } @@ -1585,7 +1622,7 @@ module ts { var firstChar = displayName.charCodeAt(0); if (firstChar === TypeScript.CharacterCodes.singleQuote || firstChar === TypeScript.CharacterCodes.doubleQuote) { // If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an - // invalid identifer name. We need to check if whatever was inside the quotes is actually a valid identifier name. + // invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name. displayName = TypeScript.stripStartAndEndQuotes(displayName); } @@ -1627,9 +1664,9 @@ module ts { } function isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - // We shouldn't be getting a possition that is outside the file because + // We shouldn't be getting a position that is outside the file because // isEntirelyInsideComment can't handle when the position is out of bounds, - // callers should be fixed, however we should be resiliant to bad inputs + // callers should be fixed, however we should be resilient to bad inputs // so we return true (this position is a blocker for getting completions) if (position < 0 || position > TypeScript.fullWidth(sourceUnit)) { return true; @@ -1719,12 +1756,12 @@ module ts { var positionedToken = TypeScript.Syntax.findCompleteTokenOnLeft(sourceUnit, position, /*includeSkippedTokens*/true); if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() == TypeScript.SyntaxKind.EndOfFileToken) { - // EndOfFile token is not intresting, get the one before it + // EndOfFile token is not interesting, get the one before it positionedToken = TypeScript. previousToken(positionedToken, /*includeSkippedTokens*/true); } if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() === TypeScript.SyntaxKind.IdentifierName) { - // The caret is at the end of an identifier, the decession to provide completion depends on the previous token + // The caret is at the end of an identifier, the decision to provide completion depends on the previous token positionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true); } @@ -1854,14 +1891,14 @@ module ts { // // get existing members // var existingMembers = compiler.getVisibleMemberSymbolsFromAST(node, document); - // // Add filtterd items to the completion list + // // Add filtered items to the completion list // getCompletionEntriesFromSymbols({ // symbols: filterContextualMembersList(contextualMembers.symbols, existingMembers, filename, position), // enclosingScopeSymbol: contextualMembers.enclosingScopeSymbol // }, entries); //} } - // Get scope memebers + // Get scope members else { isMemberCompletion = false; /// TODO filter meaning based on the current context @@ -1885,7 +1922,7 @@ module ts { function getCompletionEntryDetails(filename: string, position: number, entryName: string) { // Note: No need to call synchronizeHostData, as we have captured all the data we need - // in the getCompletionsAtPosition erlier + // in the getCompletionsAtPosition earlier filename = TypeScript.switchToForwardSlashes(filename); var session = activeCompletionSession; @@ -2149,7 +2186,6 @@ module ts { return result; } - /// Find references function getOccurrencesAtPosition(filename: string, position: number): ReferenceEntry[] { synchronizeHostData(); @@ -2161,11 +2197,23 @@ module ts { return undefined; } - if (node.kind === SyntaxKind.Identifier || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || + isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { return getReferencesForNode(node, [sourceFile]); } switch (node.kind) { + case SyntaxKind.IfKeyword: + case SyntaxKind.ElseKeyword: + if (hasKind(node.parent, SyntaxKind.IfStatement)) { + return getIfElseOccurrences(node.parent); + } + break; + case SyntaxKind.ReturnKeyword: + if (hasKind(node.parent, SyntaxKind.ReturnStatement)) { + return getReturnOccurrences(node.parent); + } + break; case SyntaxKind.TryKeyword: case SyntaxKind.CatchKeyword: case SyntaxKind.FinallyKeyword: @@ -2185,14 +2233,107 @@ module ts { } break; case SyntaxKind.BreakKeyword: - if (hasKind(node.parent, SyntaxKind.BreakStatement)) { - return getBreakStatementOccurences(node.parent); + case SyntaxKind.ContinueKeyword: + if (hasKind(node.parent, SyntaxKind.BreakStatement) || hasKind(node.parent, SyntaxKind.ContinueStatement)) { + return getBreakOrContinueStatementOccurences(node.parent); + } + break; + case SyntaxKind.ForKeyword: + if (hasKind(node.parent, SyntaxKind.ForStatement) || hasKind(node.parent, SyntaxKind.ForInStatement)) { + return getLoopBreakContinueOccurrences(node.parent); + } + break; + case SyntaxKind.WhileKeyword: + case SyntaxKind.DoKeyword: + if (hasKind(node.parent, SyntaxKind.WhileStatement) || hasKind(node.parent, SyntaxKind.DoStatement)) { + return getLoopBreakContinueOccurrences(node.parent); + } + break; + case SyntaxKind.ConstructorKeyword: + if (hasKind(node.parent, SyntaxKind.Constructor)) { + return getConstructorOccurrences(node.parent); } break; } return undefined; + function getIfElseOccurrences(ifStatement: IfStatement): ReferenceEntry[] { + var keywords: Node[] = []; + + // Traverse upwards through all parent if-statements linked by their else-branches. + while (hasKind(ifStatement.parent, SyntaxKind.IfStatement) && (ifStatement.parent).elseStatement === ifStatement) { + ifStatement = ifStatement.parent; + } + + // Now traverse back down through the else branches, aggregating if/else keywords of if-statements. + while (ifStatement) { + var children = ifStatement.getChildren(); + pushKeywordIf(keywords, children[0], SyntaxKind.IfKeyword); + + // Generally the 'else' keyword is second-to-last, so we traverse backwards. + for (var i = children.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, children[i], SyntaxKind.ElseKeyword)) { + break; + } + } + + if (!hasKind(ifStatement.elseStatement, SyntaxKind.IfStatement)) { + break + } + + ifStatement = ifStatement.elseStatement; + } + + var result: ReferenceEntry[] = []; + + // We'd like to highlight else/ifs together if they are only separated by whitespace + // (i.e. the keywords are separated by no comments, no newlines). + for (var i = 0; i < keywords.length; i++) { + if (keywords[i].kind === SyntaxKind.ElseKeyword && i < keywords.length - 1) { + var elseKeyword = keywords[i]; + var ifKeyword = keywords[i + 1]; // this *should* always be an 'if' keyword. + + var shouldHighlightNextKeyword = true; + + // Avoid recalculating getStart() by iterating backwards. + for (var j = ifKeyword.getStart() - 1; j >= elseKeyword.end; j--) { + if (!isWhiteSpace(sourceFile.text.charCodeAt(j))) { + shouldHighlightNextKeyword = false; + break; + } + } + + if (shouldHighlightNextKeyword) { + result.push(new ReferenceEntry(filename, TypeScript.TextSpan.fromBounds(elseKeyword.getStart(), ifKeyword.end), /* isWriteAccess */ false)); + i++; // skip the next keyword + continue; + } + } + + // Ordinary case: just highlight the keyword. + result.push(getReferenceEntryFromNode(keywords[i])); + } + + return result; + } + + function getReturnOccurrences(returnStatement: ReturnStatement): ReferenceEntry[] { + var func = getContainingFunction(returnStatement); + + // If we didn't find a containing function with a block body, bail out. + if (!(func && hasKind(func.body, SyntaxKind.FunctionBlock))) { + return undefined; + } + + var keywords: Node[] = [] + forEachReturnStatement((func).body, returnStatement => { + pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword); + }); + + return map(keywords, getReferenceEntryFromNode); + } + function getTryCatchFinallyOccurrences(tryStatement: TryStatement): ReferenceEntry[] { var keywords: Node[] = []; @@ -2206,7 +2347,34 @@ module ts { pushKeywordIf(keywords, tryStatement.finallyBlock.getFirstToken(), SyntaxKind.FinallyKeyword); } - return keywordsToReferenceEntries(keywords); + return map(keywords, getReferenceEntryFromNode); + } + + function getLoopBreakContinueOccurrences(loopNode: IterationStatement): ReferenceEntry[] { + var keywords: Node[] = []; + + if (pushKeywordIf(keywords, loopNode.getFirstToken(), SyntaxKind.ForKeyword, SyntaxKind.WhileKeyword, SyntaxKind.DoKeyword)) { + // If we succeeded and got a do-while loop, then start looking for a 'while' keyword. + if (loopNode.kind === SyntaxKind.DoStatement) { + var loopTokens = loopNode.getChildren(); + + for (var i = loopTokens.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, loopTokens[i], SyntaxKind.WhileKeyword)) { + break; + } + } + } + } + + var breaksAndContinues = aggregateAllBreakAndContinueStatements(loopNode.statement); + + forEach(breaksAndContinues, statement => { + if (ownsBreakOrContinueStatement(loopNode, statement)) { + pushKeywordIf(keywords, statement.getFirstToken(), SyntaxKind.BreakKeyword, SyntaxKind.ContinueKeyword); + } + }); + + return map(keywords, getReferenceEntryFromNode); } function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement) { @@ -2214,68 +2382,111 @@ module ts { pushKeywordIf(keywords, switchStatement.getFirstToken(), SyntaxKind.SwitchKeyword); - // Go through each clause in the switch statement, collecting the clause keywords. + // Types of break statements we can grab on to. + var breakSearchType = BreakContinueSearchType.All; + + // Go through each clause in the switch statement, collecting the 'case'/'default' keywords. forEach(switchStatement.clauses, clause => { pushKeywordIf(keywords, clause.getFirstToken(), SyntaxKind.CaseKeyword, SyntaxKind.DefaultKeyword); - // For each clause, also recursively traverse the statements where we can find analogous breaks. - forEachChild(clause, function aggregateBreakKeywords(node: Node): void { - switch (node.kind) { - case SyntaxKind.BreakStatement: - // If the break statement has a label, it cannot be part of a switch block. - if (!(node).label) { - pushKeywordIf(keywords, node.getFirstToken(), SyntaxKind.BreakKeyword); - } - // Fall through - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.SwitchStatement: - return; - } + var breaksAndContinues = aggregateAllBreakAndContinueStatements(clause); - // Do not cross function boundaries. - if (!isAnyFunction(node)) { - forEachChild(node, aggregateBreakKeywords); + forEach(breaksAndContinues, statement => { + if (ownsBreakOrContinueStatement(switchStatement, statement)) { + pushKeywordIf(keywords, statement.getFirstToken(), SyntaxKind.BreakKeyword); } }); }); - return keywordsToReferenceEntries(keywords); + return map(keywords, getReferenceEntryFromNode); } - function getBreakStatementOccurences(breakStatement: BreakOrContinueStatement): ReferenceEntry[]{ - // TODO (drosen): Deal with labeled statements. - if (breakStatement.label) { - return undefined; - } - - for (var owner = node.parent; owner; owner = owner.parent) { + function getBreakOrContinueStatementOccurences(breakOrContinueStatement: BreakOrContinueStatement): ReferenceEntry[]{ + var owner = getBreakOrContinueOwner(breakOrContinueStatement); + + if (owner) { switch (owner.kind) { case SyntaxKind.ForStatement: case SyntaxKind.ForInStatement: case SyntaxKind.DoStatement: case SyntaxKind.WhileStatement: - // TODO (drosen): Handle loops! - return undefined; - + return getLoopBreakContinueOccurrences(owner) case SyntaxKind.SwitchStatement: return getSwitchCaseDefaultOccurrences(owner); - default: - if (isAnyFunction(owner)) { - return undefined; - } } } return undefined; } + function aggregateAllBreakAndContinueStatements(node: Node): BreakOrContinueStatement[] { + var statementAccumulator: BreakOrContinueStatement[] = [] + aggregate(node); + return statementAccumulator; + + function aggregate(node: Node): void { + if (node.kind === SyntaxKind.BreakStatement || node.kind === SyntaxKind.ContinueStatement) { + statementAccumulator.push(node); + } + // Do not cross function boundaries. + else if (!isAnyFunction(node)) { + forEachChild(node, aggregate); + } + }; + } + + function ownsBreakOrContinueStatement(owner: Node, statement: BreakOrContinueStatement): boolean { + var actualOwner = getBreakOrContinueOwner(statement); + + return actualOwner && actualOwner === owner; + } + + function getBreakOrContinueOwner(statement: BreakOrContinueStatement): Node { + for (var node = statement.parent; node; node = node.parent) { + switch (node.kind) { + case SyntaxKind.SwitchStatement: + if (statement.kind === SyntaxKind.ContinueStatement) { + continue; + } + // Fall through. + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.DoStatement: + if (!statement.label || isLabeledBy(node, statement.label.text)) { + return node; + } + break; + default: + // Don't cross function boundaries. + if (isAnyFunction(node)) { + return undefined; + } + break; + } + } + + return undefined; + } + + function getConstructorOccurrences(constructorDeclaration: ConstructorDeclaration): ReferenceEntry[] { + var declarations = constructorDeclaration.symbol.getDeclarations() + + var keywords: Node[] = []; + + forEach(declarations, declaration => { + forEach(declaration.getChildren(), token => { + return pushKeywordIf(keywords, token, SyntaxKind.ConstructorKeyword); + }); + }); + + return map(keywords, getReferenceEntryFromNode); + } + // returns true if 'node' is defined and has a matching 'kind'. function hasKind(node: Node, kind: SyntaxKind) { - return !!(node && node.kind === kind); + return node !== undefined && node.kind === kind; } // Null-propagating 'parent' function. @@ -2283,20 +2494,13 @@ module ts { return node && node.parent; } - function pushKeywordIf(keywordList: Node[], token: Node, ...expected: SyntaxKind[]): void { - if (!token) { - return; - } - - if (contains(expected, token.kind)) { + function pushKeywordIf(keywordList: Node[], token: Node, ...expected: SyntaxKind[]): boolean { + if (token && contains(expected, token.kind)) { keywordList.push(token); + return true; } - } - function keywordsToReferenceEntries(keywords: Node[]): ReferenceEntry[]{ - return map(keywords, keyword => - new ReferenceEntry(filename, TypeScript.TextSpan.fromBounds(keyword.getStart(), keyword.end), /* isWriteAccess */ false) - ); + return false; } } @@ -2312,6 +2516,9 @@ module ts { } if (node.kind !== SyntaxKind.Identifier && + // TODO (drosen): This should be enabled in a later release - currently breaks rename. + //node.kind !== SyntaxKind.ThisKeyword && + //node.kind !== SyntaxKind.SuperKeyword && !isLiteralNameOfPropertyDeclarationOrIndexAccess(node) && !isNameOfExternalModuleImportOrDeclaration(node)) { return undefined; @@ -2327,7 +2534,7 @@ module ts { var labelDefinition = getTargetLabel((node.parent), (node).text); // if we have a label definition, look within its statement for references, if not, then // the label is undefined, just return a set of one for the current node. - return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntry(node)]; + return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntryFromNode(node)]; } else { // it is a label definition and not a target, search within the parent labeledStatement @@ -2335,13 +2542,21 @@ module ts { } } + if (node.kind === SyntaxKind.ThisKeyword) { + return getReferencesForThisKeyword(node, sourceFiles); + } + + if (node.kind === SyntaxKind.SuperKeyword) { + return getReferencesForSuperKeyword(node); + } + var symbol = typeInfoResolver.getSymbolInfo(node); // Could not find a symbol e.g. unknown identifier if (!symbol) { - // Even if we did not find a symbol, we have an identifer, so there is at least - // one reference that we know of. return than instead of undefined. - return [getReferenceEntry(node)]; + // Even if we did not find a symbol, we have an identifier, so there is at least + // one reference that we know of. return that instead of undefined. + return [getReferenceEntryFromNode(node)]; } // the symbol was an internal symbol and does not have a declaration e.g.undefined symbol @@ -2485,7 +2700,7 @@ module ts { // Only pick labels that are either the target label, or have a target that is the target label if (node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) { - result.push(getReferenceEntry(node)); + result.push(getReferenceEntryFromNode(node)); } }); return result; @@ -2550,7 +2765,132 @@ module ts { } if (isRelatableToSearchSet(searchSymbols, referenceSymbol, referenceLocation)) { - result.push(getReferenceEntry(referenceLocation)); + result.push(getReferenceEntryFromNode(referenceLocation)); + } + }); + } + } + + function getReferencesForSuperKeyword(superKeyword: Node): ReferenceEntry[]{ + var searchSpaceNode = getSuperContainer(superKeyword); + if (!searchSpaceNode) { + return undefined; + } + // Whether 'super' occurs in a static context within a class. + var staticFlag = NodeFlags.Static; + + switch (searchSpaceNode.kind) { + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + staticFlag &= searchSpaceNode.flags; + searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class + break; + default: + return undefined; + } + + var result: ReferenceEntry[] = []; + + var sourceFile = searchSpaceNode.getSourceFile(); + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + var node = getNodeAtPosition(sourceFile, position); + + if (!node || node.kind !== SyntaxKind.SuperKeyword) { + return; + } + + var container = getSuperContainer(node); + + // If we have a 'super' container, we must have an enclosing class. + // Now make sure the owning class is the same as the search-space + // and has the same static qualifier as the original 'super's owner. + if (container && (NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + }); + + return result; + } + + function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: SourceFile[]): ReferenceEntry[] { + var searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false); + + // Whether 'this' occurs in a static context within a class. + var staticFlag = NodeFlags.Static; + + switch (searchSpaceNode.kind) { + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + staticFlag &= searchSpaceNode.flags + searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class + break; + case SyntaxKind.SourceFile: + if (isExternalModule(searchSpaceNode)) { + return undefined; + } + // Fall through + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + break; + default: + return undefined; + } + + var result: ReferenceEntry[] = []; + + if (searchSpaceNode.kind === SyntaxKind.SourceFile) { + forEach(sourceFiles, sourceFile => { + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd()); + getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, result); + }); + } + else { + var sourceFile = searchSpaceNode.getSourceFile(); + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result); + } + + return result; + + function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: number[], result: ReferenceEntry[]): void { + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + var node = getNodeAtPosition(sourceFile, position); + if (!node || node.kind !== SyntaxKind.ThisKeyword) { + return; + } + + var container = getThisContainer(node, /* includeArrowFunctions */ false); + + switch (searchSpaceNode.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + if (searchSpaceNode.symbol === container.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.ClassDeclaration: + // Make sure the container belongs to the same class + // and has the appropriate static modifier from the original container. + if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.SourceFile: + if (container.kind === SyntaxKind.SourceFile && !isExternalModule(container)) { + result.push(getReferenceEntryFromNode(node)); + } + break; } }); } @@ -2604,7 +2944,7 @@ module ts { var propertySymbol = typeReferenceSymbol.members[propertyName]; if (propertySymbol) result.push(typeReferenceSymbol.members[propertyName]); - // Visit the typeReference as well to see if it directelly or indirectelly use that property + // Visit the typeReference as well to see if it directly or indirectly use that property getPropertySymbolsFromBaseTypes(typeReferenceSymbol, propertyName, result); } } @@ -2612,7 +2952,7 @@ module ts { } function isRelatableToSearchSet(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node): boolean { - // Unwrap symbols to get to the root (e.g. triansient symbols as a result of widenning) + // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) var referenceSymbolTarget = typeInfoResolver.getRootSymbol(referenceSymbol); // if it is in the list, then we are done @@ -2630,7 +2970,7 @@ module ts { } } - // Finally, try all properties with the same name in any type the containing type extened or implemented, and + // Finally, try all properties with the same name in any type the containing type extend or implemented, and // see if any is in the list if (referenceSymbol.parent && referenceSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) { var result: Symbol[] = []; @@ -2652,18 +2992,6 @@ module ts { return undefined; } - function getReferenceEntry(node: Node): ReferenceEntry { - var start = node.getStart(); - var end = node.getEnd(); - - if (node.kind === SyntaxKind.StringLiteral) { - start += 1; - end -= 1; - } - - return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node)); - } - function getMeaningFromDeclaration(node: Declaration): SearchMeaning { switch (node.kind) { case SyntaxKind.Parameter: @@ -2705,7 +3033,7 @@ module ts { case SyntaxKind.ImportDeclaration: return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace; } - Debug.fail("Unkown declaration type"); + Debug.fail("Unknown declaration type"); } function isTypeReference(node: Node): boolean { @@ -2786,7 +3114,7 @@ module ts { // intersects with the class in the value space. // To achieve that we will keep iterating until the result stabilizes. - // Remeber the last meaning + // Remember the last meaning var lastIterationMeaning = meaning; for (var i = 0, n = declarations.length; i < n; i++) { @@ -2800,40 +3128,38 @@ module ts { } return meaning; } + } - /// A node is considedered a writeAccess iff it is a name of a declaration or a target of an assignment - function isWriteAccess(node: Node): boolean { - if (node.kind === SyntaxKind.Identifier && isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { + function getReferenceEntryFromNode(node: Node): ReferenceEntry { + var start = node.getStart(); + var end = node.getEnd(); + + if (node.kind === SyntaxKind.StringLiteral) { + start += 1; + end -= 1; + } + + return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node)); + } + + /// A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment + function isWriteAccess(node: Node): boolean { + if (node.kind === SyntaxKind.Identifier && isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { + return true; + } + + var parent = node.parent; + if (parent) { + if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) { return true; } - - var parent = node.parent; - if (parent) { - if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) { - return true; - } - else if (parent.kind === SyntaxKind.BinaryExpression && (parent).left === node) { - var operator = (parent).operator; - switch (operator) { - case SyntaxKind.AsteriskEqualsToken: - case SyntaxKind.SlashEqualsToken: - case SyntaxKind.PercentEqualsToken: - case SyntaxKind.MinusEqualsToken: - case SyntaxKind.LessThanLessThanEqualsToken: - case SyntaxKind.GreaterThanGreaterThanEqualsToken: - case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - case SyntaxKind.BarEqualsToken: - case SyntaxKind.CaretEqualsToken: - case SyntaxKind.AmpersandEqualsToken: - case SyntaxKind.PlusEqualsToken: - case SyntaxKind.EqualsToken: - return true; - } - } - - return false; + else if (parent.kind === SyntaxKind.BinaryExpression && (parent).left === node) { + var operator = (parent).operator; + return SyntaxKind.FirstAssignment <= operator && operator <= SyntaxKind.LastAssignment; } } + + return false; } /// Syntactic features @@ -2918,6 +3244,198 @@ module ts { return new TypeScript.Services.NavigationBarItemGetter().getItems(syntaxTree.sourceUnit()); } + function getSemanticClassifications(fileName: string, span: TypeScript.TextSpan): ClassifiedSpan[] { + synchronizeHostData(); + fileName = TypeScript.switchToForwardSlashes(fileName); + + var sourceFile = getSourceFile(fileName); + + var result: ClassifiedSpan[] = []; + processNode(sourceFile); + + return result; + + function classifySymbol(symbol: Symbol) { + var flags = symbol.getFlags(); + + if (flags & SymbolFlags.Class) { + return ClassificationTypeNames.className; + } + else if (flags & SymbolFlags.Enum) { + return ClassificationTypeNames.enumName; + } + else if (flags & SymbolFlags.Interface) { + return ClassificationTypeNames.interfaceName; + } + else if (flags & SymbolFlags.Module) { + return ClassificationTypeNames.moduleName; + } + else if (flags & SymbolFlags.TypeParameter) { + return ClassificationTypeNames.typeParameterName; + } + } + + function processNode(node: Node) { + // Only walk into nodes that intersect the requested span. + if (node && span.intersectsWith(node.getStart(), node.getWidth())) { + if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) { + var symbol = typeInfoResolver.getSymbolInfo(node); + if (symbol) { + var type = classifySymbol(symbol); + if (type) { + result.push(new ClassifiedSpan( + new TypeScript.TextSpan(node.getStart(), node.getWidth()), + type)); + } + } + } + + forEachChild(node, processNode); + } + } + } + + function getSyntacticClassifications(fileName: string, span: TypeScript.TextSpan): ClassifiedSpan[] { + // doesn't use compiler - no need to synchronize with host + fileName = TypeScript.switchToForwardSlashes(fileName); + var sourceFile = getCurrentSourceFile(fileName); + + var result: ClassifiedSpan[] = []; + processElement(sourceFile.getSourceUnit()); + + return result; + + function classifyTrivia(trivia: TypeScript.ISyntaxTrivia) { + if (trivia.isComment() && span.intersectsWith(trivia.fullStart(), trivia.fullWidth())) { + result.push(new ClassifiedSpan( + new TypeScript.TextSpan(trivia.fullStart(), trivia.fullWidth()), + ClassificationTypeNames.comment)); + } + } + + function classifyTriviaList(trivia: TypeScript.ISyntaxTriviaList) { + for (var i = 0, n = trivia.count(); i < n; i++) { + classifyTrivia(trivia.syntaxTriviaAt(i)); + } + } + + function classifyToken(token: TypeScript.ISyntaxToken) { + if (token.hasLeadingComment()) { + classifyTriviaList(token.leadingTrivia()); + } + + if (TypeScript.width(token) > 0) { + var type = classifyTokenType(token); + if (type) { + result.push(new ClassifiedSpan( + new TypeScript.TextSpan(TypeScript.start(token), TypeScript.width(token)), + type)); + } + } + + if (token.hasTrailingComment()) { + classifyTriviaList(token.trailingTrivia()); + } + } + + function classifyTokenType(token: TypeScript.ISyntaxToken): string { + var tokenKind = token.kind(); + if (TypeScript.SyntaxFacts.isAnyKeyword(token.kind())) { + return ClassificationTypeNames.keyword; + } + + // Special case < and > If they appear in a generic context they are punctation, + // not operators. + if (tokenKind === TypeScript.SyntaxKind.LessThanToken || tokenKind === TypeScript.SyntaxKind.GreaterThanToken) { + var tokenParentKind = token.parent.kind(); + if (tokenParentKind === TypeScript.SyntaxKind.TypeArgumentList || + tokenParentKind === TypeScript.SyntaxKind.TypeParameterList) { + + return ClassificationTypeNames.punctuation; + } + } + + if (TypeScript.SyntaxFacts.isBinaryExpressionOperatorToken(tokenKind) || + TypeScript.SyntaxFacts.isPrefixUnaryExpressionOperatorToken(tokenKind)) { + return ClassificationTypeNames.operator; + } + else if (TypeScript.SyntaxFacts.isAnyPunctuation(tokenKind)) { + return ClassificationTypeNames.punctuation; + } + else if (tokenKind === TypeScript.SyntaxKind.NumericLiteral) { + return ClassificationTypeNames.numericLiteral; + } + else if (tokenKind === TypeScript.SyntaxKind.StringLiteral) { + return ClassificationTypeNames.stringLiteral; + } + else if (tokenKind === TypeScript.SyntaxKind.RegularExpressionLiteral) { + // TODO: we shoudl get another classification type for these literals. + return ClassificationTypeNames.stringLiteral; + } + else if (tokenKind === TypeScript.SyntaxKind.IdentifierName) { + var current: TypeScript.ISyntaxNodeOrToken = token; + var parent = token.parent; + while (parent.kind() === TypeScript.SyntaxKind.QualifiedName) { + current = parent; + parent = parent.parent; + } + + switch (parent.kind()) { + case TypeScript.SyntaxKind.SimplePropertyAssignment: + if ((parent).propertyName === token) { + return ClassificationTypeNames.identifier; + } + return; + case TypeScript.SyntaxKind.ClassDeclaration: + if ((parent).identifier === token) { + return ClassificationTypeNames.className; + } + return; + case TypeScript.SyntaxKind.TypeParameter: + if ((parent).identifier === token) { + return ClassificationTypeNames.typeParameterName; + } + return; + case TypeScript.SyntaxKind.InterfaceDeclaration: + if ((parent).identifier === token) { + return ClassificationTypeNames.interfaceName; + } + return; + case TypeScript.SyntaxKind.EnumDeclaration: + if ((parent).identifier === token) { + return ClassificationTypeNames.enumName; + } + return; + case TypeScript.SyntaxKind.ModuleDeclaration: + if ((parent).name === current) { + return ClassificationTypeNames.moduleName; + } + return; + default: + return ClassificationTypeNames.text; + } + } + } + + function processElement(element: TypeScript.ISyntaxElement) { + // Ignore nodes that don't intersect the original span to classify. + if (!TypeScript.isShared(element) && span.intersectsWith(TypeScript.fullStart(element), TypeScript.fullWidth(element))) { + for (var i = 0, n = TypeScript.childCount(element); i < n; i++) { + var child = TypeScript.childAt(element, i); + if (child) { + if (TypeScript.isToken(child)) { + classifyToken(child); + } + else { + // Recurse into our child nodes. + processElement(child); + } + } + } + } + } + } + function getOutliningSpans(filename: string): OutliningSpan[] { // doesn't use compiler - no need to synchronize with host filename = TypeScript.switchToForwardSlashes(filename); @@ -3098,7 +3616,7 @@ module ts { var preamble = matchArray[1]; var matchPosition = matchArray.index + preamble.length; - // Ok, we have found a match in the file. This is ony an acceptable match if + // Ok, we have found a match in the file. This is only an acceptable match if // it is contained within a comment. var token = TypeScript.findToken(syntaxTree.sourceUnit(), matchPosition); @@ -3108,7 +3626,7 @@ module ts { continue; } - // Looks to be within the trivia. See if we can find hte comment containing it. + // Looks to be within the trivia. See if we can find the comment containing it. var triviaList = matchPosition < TypeScript.start(token) ? token.leadingTrivia(syntaxTree.text) : token.trailingTrivia(syntaxTree.text); var trivia = findContainingComment(triviaList, matchPosition); if (trivia === null) { @@ -3161,6 +3679,8 @@ module ts { getSyntacticDiagnostics: getSyntacticDiagnostics, getSemanticDiagnostics: getSemanticDiagnostics, getCompilerOptionsDiagnostics: getCompilerOptionsDiagnostics, + getSyntacticClassifications: getSyntacticClassifications, + getSemanticClassifications: getSemanticClassifications, getCompletionsAtPosition: getCompletionsAtPosition, getCompletionEntryDetails: getCompletionEntryDetails, getTypeAtPosition: getTypeAtPosition, @@ -3316,7 +3836,7 @@ module ts { addResult(start - lastTokenOrCommentEnd, TokenClass.Whitespace); } - // Remeber the end of the last token + // Remember the end of the last token lastTokenOrCommentEnd = end; } diff --git a/src/services/shims.ts b/src/services/shims.ts index 0659f9f2512..c626bba0b4c 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -80,6 +80,8 @@ module ts { getSemanticDiagnostics(fileName: string): string; getCompilerOptionsDiagnostics(): string; + getSyntacticClassifications(fileName: string, start: number, length: number): string; + getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string; getCompletionEntryDetails(fileName: string, position: number, entryName: string): string; @@ -477,6 +479,24 @@ module ts { }; } + public getSyntacticClassifications(fileName: string, start: number, length: number): string { + return this.forwardJSONCall( + "getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")", + () => { + var classifications = this.languageService.getSyntacticClassifications(fileName, new TypeScript.TextSpan(start, length)); + return classifications; + }); + } + + public getSemanticClassifications(fileName: string, start: number, length: number): string { + return this.forwardJSONCall( + "getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")", + () => { + var classifications = this.languageService.getSemanticClassifications(fileName, new TypeScript.TextSpan(start, length)); + return classifications; + }); + } + public getSyntacticDiagnostics(fileName: string): string { return this.forwardJSONCall( "getSyntacticDiagnostics('" + fileName + "')", diff --git a/src/services/text/textSpan.ts b/src/services/text/textSpan.ts index d719e244010..999070a73b4 100644 --- a/src/services/text/textSpan.ts +++ b/src/services/text/textSpan.ts @@ -1,6 +1,7 @@ /// module TypeScript { + export interface ISpan { start(): number; end(): number; diff --git a/tests/baselines/reference/arrayBestCommonTypes.types b/tests/baselines/reference/arrayBestCommonTypes.types index 40f74350fe5..a0f407358c3 100644 --- a/tests/baselines/reference/arrayBestCommonTypes.types +++ b/tests/baselines/reference/arrayBestCommonTypes.types @@ -222,7 +222,7 @@ class f { >base : base >[ { x: undefined, y: new base() }, { x: '', y: new derived() } ] : { x: string; y: base; }[] >{ x: undefined, y: new base() } : { x: undefined; y: base; } ->x : any +>x : undefined >undefined : undefined >y : base >new base() : base diff --git a/tests/baselines/reference/declFileRegressionTests.types b/tests/baselines/reference/declFileRegressionTests.types index f230d93f0dd..8d058769c0a 100644 --- a/tests/baselines/reference/declFileRegressionTests.types +++ b/tests/baselines/reference/declFileRegressionTests.types @@ -4,7 +4,7 @@ var n = { w: null, x: '', y: () => { }, z: 32 }; >n : { w: any; x: string; y: () => void; z: number; } >{ w: null, x: '', y: () => { }, z: 32 } : { w: null; x: string; y: () => void; z: number; } ->w : any +>w : null >x : string >y : () => void >() => { } : () => void diff --git a/tests/baselines/reference/declInput3.types b/tests/baselines/reference/declInput3.types index 4147396b26d..df69422f55b 100644 --- a/tests/baselines/reference/declInput3.types +++ b/tests/baselines/reference/declInput3.types @@ -16,9 +16,9 @@ class bar { >a : bar >null : bar >bar : bar ->b : any +>b : undefined >undefined : undefined ->c : any +>c : undefined >void 4 : undefined public h(x = 4, y = null, z = '') { x++; } diff --git a/tests/baselines/reference/decrementOperatorWithAnyOtherType.types b/tests/baselines/reference/decrementOperatorWithAnyOtherType.types index 1a4aea0d507..4e8387f9066 100644 --- a/tests/baselines/reference/decrementOperatorWithAnyOtherType.types +++ b/tests/baselines/reference/decrementOperatorWithAnyOtherType.types @@ -15,7 +15,7 @@ var obj = {x:1,y:null}; >obj : { x: number; y: any; } >{x:1,y:null} : { x: number; y: null; } >x : number ->y : any +>y : null class A { >A : A diff --git a/tests/baselines/reference/doNotWidenAtObjectLiteralPropertyAssignment.types b/tests/baselines/reference/doNotWidenAtObjectLiteralPropertyAssignment.types index 24eafce8cde..225bca8de63 100644 --- a/tests/baselines/reference/doNotWidenAtObjectLiteralPropertyAssignment.types +++ b/tests/baselines/reference/doNotWidenAtObjectLiteralPropertyAssignment.types @@ -26,5 +26,5 @@ var test: IIntervalTreeNode[] = [{ interval: { begin: 0 }, children: null }]; // >interval : { begin: number; } >{ begin: 0 } : { begin: number; } >begin : number ->children : any +>children : null diff --git a/tests/baselines/reference/forStatementsMultipleValidDecl.types b/tests/baselines/reference/forStatementsMultipleValidDecl.types index f894eef1404..2f3bfd70cea 100644 --- a/tests/baselines/reference/forStatementsMultipleValidDecl.types +++ b/tests/baselines/reference/forStatementsMultipleValidDecl.types @@ -39,7 +39,7 @@ for (var p: Point = { x: 0, y: undefined }; ;) { } >Point : Point >{ x: 0, y: undefined } : { x: number; y: undefined; } >x : number ->y : any +>y : undefined >undefined : undefined for (var p = { x: 1, y: undefined }; ;) { } @@ -65,7 +65,7 @@ for (var p = <{ x: number; y: number; }>{ x: 0, y: undefined }; ;) { } >y : number >{ x: 0, y: undefined } : { x: number; y: undefined; } >x : number ->y : any +>y : undefined >undefined : undefined for (var p: typeof p; ;) { } diff --git a/tests/baselines/reference/functionImplementations.types b/tests/baselines/reference/functionImplementations.types index fe03fa58d98..29fe7c0e39c 100644 --- a/tests/baselines/reference/functionImplementations.types +++ b/tests/baselines/reference/functionImplementations.types @@ -253,8 +253,8 @@ function opt2(n = { x: null, y: undefined }) { >opt2 : (n?: { x: any; y: any; }) => void >n : { x: any; y: any; } >{ x: null, y: undefined } : { x: null; y: undefined; } ->x : any ->y : any +>x : null +>y : undefined >undefined : undefined var m = n; diff --git a/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt b/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt new file mode 100644 index 00000000000..84366f86ec7 --- /dev/null +++ b/tests/baselines/reference/implicitAnyFromCircularInference.errors.txt @@ -0,0 +1,73 @@ +==== tests/cases/compiler/implicitAnyFromCircularInference.ts (9 errors) ==== + + // Error expected + var a: typeof a; + ~ +!!! 'a' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation. + + // Error expected on b or c + var b: typeof c; + var c: typeof b; + ~ +!!! 'c' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation. + + // Error expected + var d: Array; + ~ +!!! 'd' implicitly has type 'any' because it is referenced directly or indirectly in its own type annotation. + + function f() { return f; } + + // Error expected + function g() { return g(); } + ~ +!!! 'g' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + + // Error expected + var f1 = function () { + ~~~~~~~~~~~~~ + return f1(); + ~~~~~~~~~~~~~~~~ + }; + ~ +!!! Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + + // Error expected + var f2 = () => f2(); + ~~~~~~~~~~ +!!! Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + + // Error expected + function h() { + ~ +!!! 'h' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + return foo(); + function foo() { + return h() || "hello"; + } + } + + interface A { + s: string; + } + + function foo(x: A): string { return "abc"; } + + class C { + // Error expected + s = foo(this); + ~~~~~~~~~~~~~~ +!!! 's' implicitly has type 'any' because it is does not have a type annotation and is referenced directly or indirectly in its own initializer. + } + + class D { + // Error expected + get x() { + ~~~~~~~~~ + return this.x; + ~~~~~~~~~~~~~~~~~~~~~~ + } + ~~~~~ +!!! 'x' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions. + } + \ No newline at end of file diff --git a/tests/baselines/reference/implicitAnyFromCircularInference.js b/tests/baselines/reference/implicitAnyFromCircularInference.js new file mode 100644 index 00000000000..d97b8420ebf --- /dev/null +++ b/tests/baselines/reference/implicitAnyFromCircularInference.js @@ -0,0 +1,103 @@ +//// [implicitAnyFromCircularInference.ts] + +// Error expected +var a: typeof a; + +// Error expected on b or c +var b: typeof c; +var c: typeof b; + +// Error expected +var d: Array; + +function f() { return f; } + +// Error expected +function g() { return g(); } + +// Error expected +var f1 = function () { + return f1(); +}; + +// Error expected +var f2 = () => f2(); + +// Error expected +function h() { + return foo(); + function foo() { + return h() || "hello"; + } +} + +interface A { + s: string; +} + +function foo(x: A): string { return "abc"; } + +class C { + // Error expected + s = foo(this); +} + +class D { + // Error expected + get x() { + return this.x; + } +} + + +//// [implicitAnyFromCircularInference.js] +// Error expected +var a; +// Error expected on b or c +var b; +var c; +// Error expected +var d; +function f() { + return f; +} +// Error expected +function g() { + return g(); +} +// Error expected +var f1 = function () { + return f1(); +}; +// Error expected +var f2 = function () { return f2(); }; +// Error expected +function h() { + return foo(); + function foo() { + return h() || "hello"; + } +} +function foo(x) { + return "abc"; +} +var C = (function () { + function C() { + // Error expected + this.s = foo(this); + } + return C; +})(); +var D = (function () { + function D() { + } + Object.defineProperty(D.prototype, "x", { + // Error expected + get: function () { + return this.x; + }, + enumerable: true, + configurable: true + }); + return D; +})(); diff --git a/tests/baselines/reference/incrementOperatorWithAnyOtherType.types b/tests/baselines/reference/incrementOperatorWithAnyOtherType.types index 3d43764943a..165c166941c 100644 --- a/tests/baselines/reference/incrementOperatorWithAnyOtherType.types +++ b/tests/baselines/reference/incrementOperatorWithAnyOtherType.types @@ -15,7 +15,7 @@ var obj = {x:1,y:null}; >obj : { x: number; y: any; } >{x:1,y:null} : { x: number; y: null; } >x : number ->y : any +>y : null class A { >A : A diff --git a/tests/baselines/reference/interfaceWithPropertyOfEveryType.types b/tests/baselines/reference/interfaceWithPropertyOfEveryType.types index 69ad29374a2..21d4359b6fb 100644 --- a/tests/baselines/reference/interfaceWithPropertyOfEveryType.types +++ b/tests/baselines/reference/interfaceWithPropertyOfEveryType.types @@ -95,7 +95,7 @@ var a: Foo = { >{} : {} e: null , ->e : any +>e : null f: [1], >f : number[] diff --git a/tests/baselines/reference/null.types b/tests/baselines/reference/null.types index 0614b5efec4..7a5232efb0b 100644 --- a/tests/baselines/reference/null.types +++ b/tests/baselines/reference/null.types @@ -41,7 +41,7 @@ var w:I={x:null,y:3}; >w : I >I : I >{x:null,y:3} : { x: null; y: number; } ->x : any +>x : null >y : number diff --git a/tests/baselines/reference/objectLiteralWidened.types b/tests/baselines/reference/objectLiteralWidened.types index e8dc707a489..3f9163e77ef 100644 --- a/tests/baselines/reference/objectLiteralWidened.types +++ b/tests/baselines/reference/objectLiteralWidened.types @@ -6,10 +6,10 @@ var x = { >{ foo: null, bar: undefined} : { foo: null; bar: undefined; } foo: null, ->foo : any +>foo : null bar: undefined ->bar : any +>bar : undefined >undefined : undefined } @@ -18,17 +18,17 @@ var y = { >{ foo: null, bar: { baz: null, boo: undefined }} : { foo: null; bar: { baz: null; boo: undefined; }; } foo: null, ->foo : any +>foo : null bar: { ->bar : { baz: any; boo: any; } +>bar : { baz: null; boo: undefined; } >{ baz: null, boo: undefined } : { baz: null; boo: undefined; } baz: null, ->baz : any +>baz : null boo: undefined ->boo : any +>boo : undefined >undefined : undefined } } diff --git a/tests/baselines/reference/overloadResolutionOverNonCTObjectLit.types b/tests/baselines/reference/overloadResolutionOverNonCTObjectLit.types index 6bc491fd157..846190010b4 100644 --- a/tests/baselines/reference/overloadResolutionOverNonCTObjectLit.types +++ b/tests/baselines/reference/overloadResolutionOverNonCTObjectLit.types @@ -61,7 +61,7 @@ module Bugs { >startIndex : number >type : string >bracket : number ->state : any +>state : null >length : number } } diff --git a/tests/baselines/reference/propertyNameWithoutTypeAnnotation.types b/tests/baselines/reference/propertyNameWithoutTypeAnnotation.types index bdc8452863d..520567d33a1 100644 --- a/tests/baselines/reference/propertyNameWithoutTypeAnnotation.types +++ b/tests/baselines/reference/propertyNameWithoutTypeAnnotation.types @@ -25,7 +25,7 @@ var b = { >{ foo: null} : { foo: null; } foo: null ->foo : any +>foo : null } // These should all be of type 'any' diff --git a/tests/baselines/reference/tupleTypes.errors.txt b/tests/baselines/reference/tupleTypes.errors.txt new file mode 100644 index 00000000000..1e1ebd07292 --- /dev/null +++ b/tests/baselines/reference/tupleTypes.errors.txt @@ -0,0 +1,87 @@ +==== tests/cases/compiler/tupleTypes.ts (9 errors) ==== + var v1: []; // Error + ~~ +!!! A tuple type element list cannot be empty. + var v2: [number]; + var v3: [number, string]; + var v4: [number, [string, string]]; + + var t: [number, string]; + var t0 = t[0]; // number + var t0: number; + var t1 = t[1]; // string + var t1: string; + var t2 = t[2]; // {} + var t2: {}; + + t = []; // Error + ~ +!!! Type '{}[]' is not assignable to type '[number, string]': +!!! Property '0' is missing in type '{}[]'. + t = [1]; // Error + ~ +!!! Type '[number]' is not assignable to type '[number, string]': +!!! Property '1' is missing in type '[number]'. + t = [1, "hello"]; // Ok + t = ["hello", 1]; // Error + ~ +!!! Type '[string, number]' is not assignable to type '[number, string]': +!!! Types of property '0' are incompatible: +!!! Type 'string' is not assignable to type 'number'. + t = [1, "hello", 2]; // Ok + + var tf: [string, (x: string) => number] = ["hello", x => x.length]; + + declare function ff(a: T, b: [T, (x: T) => U]): U; + var ff1 = ff("hello", ["foo", x => x.length]); + var ff1: number; + + function tuple2(item0: T0, item1: T1): [T0, T1]{ + return [item0, item1]; + } + + var tt = tuple2(1, "string"); + var tt0 = tt[0]; + var tt0: number; + var tt1 = tt[1]; + var tt1: string; + var tt2 = tt[2]; + var tt2: {}; + + tt = tuple2(1, undefined); + tt = [1, undefined]; + tt = [undefined, undefined]; + tt = []; // Error + ~~ +!!! Type '{}[]' is not assignable to type '[number, string]'. + + var a: number[]; + var a1: [number, string]; + var a2: [number, number]; + var a3: [number, {}]; + a = a1; // Error + ~ +!!! Type '[number, string]' is not assignable to type 'number[]': +!!! Types of property 'pop' are incompatible: +!!! Type '() => {}' is not assignable to type '() => number': +!!! Type '{}' is not assignable to type 'number'. + a = a2; + a = a3; // Error + ~ +!!! Type '[number, {}]' is not assignable to type 'number[]': +!!! Types of property 'pop' are incompatible: +!!! Type '() => {}' is not assignable to type '() => number': +!!! Type '{}' is not assignable to type 'number'. + a1 = a2; // Error + ~~ +!!! Type '[number, number]' is not assignable to type '[number, string]': +!!! Types of property '1' are incompatible: +!!! Type 'number' is not assignable to type 'string'. + a1 = a3; // Error + ~~ +!!! Type '[number, {}]' is not assignable to type '[number, string]': +!!! Types of property '1' are incompatible: +!!! Type '{}' is not assignable to type 'string'. + a3 = a1; + a3 = a2; + \ No newline at end of file diff --git a/tests/baselines/reference/typeArgInference2.types b/tests/baselines/reference/typeArgInference2.types index b6568afee24..1b94a0638bd 100644 --- a/tests/baselines/reference/typeArgInference2.types +++ b/tests/baselines/reference/typeArgInference2.types @@ -31,7 +31,7 @@ var z3 = foo({ name: null }); // { name: any } >foo({ name: null }) : { name: any; } >foo : (x?: T, y?: T) => T >{ name: null } : { name: null; } ->name : any +>name : null var z4 = foo({ name: "abc" }); // { name: string } >z4 : { name: string; } diff --git a/tests/baselines/reference/typeArgInferenceWithNull.types b/tests/baselines/reference/typeArgInferenceWithNull.types index 9fd3ea33e24..f480e7c169c 100644 --- a/tests/baselines/reference/typeArgInferenceWithNull.types +++ b/tests/baselines/reference/typeArgInferenceWithNull.types @@ -22,7 +22,7 @@ fn5({ x: null }); >fn5({ x: null }) : void >fn5 : (n: T) => void >{ x: null } : { x: null; } ->x : any +>x : null function fn6(n: T, fun: (x: T) => void, n2: T) { } >fn6 : (n: T, fun: (x: T) => void, n2: T) => void @@ -40,7 +40,7 @@ fn6({ x: null }, y => { }, { x: "" }); // y has type { x: any }, but ideally wou >fn6({ x: null }, y => { }, { x: "" }) : void >fn6 : (n: T, fun: (x: T) => void, n2: T) => void >{ x: null } : { x: null; } ->x : any +>x : null >y => { } : (y: { x: string; }) => void >y : { x: string; } >{ x: "" } : { x: string; } diff --git a/tests/baselines/reference/typeName1.errors.txt b/tests/baselines/reference/typeName1.errors.txt index 92b3279ab81..9c2b8c3797f 100644 --- a/tests/baselines/reference/typeName1.errors.txt +++ b/tests/baselines/reference/typeName1.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/compiler/typeName1.ts (16 errors) ==== +==== tests/cases/compiler/typeName1.ts (17 errors) ==== interface I { k; } @@ -55,6 +55,8 @@ ~~~ !!! Type 'number' is not assignable to type '{ z: I; x: boolean; y: (s: string) => boolean; w: { (): boolean; [x: string]: { x: any; y: any; }; [x: number]: { x: any; y: any; }; z: I; }; }[][]': !!! Property 'length' is missing in type 'Number'. + ~~~~ +!!! Property 'z' of type 'I' is not assignable to string index type '{ x: any; y: any; }'. var x13:{ new(): number; new(n:number):number; x: string; w: {y: number;}; (): {}; } = 3; ~~~ !!! Type 'number' is not assignable to type '{ (): {}; new (): number; new (n: number): number; x: string; w: { y: number; }; }': diff --git a/tests/baselines/reference/undefinedArgumentInference.types b/tests/baselines/reference/undefinedArgumentInference.types index e6c50461aeb..998a717b70a 100644 --- a/tests/baselines/reference/undefinedArgumentInference.types +++ b/tests/baselines/reference/undefinedArgumentInference.types @@ -19,8 +19,8 @@ var z1 = foo1({ x: undefined, y: undefined }); >foo1({ x: undefined, y: undefined }) : any >foo1 : (f1: { x: T; y: T; }) => T >{ x: undefined, y: undefined } : { x: undefined; y: undefined; } ->x : any +>x : undefined >undefined : undefined ->y : any +>y : undefined >undefined : undefined diff --git a/tests/baselines/reference/validMultipleVariableDeclarations.types b/tests/baselines/reference/validMultipleVariableDeclarations.types index 0e25906aac4..89d3702a702 100644 --- a/tests/baselines/reference/validMultipleVariableDeclarations.types +++ b/tests/baselines/reference/validMultipleVariableDeclarations.types @@ -47,7 +47,7 @@ var p: Point = { x: 0, y: undefined }; >Point : Point >{ x: 0, y: undefined } : { x: number; y: undefined; } >x : number ->y : any +>y : undefined >undefined : undefined var p = { x: 1, y: undefined }; @@ -73,7 +73,7 @@ var p = <{ x: number; y: number; }>{ x: 0, y: undefined }; >y : number >{ x: 0, y: undefined } : { x: number; y: undefined; } >x : number ->y : any +>y : undefined >undefined : undefined var p: typeof p; diff --git a/tests/baselines/reference/widenedTypes1.types b/tests/baselines/reference/widenedTypes1.types index 75cc5e3ede4..7d334054d18 100644 --- a/tests/baselines/reference/widenedTypes1.types +++ b/tests/baselines/reference/widenedTypes1.types @@ -9,13 +9,13 @@ var b = undefined; var c = {x: null}; >c : { x: any; } >{x: null} : { x: null; } ->x : any +>x : null var d = [{x: null}]; >d : { x: any; }[] >[{x: null}] : { x: null; }[] >{x: null} : { x: null; } ->x : any +>x : null var f = [null, null]; >f : any[] @@ -31,6 +31,6 @@ var h = [{x: undefined}]; >h : { x: any; }[] >[{x: undefined}] : { x: undefined; }[] >{x: undefined} : { x: undefined; } ->x : any +>x : undefined >undefined : undefined diff --git a/tests/cases/compiler/implicitAnyFromCircularInference.ts b/tests/cases/compiler/implicitAnyFromCircularInference.ts new file mode 100644 index 00000000000..a4c8b1ba78b --- /dev/null +++ b/tests/cases/compiler/implicitAnyFromCircularInference.ts @@ -0,0 +1,51 @@ +// @noimplicitany: true +// @target: es5 + +// Error expected +var a: typeof a; + +// Error expected on b or c +var b: typeof c; +var c: typeof b; + +// Error expected +var d: Array; + +function f() { return f; } + +// Error expected +function g() { return g(); } + +// Error expected +var f1 = function () { + return f1(); +}; + +// Error expected +var f2 = () => f2(); + +// Error expected +function h() { + return foo(); + function foo() { + return h() || "hello"; + } +} + +interface A { + s: string; +} + +function foo(x: A): string { return "abc"; } + +class C { + // Error expected + s = foo(this); +} + +class D { + // Error expected + get x() { + return this.x; + } +} diff --git a/tests/cases/compiler/tupleTypes.ts b/tests/cases/compiler/tupleTypes.ts new file mode 100644 index 00000000000..3b22c284cb1 --- /dev/null +++ b/tests/cases/compiler/tupleTypes.ts @@ -0,0 +1,53 @@ +var v1: []; // Error +var v2: [number]; +var v3: [number, string]; +var v4: [number, [string, string]]; + +var t: [number, string]; +var t0 = t[0]; // number +var t0: number; +var t1 = t[1]; // string +var t1: string; +var t2 = t[2]; // {} +var t2: {}; + +t = []; // Error +t = [1]; // Error +t = [1, "hello"]; // Ok +t = ["hello", 1]; // Error +t = [1, "hello", 2]; // Ok + +var tf: [string, (x: string) => number] = ["hello", x => x.length]; + +declare function ff(a: T, b: [T, (x: T) => U]): U; +var ff1 = ff("hello", ["foo", x => x.length]); +var ff1: number; + +function tuple2(item0: T0, item1: T1): [T0, T1]{ + return [item0, item1]; +} + +var tt = tuple2(1, "string"); +var tt0 = tt[0]; +var tt0: number; +var tt1 = tt[1]; +var tt1: string; +var tt2 = tt[2]; +var tt2: {}; + +tt = tuple2(1, undefined); +tt = [1, undefined]; +tt = [undefined, undefined]; +tt = []; // Error + +var a: number[]; +var a1: [number, string]; +var a2: [number, number]; +var a3: [number, {}]; +a = a1; // Error +a = a2; +a = a3; // Error +a1 = a2; // Error +a1 = a3; // Error +a3 = a1; +a3 = a2; diff --git a/tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts b/tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts new file mode 100644 index 00000000000..4b9f7a450ec --- /dev/null +++ b/tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: file1.ts +////this; this; + +// @Filename: file2.ts +////this; +////this; + +// @Filename: file3.ts +//// ((x = this, y) => t/**/his)(this, this); + +goTo.file("file1.ts"); +goTo.marker(); + +// TODO (drosen): The CURRENT behavior is that findAllRefs doesn't work on 'this' or 'super' keywords. +// This should change down the line. +verify.referencesCountIs(0); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index b4080d12e2f..e1b1e26c3c2 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -382,6 +382,14 @@ module FourSlashInterface { public completionEntryDetailIs(entryName: string, type: string, docComment?: string, fullSymbolName?: string, kind?: string) { FourSlash.currentTestState.verifyCompletionEntryDetails(entryName, type, docComment, fullSymbolName, kind); } + + public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { + FourSlash.currentTestState.verifySyntacticClassifications(classifications); + } + + public semanticClassificationsAre(...classifications: { classificationType: string; text: string }[]) { + FourSlash.currentTestState.verifySemanticClassifications(classifications); + } } export class edit { @@ -524,6 +532,64 @@ module FourSlashInterface { FourSlash.currentTestState.cancellationToken.setCancelled(numberOfCalls); } } + + export class classification { + public static comment(text: string): { classificationType: string; text: string } { + return { classificationType: "comment", text: text }; + } + + public static identifier(text: string): { classificationType: string; text: string } { + return { classificationType: "identifier", text: text }; + } + + public static keyword(text: string): { classificationType: string; text: string } { + return { classificationType: "keyword", text: text }; + } + + public static numericLiteral(text: string): { classificationType: string; text: string } { + return { classificationType: "numericLiteral", text: text }; + } + + public static operator(text: string): { classificationType: string; text: string } { + return { classificationType: "operator", text: text }; + } + + public static stringLiteral(text: string): { classificationType: string; text: string } { + return { classificationType: "stringLiteral", text: text }; + } + + public static whiteSpace(text: string): { classificationType: string; text: string } { + return { classificationType: "whiteSpace", text: text }; + } + + public static text(text: string): { classificationType: string; text: string } { + return { classificationType: "text", text: text }; + } + + public static punctuation(text: string): { classificationType: string; text: string } { + return { classificationType: "punctuation", text: text }; + } + + public static className(text: string): { classificationType: string; text: string } { + return { classificationType: "className", text: text }; + } + + public static enumName(text: string): { classificationType: string; text: string } { + return { classificationType: "enumName", text: text }; + } + + public static interfaceName(text: string): { classificationType: string; text: string } { + return { classificationType: "interfaceName", text: text }; + } + + public static moduleName(text: string): { classificationType: string; text: string } { + return { classificationType: "moduleName", text: text }; + } + + public static typeParameterName(text: string): { classificationType: string; text: string } { + return { classificationType: "typeParameterName", text: text }; + } + } } module fs { @@ -547,3 +613,4 @@ var debug = new FourSlashInterface.debug(); var format = new FourSlashInterface.format(); var diagnostics = new FourSlashInterface.diagnostics(); var cancellation = new FourSlashInterface.cancellation(); +var classification = FourSlashInterface.classification; diff --git a/tests/cases/fourslash/getOccurrencesConstructor.ts b/tests/cases/fourslash/getOccurrencesConstructor.ts new file mode 100644 index 00000000000..0a6b84a5770 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesConstructor.ts @@ -0,0 +1,32 @@ +/// + +////class C { +//// [|const/**/ructor|](); +//// [|constructor|](x: number); +//// [|constructor|](y: string, x: number); +//// [|constructor|](a?: any, ...r: any[]) { +//// if (a === undefined && r.length === 0) { +//// return; +//// } +//// +//// return; +//// } +////} +//// +////class D { +//// constructor(public x: number, public y: number) { +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesConstructor2.ts b/tests/cases/fourslash/getOccurrencesConstructor2.ts new file mode 100644 index 00000000000..049c25b7f52 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesConstructor2.ts @@ -0,0 +1,32 @@ +/// + +////class C { +//// constructor(); +//// constructor(x: number); +//// constructor(y: string, x: number); +//// constructor(a?: any, ...r: any[]) { +//// if (a === undefined && r.length === 0) { +//// return; +//// } +//// +//// return; +//// } +////} +//// +////class D { +//// [|con/**/structor|](public x: number, public y: number) { +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse.ts b/tests/cases/fourslash/getOccurrencesIfElse.ts new file mode 100644 index 00000000000..96c70d404ab --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse.ts @@ -0,0 +1,36 @@ +/// + +////[|if|] (true) { +//// if (false) { +//// } +//// else { +//// } +//// if (true) { +//// } +//// else { +//// if (false) +//// if (true) +//// var x = undefined; +//// } +////} +////[|else i/**/f|] (null) { +////} +////[|else|] /* whar garbl */ [|if|] (undefined) { +////} +////[|else|] +////[|if|] (false) { +////} +////[|else|] { } + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse2.ts b/tests/cases/fourslash/getOccurrencesIfElse2.ts new file mode 100644 index 00000000000..012e7a96efd --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse2.ts @@ -0,0 +1,32 @@ +/// + +////if (true) { +//// [|if|] (false) { +//// } +//// [|else|]{ +//// } +//// if (true) { +//// } +//// else { +//// if (false) +//// if (true) +//// var x = undefined; +//// } +////} +////else if (null) { +////} +////else /* whar garbl */ if (undefined) { +////} +////else +////if (false) { +////} +////else { } + + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse3.ts b/tests/cases/fourslash/getOccurrencesIfElse3.ts new file mode 100644 index 00000000000..b0ca3615648 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse3.ts @@ -0,0 +1,32 @@ +/// + +////if (true) { +//// if (false) { +//// } +//// else { +//// } +//// [|if|] (true) { +//// } +//// [|else|] { +//// if (false) +//// if (true) +//// var x = undefined; +//// } +////} +////else if (null) { +////} +////else /* whar garbl */ if (undefined) { +////} +////else +////if (false) { +////} +////else { } + + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse4.ts b/tests/cases/fourslash/getOccurrencesIfElse4.ts new file mode 100644 index 00000000000..66746252741 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse4.ts @@ -0,0 +1,30 @@ +/// + +////if (true) { +//// if (false) { +//// } +//// else { +//// } +//// if (true) { +//// } +//// else { +//// /*1*/if (false) +//// /*2*/i/*3*/f (true) +//// var x = undefined; +//// } +////} +////else if (null) { +////} +////else /* whar garbl */ if (undefined) { +////} +////else +////if (false) { +////} +////else { } + + +for (var i = 1; i <= test.markers().length; i++) { + goTo.marker("" + i); + + verify.occurrencesAtPositionCount(1); +} \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElseBroken.ts b/tests/cases/fourslash/getOccurrencesIfElseBroken.ts new file mode 100644 index 00000000000..a9e1e94f42d --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElseBroken.ts @@ -0,0 +1,24 @@ +/// + + +////[|if|] (true) { +//// var x = 1; +////} +////[|else if|] () +////[|else if|] +////[|else|] /* whar garbl */ [|if|] (i/**/f (true) { } else { }) +////else + +// It would be nice if in the future, +// We could include that last 'else'. + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +verify.occurrencesAtPositionCount(2); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts b/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts new file mode 100644 index 00000000000..601eba63c64 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts @@ -0,0 +1,29 @@ +/// + +////if/*1*/ (true) { +//// if/*2*/ (false) { +//// } +//// else/*3*/ { +//// } +//// if/*4*/ (true) { +//// } +//// else/*5*/ { +//// if/*6*/ (false) +//// if/*7*/ (true) +//// var x = undefined; +//// } +////} +////else/*8*/ if (null) { +////} +////else/*9*/ /* whar garbl */ if/*10*/ (undefined) { +////} +////else/*11*/ +////if/*12*/ (false) { +////} +////else/*13*/ { } + + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + verify.occurrencesAtPositionCount(0); +}); diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinue.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinue.ts new file mode 100644 index 00000000000..81aaaed5c58 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinue.ts @@ -0,0 +1,79 @@ +/// + +////var arr = [1, 2, 3, 4]; +////label1: [|for|] (var n in arr) { +//// [|break|]; +//// [|continue|]; +//// [|br/**/eak|] label1; +//// [|continue|] label1; +//// +//// label2: for (var i = 0; i < arr[n]; i++) { +//// [|break|] label1; +//// [|continue|] label1; +//// +//// break; +//// continue; +//// break label2; +//// continue label2; +//// +//// function foo() { +//// label3: while (true) { +//// break; +//// continue; +//// break label3; +//// continue label3; +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// +//// label4: do { +//// break; +//// continue; +//// break label4; +//// continue label4; +//// +//// break label3; +//// continue label3; +//// +//// switch (10) { +//// case 1: +//// case 2: +//// break; +//// break label4; +//// default: +//// continue; +//// } +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// () => { break; } +//// } while (true) +//// } +//// } +//// } +////} +//// +////label5: while (true) break label5; +//// +////label7: while (true) continue label5; + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +verify.occurrencesAtPositionCount(test.ranges().length); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinue2.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinue2.ts new file mode 100644 index 00000000000..51d4d89b657 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinue2.ts @@ -0,0 +1,79 @@ +/// + +////var arr = [1, 2, 3, 4]; +////label1: for (var n in arr) { +//// break; +//// continue; +//// break label1; +//// continue label1; +//// +//// label2: [|f/**/or|] (var i = 0; i < arr[n]; i++) { +//// break label1; +//// continue label1; +//// +//// [|break|]; +//// [|continue|]; +//// [|break|] label2; +//// [|continue|] label2; +//// +//// function foo() { +//// label3: while (true) { +//// break; +//// continue; +//// break label3; +//// continue label3; +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// +//// label4: do { +//// break; +//// continue; +//// break label4; +//// continue label4; +//// +//// break label3; +//// continue label3; +//// +//// switch (10) { +//// case 1: +//// case 2: +//// break; +//// break label4; +//// default: +//// continue; +//// } +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// () => { break; +//// } while (true) +//// } +//// } +//// } +////} +//// +////label5: while (true) break label5; +//// +////label7: while (true) continue label5; + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +verify.occurrencesAtPositionCount(test.ranges().length); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinue3.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinue3.ts new file mode 100644 index 00000000000..8777c912afd --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinue3.ts @@ -0,0 +1,78 @@ +/// + +////var arr = [1, 2, 3, 4]; +////label1: for (var n in arr) { +//// break; +//// continue; +//// break label1; +//// continue label1; +//// +//// label2: for (var i = 0; i < arr[n]; i++) { +//// break label1; +//// continue label1; +//// +//// break; +//// continue; +//// break label2; +//// continue label2; +//// +//// function foo() { +//// label3: [|w/**/hile|] (true) { +//// [|break|]; +//// [|continue|]; +//// [|break|] label3; +//// [|continue|] label3; +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// +//// label4: do { +//// break; +//// continue; +//// break label4; +//// continue label4; +//// +//// [|break|] label3; +//// [|continue|] label3; +//// +//// switch (10) { +//// case 1: +//// case 2: +//// break; +//// break label4; +//// default: +//// continue; +//// } +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// () => { break; } +//// } while (true) +//// } +//// } +//// } +////} +//// +////label5: while (true) break label5; +//// +////label7: while (true) continue label5; + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinue4.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinue4.ts new file mode 100644 index 00000000000..1bca62ba013 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinue4.ts @@ -0,0 +1,79 @@ +/// + +////var arr = [1, 2, 3, 4]; +////label1: for (var n in arr) { +//// break; +//// continue; +//// break label1; +//// continue label1; +//// +//// label2: for (var i = 0; i < arr[n]; i++) { +//// break label1; +//// continue label1; +//// +//// break; +//// continue; +//// break label2; +//// continue label2; +//// +//// function foo() { +//// label3: while (true) { +//// break; +//// continue; +//// break label3; +//// continue label3; +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// +//// label4: [|do|] { +//// [|break|]; +//// [|continue|]; +//// [|break|] label4; +//// [|continue|] label4; +//// +//// break label3; +//// continue label3; +//// +//// switch (10) { +//// case 1: +//// case 2: +//// break; +//// [|break|] label4; +//// default: +//// [|continue|]; +//// } +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// () => { break; } +//// } [|wh/**/ile|] (true) +//// } +//// } +//// } +////} +//// +////label5: while (true) break label5; +//// +////label7: while (true) continue label5; + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +verify.occurrencesAtPositionCount(test.ranges().length); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinue5.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinue5.ts new file mode 100644 index 00000000000..f4e62c554e4 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinue5.ts @@ -0,0 +1,79 @@ +/// + +////var arr = [1, 2, 3, 4]; +////label1: for (var n in arr) { +//// break; +//// continue; +//// break label1; +//// continue label1; +//// +//// label2: for (var i = 0; i < arr[n]; i++) { +//// break label1; +//// continue label1; +//// +//// break; +//// continue; +//// break label2; +//// continue label2; +//// +//// function foo() { +//// label3: while (true) { +//// break; +//// continue; +//// break label3; +//// continue label3; +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// +//// label4: do { +//// break; +//// continue; +//// break label4; +//// continue label4; +//// +//// break label3; +//// continue label3; +//// +//// switch (10) { +//// case 1: +//// case 2: +//// break; +//// break label4; +//// default: +//// continue; +//// } +//// +//// // these cross function boundaries +//// break label1; +//// continue label1; +//// break label2; +//// continue label2; +//// () => { break; } +//// } while (true) +//// } +//// } +//// } +////} +//// +////label5: [|while|] (true) [|br/**/eak|] label5; +//// +////label7: while (true) continue label5; + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +verify.occurrencesAtPositionCount(test.ranges().length); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinueNegatives.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinueNegatives.ts new file mode 100644 index 00000000000..0127245dd50 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinueNegatives.ts @@ -0,0 +1,70 @@ +/// + +////var arr = [1, 2, 3, 4]; +////label1: for (var n in arr) { +//// break; +//// continue; +//// break label1; +//// continue label1; +//// +//// label2: for (var i = 0; i < arr[n]; i++) { +//// break label1; +//// continue label1; +//// +//// break; +//// continue; +//// break label2; +//// continue label2; +//// +//// function foo() { +//// label3: while (true) { +//// break; +//// continue; +//// break label3; +//// continue label3; +//// +//// // these cross function boundaries +//// br/*1*/eak label1; +//// cont/*2*/inue label1; +//// bre/*3*/ak label2; +//// c/*4*/ontinue label2; +//// +//// label4: do { +//// break; +//// continue; +//// break label4; +//// continue label4; +//// +//// break label3; +//// continue label3; +//// +//// switch (10) { +//// case 1: +//// case 2: +//// break; +//// break label4; +//// default: +//// continue; +//// } +//// +//// // these cross function boundaries +//// br/*5*/eak label1; +//// co/*6*/ntinue label1; +//// br/*7*/eak label2; +//// con/*8*/tinue label2; +//// () => { b/*9*/reak; } +//// } while (true) +//// } +//// } +//// } +////} +//// +////label5: while (true) break label5; +//// +////label7: while (true) co/*10*/ntinue label5; + +test.markers().forEach(m => { + goTo.position(m.position); + + verify.occurrencesAtPositionCount(0); +}); diff --git a/tests/cases/fourslash/getOccurrencesReturn.ts b/tests/cases/fourslash/getOccurrencesReturn.ts new file mode 100644 index 00000000000..613e1645fb5 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturn.ts @@ -0,0 +1,33 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// [|ret/**/urn|] (function () { +//// return; +//// return; +//// return; +//// +//// if (false) { +//// return true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return 4 }) +//// +//// [|return|]; +//// [|return|] true; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturn2.ts b/tests/cases/fourslash/getOccurrencesReturn2.ts new file mode 100644 index 00000000000..15a062433fe --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturn2.ts @@ -0,0 +1,33 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// [|return|]; +//// [|ret/**/urn|]; +//// [|return|]; +//// +//// while (false) { +//// [|return|] true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return 4 }) +//// +//// return; +//// return true; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturn3.ts b/tests/cases/fourslash/getOccurrencesReturn3.ts new file mode 100644 index 00000000000..030d700ef6e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturn3.ts @@ -0,0 +1,28 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// return; +//// return; +//// return; +//// +//// if (false) { +//// return true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { [|return|] 4 }) +//// +//// return; +//// return true; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturnBroken.ts b/tests/cases/fourslash/getOccurrencesReturnBroken.ts new file mode 100644 index 00000000000..e740e7f2bb3 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturnBroken.ts @@ -0,0 +1,54 @@ +/// + +////ret/*1*/urn; +////retu/*2*/rn; +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// () => [|return|]; +//// [|return|]; +//// [|return|]; +//// +//// if (false) { +//// [|return|] true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return 4 }) +//// +//// return; +//// return true; +////} +//// +////class A { +//// ret/*3*/urn; +//// r/*4*/eturn 8675309; +////} + +// Note: For this test, these 'return's get highlighted as a result of a parse recovery +// where if an arrow function starts with a statement, we try to parse a body +// as if it was missing curly braces. If the behavior changes in the future, +// a change to this test is very much welcome. +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +for (var i = 1; i <= test.markers().length; i++) { + goTo.marker("" + i); + + switch (i) { + case 0: + case 1: + case 4: + verify.occurrencesAtPositionCount(0); + break; + case 3: + verify.occurrencesAtPositionCount(1); // 'return' is an instance member + break; + } +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturnNegatives.ts b/tests/cases/fourslash/getOccurrencesReturnNegatives.ts new file mode 100644 index 00000000000..79cb3c659c6 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturnNegatives.ts @@ -0,0 +1,25 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// return/*1*/; +//// return/*2*/; +//// return/*3*/; +//// +//// if (false) { +//// return/*4*/ true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return/*5*/ 4 }) +//// +//// return/*6*/; +//// return/*7*/ true; +////} + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + verify.occurrencesAtPositionCount(0); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesSuper.ts b/tests/cases/fourslash/getOccurrencesSuper.ts new file mode 100644 index 00000000000..f53d9aca62e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSuper.ts @@ -0,0 +1,64 @@ +/// + +////class SuperType { +//// superMethod() { +//// } +//// +//// static superStaticMethod() { +//// return 10; +//// } +////} +//// +////class SubType extends SuperType { +//// public prop1 = [|s/**/uper|].superMethod; +//// private prop2 = [|super|].superMethod; +//// +//// constructor() { +//// [|super|](); +//// } +//// +//// public method1() { +//// return [|super|].superMethod(); +//// } +//// +//// private method2() { +//// return [|super|].superMethod(); +//// } +//// +//// public method3() { +//// var x = () => [|super|].superMethod(); +//// +//// // Bad but still gets highlighted +//// function f() { +//// [|super|].superMethod(); +//// } +//// } +//// +//// // Bad but still gets highlighted. +//// public static statProp1 = super.superStaticMethod; +//// +//// public static staticMethod1() { +//// return super.superStaticMethod(); +//// } +//// +//// private static staticMethod2() { +//// return super.superStaticMethod(); +//// } +//// +//// // Are not actually 'super' keywords. +//// super = 10; +//// static super = 20; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesSuper2.ts b/tests/cases/fourslash/getOccurrencesSuper2.ts new file mode 100644 index 00000000000..1392170ae18 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSuper2.ts @@ -0,0 +1,64 @@ +/// + +////class SuperType { +//// superMethod() { +//// } +//// +//// static superStaticMethod() { +//// return 10; +//// } +////} +//// +////class SubType extends SuperType { +//// public prop1 = super.superMethod; +//// private prop2 = super.superMethod; +//// +//// constructor() { +//// super(); +//// } +//// +//// public method1() { +//// return super.superMethod(); +//// } +//// +//// private method2() { +//// return super.superMethod(); +//// } +//// +//// public method3() { +//// var x = () => super.superMethod(); +//// +//// // Bad but still gets highlighted +//// function f() { +//// super.superMethod(); +//// } +//// } +//// +//// // Bad but still gets highlighted. +//// public static statProp1 = [|super|].superStaticMethod; +//// +//// public static staticMethod1() { +//// return [|super|].superStaticMethod(); +//// } +//// +//// private static staticMethod2() { +//// return [|supe/**/r|].superStaticMethod(); +//// } +//// +//// // Are not actually 'super' keywords. +//// super = 10; +//// static super = 20; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesSuperNegatives.ts b/tests/cases/fourslash/getOccurrencesSuperNegatives.ts new file mode 100644 index 00000000000..8c76da33c12 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSuperNegatives.ts @@ -0,0 +1,27 @@ +/// + +////function f(x = [|super|]) { +//// [|super|]; +////} +//// +////module M { +//// [|super|]; +//// function f(x = [|super|]) { +//// [|super|]; +//// } +//// +//// class A { +//// } +//// +//// class B extends A { +//// constructor() { +//// super(); +//// } +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + verify.occurrencesAtPositionCount(0); +}); diff --git a/tests/cases/fourslash/getOccurrencesSwitchCaseDefault.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault.ts index a3d51e642d1..f32ff0e8f82 100644 --- a/tests/cases/fourslash/getOccurrencesSwitchCaseDefault.ts +++ b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault.ts @@ -1,10 +1,10 @@ /// -////[|sw/*1*/itch|] (10) { -//// [|/*2*/case|] 1: -//// [|cas/*3*/e|] 2: -//// [|c/*4*/ase|] 4: -//// [|c/*5*/ase|] 8: +////[|switch|] (10) { +//// [|case|] 1: +//// [|case|] 2: +//// [|case|] 4: +//// [|case|] 8: //// foo: switch (20) { //// case 1: //// case 2: @@ -12,18 +12,18 @@ //// default: //// break foo; //// } -//// [|cas/*6*/e|] 0xBEEF: -//// [|defa/*7*/ult|]: -//// [|bre/*9*/ak|]; -//// [|/*8*/case|] 16: +//// [|case|] 0xBEEF: +//// [|default|]: +//// [|break|]; +//// [|case|] 16: ////} -for (var i = 1; i <= test.markers().length; i++) { - goTo.marker("" + i); - verify.occurrencesAtPositionCount(9); +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); test.ranges().forEach(range => { verify.occurrencesAtPositionContains(range, false); }); -} +}); diff --git a/tests/cases/fourslash/getOccurrencesSwitchCaseDefault2.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault2.ts index a8c91f530ca..dd4577faa1f 100644 --- a/tests/cases/fourslash/getOccurrencesSwitchCaseDefault2.ts +++ b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault2.ts @@ -5,12 +5,12 @@ //// case 2: //// case 4: //// case 8: -//// foo: [|swi/*1*/tch|] (20) { -//// [|/*2*/case|] 1: -//// [|cas/*3*/e|] 2: -//// [|b/*4*/reak|]; -//// [|defaul/*5*/t|]: -//// break foo; +//// foo: [|switch|] (20) { +//// [|case|] 1: +//// [|case|] 2: +//// [|break|]; +//// [|default|]: +//// [|break|] foo; //// } //// case 0xBEEF: //// default: @@ -19,11 +19,11 @@ ////} -for (var i = 1; i <= test.markers().length; i++) { - goTo.marker("" + i); - verify.occurrencesAtPositionCount(5); +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); test.ranges().forEach(range => { verify.occurrencesAtPositionContains(range, false); }); -} +}); diff --git a/tests/cases/fourslash/getOccurrencesSwitchCaseDefault3.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault3.ts new file mode 100644 index 00000000000..24330ca1912 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault3.ts @@ -0,0 +1,26 @@ +/// + +////foo: [|switch|] (1) { +//// [|case|] 1: +//// [|case|] 2: +//// [|break|]; +//// [|case|] 3: +//// switch (2) { +//// case 1: +//// [|break|] foo; +//// continue; // invalid +//// default: +//// break; +//// } +//// [|default|]: +//// [|break|]; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); diff --git a/tests/cases/fourslash/getOccurrencesSwitchCaseDefault4.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault4.ts new file mode 100644 index 00000000000..039009746dd --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault4.ts @@ -0,0 +1,25 @@ +/// + +////foo: [|switch|] (10) { +//// [|case|] 1: +//// [|case|] 2: +//// [|case|] 3: +//// [|break|]; +//// [|break|] foo; +//// co/*1*/ntinue; +//// contin/*2*/ue foo; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + verify.occurrencesAtPositionCount(test.ranges().length); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +test.markers().forEach(m => { + goTo.position(m.position); + verify.occurrencesAtPositionCount(0); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis.ts b/tests/cases/fourslash/getOccurrencesThis.ts new file mode 100644 index 00000000000..e4b059b9cf9 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis.ts @@ -0,0 +1,154 @@ +/// + +////[|this|]; +////[|th/**/is|]; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis2.ts b/tests/cases/fourslash/getOccurrencesThis2.ts new file mode 100644 index 00000000000..3df30369e3e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis2.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|t/**/his|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis3.ts b/tests/cases/fourslash/getOccurrencesThis3.ts new file mode 100644 index 00000000000..7ee18a31286 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis3.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// [|t/**/his|]; +//// (function (_) { +//// this; +//// })([|this|]); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis4.ts b/tests/cases/fourslash/getOccurrencesThis4.ts new file mode 100644 index 00000000000..75a9383f88e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis4.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = [|this|].method1; +//// +//// public method1() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|this|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// [|this|]; +//// [|this|]; +//// () => [|t/**/his|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|this|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis5.ts b/tests/cases/fourslash/getOccurrencesThis5.ts new file mode 100644 index 00000000000..86ce16b16be --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis5.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = [|this|].staticMethod1; +//// +//// public static staticMethod1() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|this|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|t/**/his|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThisNegatives.ts b/tests/cases/fourslash/getOccurrencesThisNegatives.ts new file mode 100644 index 00000000000..95c676e0add --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThisNegatives.ts @@ -0,0 +1,149 @@ +/// + +////this/*1*/; +////this; +//// +////function f() { +//// this/*2*/; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// var x = th/*6*/is; +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this/*3*/; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this/*4*/; +//// }, +//// g() { +//// this/*5*/; +//// } +////} + + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + + verify.occurrencesAtPositionCount(0); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThisNegatives2.ts b/tests/cases/fourslash/getOccurrencesThisNegatives2.ts new file mode 100644 index 00000000000..65fb37d09b4 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThisNegatives2.ts @@ -0,0 +1,147 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.t/*1*/his; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this./*2*/this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.thi/*3*/s; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.t/*4*/his; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.th/*5*/is; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.th/*6*/is; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + verify.occurrencesAtPositionCount(1); +}); diff --git a/tests/cases/fourslash/semanticClassification1.ts b/tests/cases/fourslash/semanticClassification1.ts new file mode 100644 index 00000000000..0a0cc68250e --- /dev/null +++ b/tests/cases/fourslash/semanticClassification1.ts @@ -0,0 +1,12 @@ +/// + +//// module M { +//// export interface I { +//// } +//// } +//// interface X extends M.I { } + +debugger; +var c = classification; +verify.semanticClassificationsAre( + c.moduleName("M"), c.interfaceName("I"), c.interfaceName("X"), c.moduleName("M"), c.interfaceName("I")); diff --git a/tests/cases/fourslash/syntacticClassifications1.ts b/tests/cases/fourslash/syntacticClassifications1.ts new file mode 100644 index 00000000000..e70a4b672ff --- /dev/null +++ b/tests/cases/fourslash/syntacticClassifications1.ts @@ -0,0 +1,36 @@ +/// + +//// // comment +//// module M { +//// var v = 0 + 1; +//// var s = "string"; +//// +//// class C { +//// } +//// +//// enum E { +//// } +//// +//// interface I { +//// } +//// +//// module M1.M2 { +//// } +//// } + +debugger; +var c = classification; +verify.syntacticClassificationsAre( + c.comment("// comment"), + c.keyword("module"), c.moduleName("M"), c.punctuation("{"), + c.keyword("var"), c.text("v"), c.operator("="), c.numericLiteral("0"), c.operator("+"), c.numericLiteral("1"), c.punctuation(";"), + c.keyword("var"), c.text("s"), c.operator("="), c.stringLiteral('"string"'), c.punctuation(";"), + c.keyword("class"), c.className("C"), c.punctuation("<"), c.typeParameterName("T"), c.punctuation(">"), c.punctuation("{"), + c.punctuation("}"), + c.keyword("enum"), c.enumName("E"), c.punctuation("{"), + c.punctuation("}"), + c.keyword("interface"), c.interfaceName("I"), c.punctuation("{"), + c.punctuation("}"), + c.keyword("module"), c.moduleName("M1"), c.punctuation("."), c.moduleName("M2"), c.punctuation("{"), + c.punctuation("}"), + c.punctuation("}")); \ No newline at end of file diff --git a/tests/webTestServer.ts b/tests/webTestServer.ts index 05cf7a10f20..40e347fed50 100644 --- a/tests/webTestServer.ts +++ b/tests/webTestServer.ts @@ -227,11 +227,15 @@ function handleRequestOperation(req: http.ServerRequest, res: http.ServerRespons send('success', res, null); break; case RequestType.DeleteFile: - fs.unlinkSync(reqPath); + if (fs.existsSync(reqPath)) { + fs.unlinkSync(reqPath); + } send('success', res, null); break; case RequestType.DeleteDir: - fs.rmdirSync(reqPath); + if (fs.existsSync(reqPath)) { + fs.rmdirSync(reqPath); + } send('success', res, null); break; case RequestType.AppendFile: