diff --git a/Jakefile.js b/Jakefile.js index e304ce0e34a..0b294597574 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -126,6 +126,7 @@ var servicesSources = [ "classifier.ts", "completions.ts", "documentHighlights.ts", + "documentRegistry.ts", "findAllReferences.ts", "goToDefinition.ts", "jsDoc.ts", @@ -1003,15 +1004,18 @@ function acceptBaseline(containerFolder) { var deleteEnding = '.delete'; for (var i in files) { var filename = files[i]; - if (filename.substr(filename.length - deleteEnding.length) === deleteEnding) { - filename = filename.substr(0, filename.length - deleteEnding.length); - fs.unlinkSync(path.join(targetFolder, filename)); - } else { - var target = path.join(targetFolder, filename); - if (fs.existsSync(target)) { - fs.unlinkSync(target); + var fullLocalPath = path.join(sourceFolder, filename); + if (fs.statSync(fullLocalPath).isFile()) { + if (filename.substr(filename.length - deleteEnding.length) === deleteEnding) { + filename = filename.substr(0, filename.length - deleteEnding.length); + fs.unlinkSync(path.join(targetFolder, filename)); + } else { + var target = path.join(targetFolder, filename); + if (fs.existsSync(target)) { + fs.unlinkSync(target); + } + fs.renameSync(path.join(sourceFolder, filename), target); } - fs.renameSync(path.join(sourceFolder, filename), target); } } } diff --git a/lib/lib.es2015.collection.d.ts b/lib/lib.es2015.collection.d.ts index f014185d9e1..175f4f8725e 100644 --- a/lib/lib.es2015.collection.d.ts +++ b/lib/lib.es2015.collection.d.ts @@ -20,7 +20,7 @@ interface Map { forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void; get(key: K): V | undefined; has(key: K): boolean; - set(key: K, value?: V): this; + set(key: K, value: V): this; readonly size: number; } @@ -36,7 +36,7 @@ interface WeakMap { delete(key: K): boolean; get(key: K): V | undefined; has(key: K): boolean; - set(key: K, value?: V): this; + set(key: K, value: V): this; } interface WeakMapConstructor { diff --git a/scripts/tslint/preferConstRule.ts b/scripts/tslint/preferConstRule.ts index 60d771863be..9425d2b6079 100644 --- a/scripts/tslint/preferConstRule.ts +++ b/scripts/tslint/preferConstRule.ts @@ -93,11 +93,16 @@ class PreferConstWalker extends Lint.RuleWalker { private visitBindingPatternIdentifiers(pattern: ts.BindingPattern) { for (const element of pattern.elements) { - if (element.name.kind === ts.SyntaxKind.Identifier) { - this.markAssignment(element.name as ts.Identifier); + if (element.kind !== ts.SyntaxKind.BindingElement) { + continue; + } + + const name = (element).name; + if (name.kind === ts.SyntaxKind.Identifier) { + this.markAssignment(name as ts.Identifier); } else { - this.visitBindingPatternIdentifiers(element.name as ts.BindingPattern); + this.visitBindingPatternIdentifiers(name as ts.BindingPattern); } } } @@ -191,7 +196,9 @@ class PreferConstWalker extends Lint.RuleWalker { private collectBindingPatternIdentifiers(value: ts.VariableDeclaration, pattern: ts.BindingPattern, table: ts.MapLike) { for (const element of pattern.elements) { - this.collectNameIdentifiers(value, element.name, table); + if (element.kind === ts.SyntaxKind.BindingElement) { + this.collectNameIdentifiers(value, (element).name, table); + } } } } diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1e738718b18..3bccf6b4a9b 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1163,8 +1163,8 @@ namespace ts { currentFlow = finishFlowLabel(postExpressionLabel); } - function bindInitializedVariableFlow(node: VariableDeclaration | BindingElement) { - const name = node.name; + function bindInitializedVariableFlow(node: VariableDeclaration | ArrayBindingElement) { + const name = !isOmittedExpression(node) ? node.name : undefined; if (isBindingPattern(name)) { for (const child of name.elements) { bindInitializedVariableFlow(child); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8c8d4b8c256..4440eeaa3aa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1043,7 +1043,7 @@ namespace ts { const moduleSymbol = resolveExternalModuleName(node, (node.parent).moduleSpecifier); if (moduleSymbol) { - const exportDefaultSymbol = isShorthandAmbientModule(moduleSymbol.valueDeclaration) ? + const exportDefaultSymbol = isShorthandAmbientModuleSymbol(moduleSymbol) ? moduleSymbol : moduleSymbol.exports["export="] ? getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") : @@ -1119,7 +1119,7 @@ namespace ts { if (targetSymbol) { const name = specifier.propertyName || specifier.name; if (name.text) { - if (isShorthandAmbientModule(moduleSymbol.valueDeclaration)) { + if (isShorthandAmbientModuleSymbol(moduleSymbol)) { return moduleSymbol; } @@ -2505,8 +2505,8 @@ namespace ts { } } - function buildBindingElementDisplay(bindingElement: BindingElement, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { - if (bindingElement.kind === SyntaxKind.OmittedExpression) { + function buildBindingElementDisplay(bindingElement: ArrayBindingElement, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) { + if (isOmittedExpression(bindingElement)) { return; } Debug.assert(bindingElement.kind === SyntaxKind.BindingElement); @@ -3129,7 +3129,7 @@ namespace ts { } // Return the type implied by an object binding pattern - function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { + function getTypeFromObjectBindingPattern(pattern: ObjectBindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const members = createMap(); let hasComputedProperties = false; forEach(pattern.elements, e => { @@ -3160,11 +3160,12 @@ namespace ts { // Return the type implied by an array binding pattern function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean, reportErrors: boolean): Type { const elements = pattern.elements; - if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) { + const lastElement = lastOrUndefined(elements); + if (elements.length === 0 || (!isOmittedExpression(lastElement) && lastElement.dotDotDotToken)) { return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType; } // If the pattern has at least one element, and no rest element, then it should imply a tuple type. - const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); + const elementTypes = map(elements, e => isOmittedExpression(e) ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors)); let result = createTupleType(elementTypes); if (includePatternInType) { result = cloneTypeReference(result); @@ -3182,8 +3183,8 @@ namespace ts { // the parameter. function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean, reportErrors?: boolean): Type { return pattern.kind === SyntaxKind.ObjectBindingPattern - ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) - : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); + ? getTypeFromObjectBindingPattern(pattern, includePatternInType, reportErrors) + : getTypeFromArrayBindingPattern(pattern, includePatternInType, reportErrors); } // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type @@ -3385,7 +3386,7 @@ namespace ts { function getTypeOfFuncClassEnumModule(symbol: Symbol): Type { const links = getSymbolLinks(symbol); if (!links.type) { - if (symbol.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && isShorthandAmbientModule(symbol.valueDeclaration)) { + if (symbol.valueDeclaration.kind === SyntaxKind.ModuleDeclaration && isShorthandAmbientModuleSymbol(symbol)) { links.type = anyType; } else { @@ -8970,6 +8971,7 @@ namespace ts { const isParameter = getRootDeclaration(declaration).kind === SyntaxKind.Parameter; const declarationContainer = getControlFlowContainer(declaration); let flowContainer = getControlFlowContainer(node); + const isOuterVariable = flowContainer !== declarationContainer; // When the control flow originates in a function expression or arrow function and we are referencing // a const variable or parameter from an outer function, we extend the origin of the control flow // analysis to include the immediately enclosing function. @@ -8982,7 +8984,7 @@ namespace ts { // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). const assumeInitialized = !strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isParameter || - flowContainer !== declarationContainer || isInAmbientContext(declaration); + isOuterVariable || isInAmbientContext(declaration); const flowType = getFlowTypeOfReference(node, type, assumeInitialized, flowContainer); // A variable is considered uninitialized when it is possible to analyze the entire control flow graph // from declaration to use, and when the variable's declared type doesn't include undefined but the @@ -12437,7 +12439,7 @@ namespace ts { function assignBindingElementTypes(node: VariableLikeDeclaration) { if (isBindingPattern(node.name)) { for (const element of (node.name).elements) { - if (element.kind !== SyntaxKind.OmittedExpression) { + if (!isOmittedExpression(element)) { if (element.name.kind === SyntaxKind.Identifier) { getSymbolLinks(getSymbolOfNode(element)).type = getTypeForBindingElement(element); } @@ -13880,7 +13882,12 @@ namespace ts { pattern: BindingPattern, predicateVariableNode: Node, predicateVariableName: string) { - for (const { name } of pattern.elements) { + for (const element of pattern.elements) { + if (isOmittedExpression(element)) { + continue; + } + + const name = element.name; if (name.kind === SyntaxKind.Identifier && (name).text === predicateVariableName) { error(predicateVariableNode, @@ -18356,8 +18363,8 @@ namespace ts { function moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean { let moduleSymbol = resolveExternalModuleName(moduleReferenceExpression.parent, moduleReferenceExpression); - if (!moduleSymbol) { - // module not found - be conservative + if (!moduleSymbol || isShorthandAmbientModuleSymbol(moduleSymbol)) { + // If the module is not found or is shorthand, assume that it may export a value. return true; } @@ -19990,7 +19997,7 @@ namespace ts { else { const elements = (name).elements; for (const element of elements) { - if (element.kind !== SyntaxKind.OmittedExpression) { + if (!isOmittedExpression(element)) { checkGrammarNameInLetOrConstDeclarations(element.name); } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0f96b04df9a..51808592bd0 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -554,9 +554,9 @@ const _super = (function (geti, seti) { // Binding patterns case SyntaxKind.ObjectBindingPattern: - return emitObjectBindingPattern(node); + return emitObjectBindingPattern(node); case SyntaxKind.ArrayBindingPattern: - return emitArrayBindingPattern(node); + return emitArrayBindingPattern(node); case SyntaxKind.BindingElement: return emitBindingElement(node); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 1930481115c..16eeb86f59a 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -368,13 +368,13 @@ namespace ts { return node; } - export function createArrayBindingPattern(elements: BindingElement[], location?: TextRange) { + export function createArrayBindingPattern(elements: ArrayBindingElement[], location?: TextRange) { const node = createNode(SyntaxKind.ArrayBindingPattern, location); node.elements = createNodeArray(elements); return node; } - export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: BindingElement[]) { + export function updateArrayBindingPattern(node: ArrayBindingPattern, elements: ArrayBindingElement[]) { if (node.elements !== elements) { return updateNode(createArrayBindingPattern(elements, node), node); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e14a60eb10c..6e6b372b1c1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4815,9 +4815,9 @@ namespace ts { // DECLARATIONS - function parseArrayBindingElement(): BindingElement { + function parseArrayBindingElement(): ArrayBindingElement { if (token() === SyntaxKind.CommaToken) { - return createNode(SyntaxKind.OmittedExpression); + return createNode(SyntaxKind.OmittedExpression); } const node = createNode(SyntaxKind.BindingElement); node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); @@ -4842,16 +4842,16 @@ namespace ts { return finishNode(node); } - function parseObjectBindingPattern(): BindingPattern { - const node = createNode(SyntaxKind.ObjectBindingPattern); + function parseObjectBindingPattern(): ObjectBindingPattern { + const node = createNode(SyntaxKind.ObjectBindingPattern); parseExpected(SyntaxKind.OpenBraceToken); node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement); parseExpected(SyntaxKind.CloseBraceToken); return finishNode(node); } - function parseArrayBindingPattern(): BindingPattern { - const node = createNode(SyntaxKind.ArrayBindingPattern); + function parseArrayBindingPattern(): ArrayBindingPattern { + const node = createNode(SyntaxKind.ArrayBindingPattern); parseExpected(SyntaxKind.OpenBracketToken); node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement); parseExpected(SyntaxKind.CloseBracketToken); diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index e211ca61f36..c6079ee1378 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -326,12 +326,15 @@ namespace ts { } for (let i = 0; i < numElements; i++) { const element = elements[i]; - if (name.kind === SyntaxKind.ObjectBindingPattern) { + if (isOmittedExpression(element)) { + continue; + } + else if (name.kind === SyntaxKind.ObjectBindingPattern) { // Rewrite element to a declaration with an initializer that fetches property const propName = element.propertyName || element.name; emitBindingElement(element, createDestructuringPropertyAccess(value, propName)); } - else if (element.kind !== SyntaxKind.OmittedExpression) { + else { if (!element.dotDotDotToken) { // Rewrite element to a declaration that accesses array element at index i emitBindingElement(element, createElementAccess(value, i)); diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 4e994c1acb0..5f336da5460 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -1945,7 +1945,9 @@ namespace ts { } else { for (const element of (node).elements) { - visit(element.name); + if (!isOmittedExpression(element)) { + visit(element.name); + } } } } @@ -2289,7 +2291,9 @@ namespace ts { const name = decl.name; if (isBindingPattern(name)) { for (const element of name.elements) { - processLoopVariableDeclaration(element, loopParameters, loopOutParameters); + if (!isOmittedExpression(element)) { + processLoopVariableDeclaration(element, loopParameters, loopOutParameters); + } } } else { diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 144420b7ae9..61db452cf50 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -660,7 +660,9 @@ namespace ts { function addExportMemberAssignmentsForBindingName(resultStatements: Statement[], name: BindingName): void { if (isBindingPattern(name)) { for (const element of name.elements) { - addExportMemberAssignmentsForBindingName(resultStatements, element.name); + if (!isOmittedExpression(element)) { + addExportMemberAssignmentsForBindingName(resultStatements, element.name); + } } } else { diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index d303dd580ef..7b013e18e7d 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -1368,7 +1368,11 @@ namespace ts { exportedFunctionDeclarations.push(createDeclarationExport(node)); } - function hoistBindingElement(node: VariableDeclaration | BindingElement, isExported: boolean): void { + function hoistBindingElement(node: VariableDeclaration | ArrayBindingElement, isExported: boolean): void { + if (isOmittedExpression(node)) { + return; + } + const name = node.name; if (isIdentifier(name)) { hoistVariableDeclaration(getSynthesizedClone(name)); @@ -1381,11 +1385,11 @@ namespace ts { } } - function hoistExportedBindingElement(node: VariableDeclaration | BindingElement) { + function hoistExportedBindingElement(node: VariableDeclaration | ArrayBindingElement) { hoistBindingElement(node, /*isExported*/ true); } - function hoistNonExportedBindingElement(node: VariableDeclaration | BindingElement) { + function hoistNonExportedBindingElement(node: VariableDeclaration | ArrayBindingElement) { hoistBindingElement(node, /*isExported*/ false); } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index efb247ba663..e0765ed7025 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2187,7 +2187,7 @@ namespace ts { * * @param node The function expression node. */ - function visitFunctionExpression(node: FunctionExpression) { + function visitFunctionExpression(node: FunctionExpression): Expression { if (nodeIsMissing(node.body)) { return createOmittedExpression(); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 18404a48bd6..5a377efadf1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -688,14 +688,20 @@ namespace ts { } export interface BindingPattern extends Node { - elements: NodeArray; + elements: NodeArray; } // @kind(SyntaxKind.ObjectBindingPattern) - export interface ObjectBindingPattern extends BindingPattern { } + export interface ObjectBindingPattern extends BindingPattern { + elements: NodeArray; + } + + export type ArrayBindingElement = BindingElement | OmittedExpression; // @kind(SyntaxKind.ArrayBindingPattern) - export interface ArrayBindingPattern extends BindingPattern { } + export interface ArrayBindingPattern extends BindingPattern { + elements: NodeArray; + } /** * Several node kinds share function-like features such as a signature, @@ -868,7 +874,9 @@ namespace ts { } // @kind(SyntaxKind.OmittedExpression) - export interface OmittedExpression extends Expression { } + export interface OmittedExpression extends Expression { + _omittedExpressionBrand: any; + } // Represents an expression that is elided as part of a transformation to emit comments on a // not-emitted node. The 'expression' property of a NotEmittedExpression should be emitted. diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9ea74abbf76..6c948a8e6d9 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -414,7 +414,11 @@ namespace ts { ((node).name.kind === SyntaxKind.StringLiteral || isGlobalScopeAugmentation(node)); } - export function isShorthandAmbientModule(node: Node): boolean { + export function isShorthandAmbientModuleSymbol(moduleSymbol: Symbol): boolean { + return isShorthandAmbientModule(moduleSymbol.valueDeclaration); + } + + function isShorthandAmbientModule(node: Node): boolean { // The only kind of module that can be missing a body is a shorthand ambient module. return node.kind === SyntaxKind.ModuleDeclaration && (!(node).body); } @@ -3701,6 +3705,12 @@ namespace ts { return node.kind === SyntaxKind.BindingElement; } + export function isArrayBindingElement(node: Node): node is ArrayBindingElement { + const kind = node.kind; + return kind === SyntaxKind.BindingElement + || kind === SyntaxKind.OmittedExpression; + } + // Expression export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression { @@ -3817,6 +3827,10 @@ namespace ts { || isPartiallyEmittedExpression(node); } + export function isOmittedExpression(node: Node): node is OmittedExpression { + return node.kind === SyntaxKind.OmittedExpression; + } + // Misc export function isTemplateSpan(node: Node): node is TemplateSpan { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 648fd235c44..1e0cadaaa6b 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -757,7 +757,7 @@ namespace ts { case SyntaxKind.ArrayBindingPattern: return updateArrayBindingPattern(node, - visitNodes((node).elements, visitor, isBindingElement)); + visitNodes((node).elements, visitor, isArrayBindingElement)); case SyntaxKind.BindingElement: return updateBindingElement(node, diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 44ea0e83e0f..b727a2e2cb7 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -954,26 +954,20 @@ namespace FourSlash { assert.equal(actual, expected); } - public verifyQuickInfoString(negative: boolean, expectedText?: string, expectedDocumentation?: string) { + public verifyQuickInfoString(negative: boolean, expectedText: string, expectedDocumentation?: string) { const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); const actualQuickInfoText = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.displayParts) : ""; const actualQuickInfoDocumentation = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.documentation) : ""; if (negative) { - if (expectedText !== undefined) { - assert.notEqual(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text")); - } - // TODO: should be '==='? - if (expectedDocumentation != undefined) { + assert.notEqual(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text")); + if (expectedDocumentation !== undefined) { assert.notEqual(actualQuickInfoDocumentation, expectedDocumentation, this.messageAtLastKnownMarker("quick info doc comment")); } } else { - if (expectedText !== undefined) { - assert.equal(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text")); - } - // TODO: should be '==='? - if (expectedDocumentation != undefined) { + assert.equal(actualQuickInfoText, expectedText, this.messageAtLastKnownMarker("quick info text")); + if (expectedDocumentation !== undefined) { assert.equal(actualQuickInfoDocumentation, expectedDocumentation, this.assertionMessageAtLastKnownMarker("quick info doc")); } } @@ -2969,7 +2963,7 @@ namespace FourSlashInterface { this.state.verifyErrorExistsAfterMarker(markerName, !this.negative, /*after*/ false); } - public quickInfoIs(expectedText?: string, expectedDocumentation?: string) { + public quickInfoIs(expectedText: string, expectedDocumentation?: string) { this.state.verifyQuickInfoString(this.negative, expectedText, expectedDocumentation); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index b226fa7bb78..3518174cc2d 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -232,8 +232,8 @@ namespace Harness.LanguageService { } getHost() { return this.host; } getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); } - getClassifier(): ts.Classifier { return ts.Classifier.createClassifier(); } - getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.PreProcess.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); } + getClassifier(): ts.Classifier { return ts.createClassifier(); } + getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); } } /// Shim adapter @@ -258,7 +258,7 @@ namespace Harness.LanguageService { }; this.getModuleResolutionsForFile = (fileName) => { const scriptInfo = this.getScriptInfo(fileName); - const preprocessInfo = ts.PreProcess.preProcessFile(scriptInfo.content, /*readImportFiles*/ true); + const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true); const imports = ts.createMap(); for (const module of preprocessInfo.importedFiles) { const resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost); @@ -271,7 +271,7 @@ namespace Harness.LanguageService { this.getTypeReferenceDirectiveResolutionsForFile = (fileName) => { const scriptInfo = this.getScriptInfo(fileName); if (scriptInfo) { - const preprocessInfo = ts.PreProcess.preProcessFile(scriptInfo.content, /*readImportFiles*/ false); + const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false); const resolutions = ts.createMap(); const settings = this.nativeHost.getCompilationSettings(); for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) { @@ -408,6 +408,9 @@ namespace Harness.LanguageService { getCompletionEntryDetails(fileName: string, position: number, entryName: string): ts.CompletionEntryDetails { return unwrapJSONCallResult(this.shim.getCompletionEntryDetails(fileName, position, entryName)); } + getCompletionEntrySymbol(fileName: string, position: number, entryName: string): ts.Symbol { + throw new Error("getCompletionEntrySymbol not implemented across the shim layer."); + } getQuickInfoAtPosition(fileName: string, position: number): ts.QuickInfo { return unwrapJSONCallResult(this.shim.getQuickInfoAtPosition(fileName, position)); } diff --git a/src/harness/unittests/services/preProcessFile.ts b/src/harness/unittests/services/preProcessFile.ts index 6e181e7aef2..403cccc8cf3 100644 --- a/src/harness/unittests/services/preProcessFile.ts +++ b/src/harness/unittests/services/preProcessFile.ts @@ -2,7 +2,7 @@ describe("PreProcessFile:", function () { function test(sourceText: string, readImportFile: boolean, detectJavaScriptImports: boolean, expectedPreProcess: ts.PreProcessedFileInfo): void { - const resultPreProcess = ts.PreProcess.preProcessFile(sourceText, readImportFile, detectJavaScriptImports); + const resultPreProcess = ts.preProcessFile(sourceText, readImportFile, detectJavaScriptImports); assert.equal(resultPreProcess.isLibFile, expectedPreProcess.isLibFile, "Pre-processed file has different value for isLibFile. Expected: " + expectedPreProcess.isLibFile + ". Actual: " + resultPreProcess.isLibFile); diff --git a/src/server/client.ts b/src/server/client.ts index ca2d517701f..8391300d468 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -246,6 +246,10 @@ namespace ts.server { return response.body[0]; } + getCompletionEntrySymbol(fileName: string, position: number, entryName: string): Symbol { + throw new Error("Not Implemented Yet."); + } + getNavigateToItems(searchValue: string): NavigateToItem[] { const args: protocol.NavtoRequestArgs = { searchValue, diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 87e26ce2bf3..e0f9e8d5cf6 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1566,7 +1566,7 @@ namespace ts.server { this.setCompilerOptions(defaultOpts); } this.languageService = ts.createLanguageService(this.host, this.documentRegistry); - this.classifier = ts.Classifier.createClassifier(); + this.classifier = ts.createClassifier(); } setCompilerOptions(opt: ts.CompilerOptions) { diff --git a/src/services/classifier.ts b/src/services/classifier.ts index 56c31b08a60..0c19fbc74f9 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -1,5 +1,4 @@ -/* @internal */ -namespace ts.Classifier { +namespace ts { /// Classifier export function createClassifier(): Classifier { const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false); @@ -462,6 +461,7 @@ namespace ts.Classifier { }; } + /* @internal */ export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Map, span: TextSpan): ClassifiedSpan[] { return convertClassifications(getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span)); } @@ -486,6 +486,7 @@ namespace ts.Classifier { } } + /* @internal */ export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Map, span: TextSpan): Classifications { const result: number[] = []; processNode(sourceFile); @@ -614,10 +615,12 @@ namespace ts.Classifier { return result; } + /* @internal */ export function getSyntacticClassifications(cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { return convertClassifications(getEncodedSyntacticClassifications(cancellationToken, sourceFile, span)); } + /* @internal */ export function getEncodedSyntacticClassifications(cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { const spanStart = span.start; const spanLength = span.length; diff --git a/src/services/completions.ts b/src/services/completions.ts index d933c894344..121eaf83442 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -736,6 +736,22 @@ namespace ts.Completions { return undefined; } + export function getCompletionEntrySymbol(typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number, entryName: string): Symbol { + // Compute all the completion symbols again. + const completionData = getCompletionData(typeChecker, log, sourceFile, position); + if (completionData) { + const { symbols, location } = completionData; + + // Find the symbol with the matching entry name. + // We don't need to perform character checks here because we're only comparing the + // name against 'entryName' (which is known to be good), not building a new + // completion entry. + return forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined); + } + + return undefined; + } + function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) { const isJavaScriptFile = isSourceFileJavaScript(sourceFile); @@ -1192,7 +1208,7 @@ namespace ts.Completions { } if (canGetType) { typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); - existingMembers = (objectLikeContainer).elements; + existingMembers = (objectLikeContainer).elements; } } else { diff --git a/src/services/documentRegistry.ts b/src/services/documentRegistry.ts new file mode 100644 index 00000000000..d73e4d3b0a1 --- /dev/null +++ b/src/services/documentRegistry.ts @@ -0,0 +1,240 @@ +namespace ts { + /** + * The document registry represents a store of SourceFile objects that can be shared between + * multiple LanguageService instances. A LanguageService instance holds on the SourceFile (AST) + * of files in the context. + * SourceFile objects account for most of the memory usage by the language service. Sharing + * the same DocumentRegistry instance between different instances of LanguageService allow + * for more efficient memory utilization since all projects will share at least the library + * file (lib.d.ts). + * + * A more advanced use of the document registry is to serialize sourceFile objects to disk + * and re-hydrate them when needed. + * + * To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it + * to all subsequent createLanguageService calls. + */ + export interface DocumentRegistry { + /** + * Request a stored SourceFile with a given fileName and compilationSettings. + * The first call to acquire will call createLanguageServiceSourceFile to generate + * the SourceFile if was not found in the registry. + * + * @param fileName The name of the file requested + * @param compilationSettings Some compilation settings like target affects the + * shape of a the resulting SourceFile. This allows the DocumentRegistry to store + * multiple copies of the same file for different compilation settings. + * @parm scriptSnapshot Text of the file. Only used if the file was not found + * in the registry and a new one was created. + * @parm version Current version of the file. Only used if the file was not found + * in the registry and a new one was created. + */ + acquireDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind): SourceFile; + + acquireDocumentWithKey( + fileName: string, + path: Path, + compilationSettings: CompilerOptions, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind): SourceFile; + + /** + * Request an updated version of an already existing SourceFile with a given fileName + * and compilationSettings. The update will in-turn call updateLanguageServiceSourceFile + * to get an updated SourceFile. + * + * @param fileName The name of the file requested + * @param compilationSettings Some compilation settings like target affects the + * shape of a the resulting SourceFile. This allows the DocumentRegistry to store + * multiple copies of the same file for different compilation settings. + * @param scriptSnapshot Text of the file. + * @param version Current version of the file. + */ + updateDocument( + fileName: string, + compilationSettings: CompilerOptions, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind): SourceFile; + + updateDocumentWithKey( + fileName: string, + path: Path, + compilationSettings: CompilerOptions, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + scriptKind?: ScriptKind): SourceFile; + + getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey; + /** + * Informs the DocumentRegistry that a file is not needed any longer. + * + * Note: It is not allowed to call release on a SourceFile that was not acquired from + * this registry originally. + * + * @param fileName The name of the file to be released + * @param compilationSettings The compilation settings used to acquire the file + */ + releaseDocument(fileName: string, compilationSettings: CompilerOptions): void; + + releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey): void; + + reportStats(): string; + } + + export type DocumentRegistryBucketKey = string & { __bucketKey: any }; + + interface DocumentRegistryEntry { + sourceFile: SourceFile; + + // The number of language services that this source file is referenced in. When no more + // language services are referencing the file, then the file can be removed from the + // registry. + languageServiceRefCount: number; + owners: string[]; + } + + export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry { + // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have + // for those settings. + const buckets = createMap>(); + const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames); + + function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey { + return `_${settings.target}|${settings.module}|${settings.noResolve}|${settings.jsx}|${settings.allowJs}|${settings.baseUrl}|${JSON.stringify(settings.typeRoots)}|${JSON.stringify(settings.rootDirs)}|${JSON.stringify(settings.paths)}`; + } + + function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): FileMap { + let bucket = buckets[key]; + if (!bucket && createIfMissing) { + buckets[key] = bucket = createFileMap(); + } + return bucket; + } + + function reportStats() { + const bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === "_").map(name => { + const entries = buckets[name]; + const sourceFiles: { name: string; refCount: number; references: string[]; }[] = []; + entries.forEachValue((key, entry) => { + sourceFiles.push({ + name: key, + refCount: entry.languageServiceRefCount, + references: entry.owners.slice(0) + }); + }); + sourceFiles.sort((x, y) => y.refCount - x.refCount); + return { + bucket: name, + sourceFiles + }; + }); + return JSON.stringify(bucketInfoArray, undefined, 2); + } + + function acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { + const path = toPath(fileName, currentDirectory, getCanonicalFileName); + const key = getKeyForCompilationSettings(compilationSettings); + return acquireDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind); + } + + function acquireDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { + return acquireOrUpdateDocument(fileName, path, compilationSettings, key, scriptSnapshot, version, /*acquiring*/ true, scriptKind); + } + + function updateDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { + const path = toPath(fileName, currentDirectory, getCanonicalFileName); + const key = getKeyForCompilationSettings(compilationSettings); + return updateDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind); + } + + function updateDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { + return acquireOrUpdateDocument(fileName, path, compilationSettings, key, scriptSnapshot, version, /*acquiring*/ false, scriptKind); + } + + function acquireOrUpdateDocument( + fileName: string, + path: Path, + compilationSettings: CompilerOptions, + key: DocumentRegistryBucketKey, + scriptSnapshot: IScriptSnapshot, + version: string, + acquiring: boolean, + scriptKind?: ScriptKind): SourceFile { + + const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/ true); + let entry = bucket.get(path); + if (!entry) { + Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?"); + + // Have never seen this file with these settings. Create a new source file for it. + const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, compilationSettings.target, version, /*setNodeParents*/ false, scriptKind); + + entry = { + sourceFile: sourceFile, + languageServiceRefCount: 0, + owners: [] + }; + bucket.set(path, entry); + } + else { + // We have an entry for this file. However, it may be for a different version of + // the script snapshot. If so, update it appropriately. Otherwise, we can just + // return it as is. + if (entry.sourceFile.version !== version) { + entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, + scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot)); + } + } + + // If we're acquiring, then this is the first time this LS is asking for this document. + // Increase our ref count so we know there's another LS using the document. If we're + // not acquiring, then that means the LS is 'updating' the file instead, and that means + // it has already acquired the document previously. As such, we do not need to increase + // the ref count. + if (acquiring) { + entry.languageServiceRefCount++; + } + + return entry.sourceFile; + } + + function releaseDocument(fileName: string, compilationSettings: CompilerOptions): void { + const path = toPath(fileName, currentDirectory, getCanonicalFileName); + const key = getKeyForCompilationSettings(compilationSettings); + return releaseDocumentWithKey(path, key); + } + + function releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey): void { + const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/false); + Debug.assert(bucket !== undefined); + + const entry = bucket.get(path); + entry.languageServiceRefCount--; + + Debug.assert(entry.languageServiceRefCount >= 0); + if (entry.languageServiceRefCount === 0) { + bucket.remove(path); + } + } + + return { + acquireDocument, + acquireDocumentWithKey, + updateDocument, + updateDocumentWithKey, + releaseDocument, + releaseDocumentWithKey, + reportStats, + getKeyForCompilationSettings + }; + } +} diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index 8b3d42af328..0f0702066e1 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -1,5 +1,4 @@ -/* @internal */ -namespace ts.PreProcess { +namespace ts { export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo { const referencedFiles: FileReference[] = []; const typeReferenceDirectives: FileReference[] = []; diff --git a/src/services/services.ts b/src/services/services.ts index e0c08a670ca..bdc6fe62d5d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -7,6 +7,7 @@ /// /// /// +/// /// /// /// @@ -668,16 +669,6 @@ namespace ts { scriptKind: ScriptKind; } - interface DocumentRegistryEntry { - sourceFile: SourceFile; - - // The number of language services that this source file is referenced in. When no more - // language services are referencing the file, then the file can be removed from the - // registry. - languageServiceRefCount: number; - owners: string[]; - } - export interface DisplayPartsSymbolWriter extends SymbolWriter { displayParts(): SymbolDisplayPart[]; } @@ -899,142 +890,6 @@ namespace ts { return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, /*setNodeParents*/ true, sourceFile.scriptKind); } - export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry { - // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have - // for those settings. - const buckets = createMap>(); - const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames); - - function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey { - return `_${settings.target}|${settings.module}|${settings.noResolve}|${settings.jsx}|${settings.allowJs}|${settings.baseUrl}|${JSON.stringify(settings.typeRoots)}|${JSON.stringify(settings.rootDirs)}|${JSON.stringify(settings.paths)}`; - } - - function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): FileMap { - let bucket = buckets[key]; - if (!bucket && createIfMissing) { - buckets[key] = bucket = createFileMap(); - } - return bucket; - } - - function reportStats() { - const bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === "_").map(name => { - const entries = buckets[name]; - const sourceFiles: { name: string; refCount: number; references: string[]; }[] = []; - entries.forEachValue((key, entry) => { - sourceFiles.push({ - name: key, - refCount: entry.languageServiceRefCount, - references: entry.owners.slice(0) - }); - }); - sourceFiles.sort((x, y) => y.refCount - x.refCount); - return { - bucket: name, - sourceFiles - }; - }); - return JSON.stringify(bucketInfoArray, undefined, 2); - } - - function acquireDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const key = getKeyForCompilationSettings(compilationSettings); - return acquireDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind); - } - - function acquireDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { - return acquireOrUpdateDocument(fileName, path, compilationSettings, key, scriptSnapshot, version, /*acquiring*/ true, scriptKind); - } - - function updateDocument(fileName: string, compilationSettings: CompilerOptions, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const key = getKeyForCompilationSettings(compilationSettings); - return updateDocumentWithKey(fileName, path, compilationSettings, key, scriptSnapshot, version, scriptKind); - } - - function updateDocumentWithKey(fileName: string, path: Path, compilationSettings: CompilerOptions, key: DocumentRegistryBucketKey, scriptSnapshot: IScriptSnapshot, version: string, scriptKind?: ScriptKind): SourceFile { - return acquireOrUpdateDocument(fileName, path, compilationSettings, key, scriptSnapshot, version, /*acquiring*/ false, scriptKind); - } - - function acquireOrUpdateDocument( - fileName: string, - path: Path, - compilationSettings: CompilerOptions, - key: DocumentRegistryBucketKey, - scriptSnapshot: IScriptSnapshot, - version: string, - acquiring: boolean, - scriptKind?: ScriptKind): SourceFile { - - const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/ true); - let entry = bucket.get(path); - if (!entry) { - Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?"); - - // Have never seen this file with these settings. Create a new source file for it. - const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, compilationSettings.target, version, /*setNodeParents*/ false, scriptKind); - - entry = { - sourceFile: sourceFile, - languageServiceRefCount: 0, - owners: [] - }; - bucket.set(path, entry); - } - else { - // We have an entry for this file. However, it may be for a different version of - // the script snapshot. If so, update it appropriately. Otherwise, we can just - // return it as is. - if (entry.sourceFile.version !== version) { - entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, - scriptSnapshot.getChangeRange(entry.sourceFile.scriptSnapshot)); - } - } - - // If we're acquiring, then this is the first time this LS is asking for this document. - // Increase our ref count so we know there's another LS using the document. If we're - // not acquiring, then that means the LS is 'updating' the file instead, and that means - // it has already acquired the document previously. As such, we do not need to increase - // the ref count. - if (acquiring) { - entry.languageServiceRefCount++; - } - - return entry.sourceFile; - } - - function releaseDocument(fileName: string, compilationSettings: CompilerOptions): void { - const path = toPath(fileName, currentDirectory, getCanonicalFileName); - const key = getKeyForCompilationSettings(compilationSettings); - return releaseDocumentWithKey(path, key); - } - - function releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey): void { - const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/false); - Debug.assert(bucket !== undefined); - - const entry = bucket.get(path); - entry.languageServiceRefCount--; - - Debug.assert(entry.languageServiceRefCount >= 0); - if (entry.languageServiceRefCount === 0) { - bucket.remove(path); - } - } - - return { - acquireDocument, - acquireDocumentWithKey, - updateDocument, - updateDocumentWithKey, - releaseDocument, - releaseDocumentWithKey, - reportStats, - getKeyForCompilationSettings - }; - } - class CancellationTokenObject implements CancellationToken { constructor(private cancellationToken: HostCancellationToken) { } @@ -1351,6 +1206,11 @@ namespace ts { return Completions.getCompletionEntryDetails(program.getTypeChecker(), log, program.getCompilerOptions(), getValidSourceFile(fileName), position, entryName); } + function getCompletionEntrySymbol(fileName: string, position: number, entryName: string): Symbol { + synchronizeHostData(); + return Completions.getCompletionEntrySymbol(program.getTypeChecker(), log, program.getCompilerOptions(), getValidSourceFile(fileName), position, entryName); + } + function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo { synchronizeHostData(); @@ -1601,22 +1461,22 @@ namespace ts { function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { synchronizeHostData(); - return Classifier.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } function getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications { synchronizeHostData(); - return Classifier.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { // doesn't use compiler - no need to synchronize with host - return Classifier.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); + return ts.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); } function getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications { // doesn't use compiler - no need to synchronize with host - return Classifier.getEncodedSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); + return ts.getEncodedSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); } function getOutliningSpans(fileName: string): OutliningSpan[] { @@ -1913,6 +1773,7 @@ namespace ts { getEncodedSemanticClassifications, getCompletionsAtPosition, getCompletionEntryDetails, + getCompletionEntrySymbol, getSignatureHelpItems, getQuickInfoAtPosition, getDefinitionAtPosition, diff --git a/src/services/shims.ts b/src/services/shims.ts index 0c7a56199cc..41b366e0857 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -986,7 +986,7 @@ namespace ts { constructor(factory: ShimFactory, private logger: Logger) { super(factory); - this.classifier = Classifier.createClassifier(); + this.classifier = createClassifier(); } public getEncodedLexicalClassifications(text: string, lexState: EndOfLineState, syntacticClassifierAbsent?: boolean): string { @@ -1047,7 +1047,7 @@ namespace ts { `getPreProcessedFileInfo('${fileName}')`, () => { // for now treat files as JavaScript - const result = PreProcess.preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true); + const result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true); return { referencedFiles: this.convertFileReferences(result.referencedFiles), importedFiles: this.convertFileReferences(result.importedFiles), diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index d0d3c88fbcd..59fd0048c82 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -46,6 +46,7 @@ "classifier.ts", "completions.ts", "documentHighlights.ts", + "documentRegistry.ts", "findAllReferences.ts", "goToDefinition.ts", "jsDoc.ts", diff --git a/src/services/types.ts b/src/services/types.ts index b8c9122fb90..5b0635e706d 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -194,6 +194,7 @@ namespace ts { getCompletionsAtPosition(fileName: string, position: number): CompletionInfo; getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails; + getCompletionEntrySymbol(fileName: string, position: number, entryName: string): Symbol; getQuickInfoAtPosition(fileName: string, position: number): QuickInfo; @@ -575,99 +576,6 @@ namespace ts { getEncodedLexicalClassifications(text: string, endOfLineState: EndOfLineState, syntacticClassifierAbsent: boolean): Classifications; } - /** - * The document registry represents a store of SourceFile objects that can be shared between - * multiple LanguageService instances. A LanguageService instance holds on the SourceFile (AST) - * of files in the context. - * SourceFile objects account for most of the memory usage by the language service. Sharing - * the same DocumentRegistry instance between different instances of LanguageService allow - * for more efficient memory utilization since all projects will share at least the library - * file (lib.d.ts). - * - * A more advanced use of the document registry is to serialize sourceFile objects to disk - * and re-hydrate them when needed. - * - * To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it - * to all subsequent createLanguageService calls. - */ - export interface DocumentRegistry { - /** - * Request a stored SourceFile with a given fileName and compilationSettings. - * The first call to acquire will call createLanguageServiceSourceFile to generate - * the SourceFile if was not found in the registry. - * - * @param fileName The name of the file requested - * @param compilationSettings Some compilation settings like target affects the - * shape of a the resulting SourceFile. This allows the DocumentRegistry to store - * multiple copies of the same file for different compilation settings. - * @parm scriptSnapshot Text of the file. Only used if the file was not found - * in the registry and a new one was created. - * @parm version Current version of the file. Only used if the file was not found - * in the registry and a new one was created. - */ - acquireDocument( - fileName: string, - compilationSettings: CompilerOptions, - scriptSnapshot: IScriptSnapshot, - version: string, - scriptKind?: ScriptKind): SourceFile; - - acquireDocumentWithKey( - fileName: string, - path: Path, - compilationSettings: CompilerOptions, - key: DocumentRegistryBucketKey, - scriptSnapshot: IScriptSnapshot, - version: string, - scriptKind?: ScriptKind): SourceFile; - - /** - * Request an updated version of an already existing SourceFile with a given fileName - * and compilationSettings. The update will in-turn call updateLanguageServiceSourceFile - * to get an updated SourceFile. - * - * @param fileName The name of the file requested - * @param compilationSettings Some compilation settings like target affects the - * shape of a the resulting SourceFile. This allows the DocumentRegistry to store - * multiple copies of the same file for different compilation settings. - * @param scriptSnapshot Text of the file. - * @param version Current version of the file. - */ - updateDocument( - fileName: string, - compilationSettings: CompilerOptions, - scriptSnapshot: IScriptSnapshot, - version: string, - scriptKind?: ScriptKind): SourceFile; - - updateDocumentWithKey( - fileName: string, - path: Path, - compilationSettings: CompilerOptions, - key: DocumentRegistryBucketKey, - scriptSnapshot: IScriptSnapshot, - version: string, - scriptKind?: ScriptKind): SourceFile; - - getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey; - /** - * Informs the DocumentRegistry that a file is not needed any longer. - * - * Note: It is not allowed to call release on a SourceFile that was not acquired from - * this registry originally. - * - * @param fileName The name of the file to be released - * @param compilationSettings The compilation settings used to acquire the file - */ - releaseDocument(fileName: string, compilationSettings: CompilerOptions): void; - - releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey): void; - - reportStats(): string; - } - - export type DocumentRegistryBucketKey = string & { __bucketKey: any }; - // TODO: move these to enums export namespace ScriptElementKind { export const unknown = ""; diff --git a/tests/baselines/reference/ambientShorthand_reExport.js b/tests/baselines/reference/ambientShorthand_reExport.js index d0433e5d478..bdfc0ee0821 100644 --- a/tests/baselines/reference/ambientShorthand_reExport.js +++ b/tests/baselines/reference/ambientShorthand_reExport.js @@ -22,6 +22,10 @@ var jquery_1 = require("jquery"); exports.x = jquery_1.x; //// [reExportAll.js] "use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +__export(require("jquery")); //// [reExportUser.js] "use strict"; var reExportX_1 = require("./reExportX"); diff --git a/tests/baselines/reference/controlFlowOuterVariable.js b/tests/baselines/reference/controlFlowOuterVariable.js new file mode 100644 index 00000000000..1925d75eb31 --- /dev/null +++ b/tests/baselines/reference/controlFlowOuterVariable.js @@ -0,0 +1,26 @@ +//// [controlFlowOuterVariable.ts] + +// Repros from #10641 + +const CONFIG = { + foo: '', + setFoo: function(foo: string) { + CONFIG.foo = foo; + } +}; + +const helper = function(t: T[]) { + helper(t.slice(1)); +} + +//// [controlFlowOuterVariable.js] +// Repros from #10641 +var CONFIG = { + foo: '', + setFoo: function (foo) { + CONFIG.foo = foo; + } +}; +var helper = function (t) { + helper(t.slice(1)); +}; diff --git a/tests/baselines/reference/controlFlowOuterVariable.symbols b/tests/baselines/reference/controlFlowOuterVariable.symbols new file mode 100644 index 00000000000..35974f28a86 --- /dev/null +++ b/tests/baselines/reference/controlFlowOuterVariable.symbols @@ -0,0 +1,34 @@ +=== tests/cases/compiler/controlFlowOuterVariable.ts === + +// Repros from #10641 + +const CONFIG = { +>CONFIG : Symbol(CONFIG, Decl(controlFlowOuterVariable.ts, 3, 5)) + + foo: '', +>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 3, 16)) + + setFoo: function(foo: string) { +>setFoo : Symbol(setFoo, Decl(controlFlowOuterVariable.ts, 4, 12)) +>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 5, 21)) + + CONFIG.foo = foo; +>CONFIG.foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 3, 16)) +>CONFIG : Symbol(CONFIG, Decl(controlFlowOuterVariable.ts, 3, 5)) +>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 3, 16)) +>foo : Symbol(foo, Decl(controlFlowOuterVariable.ts, 5, 21)) + } +}; + +const helper = function(t: T[]) { +>helper : Symbol(helper, Decl(controlFlowOuterVariable.ts, 10, 5)) +>T : Symbol(T, Decl(controlFlowOuterVariable.ts, 10, 24)) +>t : Symbol(t, Decl(controlFlowOuterVariable.ts, 10, 27)) +>T : Symbol(T, Decl(controlFlowOuterVariable.ts, 10, 24)) + + helper(t.slice(1)); +>helper : Symbol(helper, Decl(controlFlowOuterVariable.ts, 10, 5)) +>t.slice : Symbol(Array.slice, Decl(lib.d.ts, --, --)) +>t : Symbol(t, Decl(controlFlowOuterVariable.ts, 10, 27)) +>slice : Symbol(Array.slice, Decl(lib.d.ts, --, --)) +} diff --git a/tests/baselines/reference/controlFlowOuterVariable.types b/tests/baselines/reference/controlFlowOuterVariable.types new file mode 100644 index 00000000000..602776dd54d --- /dev/null +++ b/tests/baselines/reference/controlFlowOuterVariable.types @@ -0,0 +1,42 @@ +=== tests/cases/compiler/controlFlowOuterVariable.ts === + +// Repros from #10641 + +const CONFIG = { +>CONFIG : { foo: string; setFoo: (foo: string) => void; } +>{ foo: '', setFoo: function(foo: string) { CONFIG.foo = foo; }} : { foo: string; setFoo: (foo: string) => void; } + + foo: '', +>foo : string +>'' : string + + setFoo: function(foo: string) { +>setFoo : (foo: string) => void +>function(foo: string) { CONFIG.foo = foo; } : (foo: string) => void +>foo : string + + CONFIG.foo = foo; +>CONFIG.foo = foo : string +>CONFIG.foo : string +>CONFIG : { foo: string; setFoo: (foo: string) => void; } +>foo : string +>foo : string + } +}; + +const helper = function(t: T[]) { +>helper : (t: T[]) => void +>function(t: T[]) { helper(t.slice(1));} : (t: T[]) => void +>T : T +>t : T[] +>T : T + + helper(t.slice(1)); +>helper(t.slice(1)) : void +>helper : (t: T[]) => void +>t.slice(1) : T[] +>t.slice : (start?: number | undefined, end?: number | undefined) => T[] +>t : T[] +>slice : (start?: number | undefined, end?: number | undefined) => T[] +>1 : number +} diff --git a/tests/baselines/reference/exportArrayBindingPattern.js b/tests/baselines/reference/exportArrayBindingPattern.js new file mode 100644 index 00000000000..386419e5725 --- /dev/null +++ b/tests/baselines/reference/exportArrayBindingPattern.js @@ -0,0 +1,11 @@ +//// [exportArrayBindingPattern.ts] +// issue: https://github.com/Microsoft/TypeScript/issues/10778 +const [a, , b] = [1, 2, 3]; +export { a, b }; + +//// [exportArrayBindingPattern.js] +"use strict"; +// issue: https://github.com/Microsoft/TypeScript/issues/10778 +var _a = [1, 2, 3], a = _a[0], b = _a[2]; +exports.a = a; +exports.b = b; diff --git a/tests/baselines/reference/exportArrayBindingPattern.symbols b/tests/baselines/reference/exportArrayBindingPattern.symbols new file mode 100644 index 00000000000..96fb5cabc88 --- /dev/null +++ b/tests/baselines/reference/exportArrayBindingPattern.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/exportArrayBindingPattern.ts === +// issue: https://github.com/Microsoft/TypeScript/issues/10778 +const [a, , b] = [1, 2, 3]; +>a : Symbol(a, Decl(exportArrayBindingPattern.ts, 1, 7)) +>b : Symbol(b, Decl(exportArrayBindingPattern.ts, 1, 11)) + +export { a, b }; +>a : Symbol(a, Decl(exportArrayBindingPattern.ts, 2, 8)) +>b : Symbol(b, Decl(exportArrayBindingPattern.ts, 2, 11)) + diff --git a/tests/baselines/reference/exportArrayBindingPattern.types b/tests/baselines/reference/exportArrayBindingPattern.types new file mode 100644 index 00000000000..bfc1e461dd5 --- /dev/null +++ b/tests/baselines/reference/exportArrayBindingPattern.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/exportArrayBindingPattern.ts === +// issue: https://github.com/Microsoft/TypeScript/issues/10778 +const [a, , b] = [1, 2, 3]; +>a : number +> : undefined +>b : number +>[1, 2, 3] : [number, number, number] +>1 : number +>2 : number +>3 : number + +export { a, b }; +>a : number +>b : number + diff --git a/tests/cases/compiler/controlFlowOuterVariable.ts b/tests/cases/compiler/controlFlowOuterVariable.ts new file mode 100644 index 00000000000..3a33f3b25e0 --- /dev/null +++ b/tests/cases/compiler/controlFlowOuterVariable.ts @@ -0,0 +1,14 @@ +// @strictNullChecks: true + +// Repros from #10641 + +const CONFIG = { + foo: '', + setFoo: function(foo: string) { + CONFIG.foo = foo; + } +}; + +const helper = function(t: T[]) { + helper(t.slice(1)); +} \ No newline at end of file diff --git a/tests/cases/compiler/exportArrayBindingPattern.ts b/tests/cases/compiler/exportArrayBindingPattern.ts new file mode 100644 index 00000000000..e161962efe8 --- /dev/null +++ b/tests/cases/compiler/exportArrayBindingPattern.ts @@ -0,0 +1,4 @@ +// @module: commonjs +// issue: https://github.com/Microsoft/TypeScript/issues/10778 +const [a, , b] = [1, 2, 3]; +export { a, b }; \ No newline at end of file diff --git a/tests/cases/fourslash/commentsLinePreservation.ts b/tests/cases/fourslash/commentsLinePreservation.ts index 012272d7544..623f870c37c 100644 --- a/tests/cases/fourslash/commentsLinePreservation.ts +++ b/tests/cases/fourslash/commentsLinePreservation.ts @@ -107,55 +107,55 @@ ////function /*l*/l(param1: string) { /*9*/param1 = "hello"; } goTo.marker('a'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n\nThis is fourth Line"); +verify.quickInfoIs("var a: string", "This is firstLine\nThis is second Line\n\nThis is fourth Line"); goTo.marker('b'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n\nThis is fourth Line"); +verify.quickInfoIs("var b: string", "This is firstLine\nThis is second Line\n\nThis is fourth Line"); goTo.marker('c'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n\nThis is fourth Line"); +verify.quickInfoIs("var c: string", "This is firstLine\nThis is second Line\n\nThis is fourth Line"); goTo.marker('d'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n@random tag This should be third line"); +verify.quickInfoIs("function d(param: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"); goTo.marker('1'); -verify.quickInfoIs(undefined, ""); +verify.quickInfoIs("(parameter) param: string", ""); goTo.marker('e'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line"); +verify.quickInfoIs("function e(param: string): void", "This is firstLine\nThis is second Line"); goTo.marker('2'); -verify.quickInfoIs(undefined, ""); +verify.quickInfoIs("(parameter) param: string", ""); goTo.marker('f'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n@random tag This should be third line"); +verify.quickInfoIs("function f(param1: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"); goTo.marker('3'); -verify.quickInfoIs(undefined, "first line of param\n\nparam information third line"); +verify.quickInfoIs("(parameter) param1: string", "first line of param\n\nparam information third line"); goTo.marker('g'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n@random tag This should be third line"); +verify.quickInfoIs("function g(param1: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"); goTo.marker('4'); -verify.quickInfoIs(undefined, "param information first line"); +verify.quickInfoIs("(parameter) param1: string", "param information first line"); goTo.marker('h'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n@random tag This should be third line"); +verify.quickInfoIs("function h(param1: string): void", "This is firstLine\nThis is second Line\n@random tag This should be third line"); goTo.marker('5'); -verify.quickInfoIs(undefined, "param information first line\n\nparam information third line"); +verify.quickInfoIs("(parameter) param1: string", "param information first line\n\nparam information third line"); goTo.marker('i'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line"); +verify.quickInfoIs("function i(param1: string): void", "This is firstLine\nThis is second Line"); goTo.marker('6'); -verify.quickInfoIs(undefined, "param information first line\n\nparam information third line"); +verify.quickInfoIs("(parameter) param1: string", "param information first line\n\nparam information third line"); goTo.marker('j'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line"); +verify.quickInfoIs("function j(param1: string): void", "This is firstLine\nThis is second Line"); goTo.marker('7'); -verify.quickInfoIs(undefined, "param information first line\n\nparam information third line"); +verify.quickInfoIs("(parameter) param1: string", "param information first line\n\nparam information third line"); goTo.marker('k'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line\n@randomtag \n\n random information first line\n\n random information third line"); +verify.quickInfoIs("function k(param1: string): void", "This is firstLine\nThis is second Line\n@randomtag \n\n random information first line\n\n random information third line"); goTo.marker('8'); -verify.quickInfoIs(undefined, "hello "); +verify.quickInfoIs("(parameter) param1: string", "hello "); goTo.marker('l'); -verify.quickInfoIs(undefined, "This is firstLine\nThis is second Line"); +verify.quickInfoIs("function l(param1: string): void", "This is firstLine\nThis is second Line"); goTo.marker('9'); -verify.quickInfoIs(undefined, "first Line text\nblank line that shouldnt be shown when starting this \nsecond time information about the param again"); +verify.quickInfoIs("(parameter) param1: string", "first Line text\nblank line that shouldnt be shown when starting this \nsecond time information about the param again"); diff --git a/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts b/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts index ff21d10aae8..040ba08e5a7 100644 --- a/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts +++ b/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts @@ -10,13 +10,13 @@ ////var max2: Comparer = (x/*1*/x, y/*2*/y) => { return x/*3*/x.compareTo(y/*4*/y) }; goTo.marker('1'); -verify.quickInfoIs('(parameter) xx: any', null); +verify.quickInfoIs('(parameter) xx: any'); goTo.marker('2'); -verify.quickInfoIs('(parameter) yy: any', null); +verify.quickInfoIs('(parameter) yy: any'); goTo.marker('3'); -verify.quickInfoIs('(parameter) xx: any', null); +verify.quickInfoIs('(parameter) xx: any'); goTo.marker('4'); -verify.quickInfoIs('(parameter) yy: any', null); +verify.quickInfoIs('(parameter) yy: any'); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index caa800a6203..a8216de8145 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -130,7 +130,7 @@ declare namespace FourSlashInterface { errorExistsBetweenMarkers(startMarker: string, endMarker: string): void; errorExistsAfterMarker(markerName?: string): void; errorExistsBeforeMarker(markerName?: string): void; - quickInfoIs(expectedText?: string, expectedDocumentation?: string): void; + quickInfoIs(expectedText: string, expectedDocumentation?: string): void; quickInfoExists(): void; typeDefinitionCountIs(expectedCount: number): void; isValidBraceCompletionAtPosition(openingBrace?: string): void; diff --git a/tests/cases/fourslash/genericFunctionWithGenericParams1.ts b/tests/cases/fourslash/genericFunctionWithGenericParams1.ts index e57da708412..5cee2ffa813 100644 --- a/tests/cases/fourslash/genericFunctionWithGenericParams1.ts +++ b/tests/cases/fourslash/genericFunctionWithGenericParams1.ts @@ -6,4 +6,4 @@ ////}; goTo.marker(); -verify.quickInfoIs('(local var) xx: T', null); +verify.quickInfoIs('(local var) xx: T'); diff --git a/tests/cases/fourslash/genericInterfacesWithConstraints1.ts b/tests/cases/fourslash/genericInterfacesWithConstraints1.ts index e800eb06346..48e23cf8eb1 100644 --- a/tests/cases/fourslash/genericInterfacesWithConstraints1.ts +++ b/tests/cases/fourslash/genericInterfacesWithConstraints1.ts @@ -12,8 +12,8 @@ ////var v/*3*/3: G, C>; // Ok goTo.marker('1'); -verify.quickInfoIs('var v1: G', null); +verify.quickInfoIs('var v1: G'); goTo.marker('2'); -verify.quickInfoIs('var v2: G<{\n a: string;\n}, C>', null); +verify.quickInfoIs('var v2: G<{\n a: string;\n}, C>'); goTo.marker('3'); -verify.quickInfoIs('var v3: G, C>', null); +verify.quickInfoIs('var v3: G, C>'); diff --git a/tests/cases/fourslash/genericTypeParamUnrelatedToArguments1.ts b/tests/cases/fourslash/genericTypeParamUnrelatedToArguments1.ts index e4a679a4b22..ab6ffc0a192 100644 --- a/tests/cases/fourslash/genericTypeParamUnrelatedToArguments1.ts +++ b/tests/cases/fourslash/genericTypeParamUnrelatedToArguments1.ts @@ -11,19 +11,19 @@ ////var f/*6*/6: Foo = new Foo(3); goTo.marker('1'); -verify.quickInfoIs('var f1: Foo', null); +verify.quickInfoIs('var f1: Foo'); goTo.marker('2'); -verify.quickInfoIs('var f2: Foo', null); +verify.quickInfoIs('var f2: Foo'); goTo.marker('3'); -verify.quickInfoIs('var f3: any', null); +verify.quickInfoIs('var f3: any'); goTo.marker('4'); -verify.quickInfoIs('var f4: Foo', null); +verify.quickInfoIs('var f4: Foo'); goTo.marker('5'); -verify.quickInfoIs('var f5: any', null); +verify.quickInfoIs('var f5: any'); goTo.marker('6'); -verify.quickInfoIs('var f6: Foo', null); +verify.quickInfoIs('var f6: Foo'); diff --git a/tests/cases/fourslash/quickInfoOnGenericClass.ts b/tests/cases/fourslash/quickInfoOnGenericClass.ts index d05a509973c..4ffb3c7febf 100644 --- a/tests/cases/fourslash/quickInfoOnGenericClass.ts +++ b/tests/cases/fourslash/quickInfoOnGenericClass.ts @@ -5,4 +5,4 @@ ////} goTo.marker(); -verify.quickInfoIs('class Container', null); \ No newline at end of file +verify.quickInfoIs('class Container'); \ No newline at end of file diff --git a/tests/cases/fourslash/quickInfoOnGenericWithConstraints1.ts b/tests/cases/fourslash/quickInfoOnGenericWithConstraints1.ts index 2f4fe31fdcf..9a6dbd36162 100644 --- a/tests/cases/fourslash/quickInfoOnGenericWithConstraints1.ts +++ b/tests/cases/fourslash/quickInfoOnGenericWithConstraints1.ts @@ -3,7 +3,7 @@ ////interface Fo/*1*/o {} goTo.marker('1'); -verify.quickInfoIs('interface Foo', null); +verify.quickInfoIs('interface Foo'); goTo.marker('2'); -verify.quickInfoIs('(type parameter) TT in Foo', null); +verify.quickInfoIs('(type parameter) TT in Foo'); diff --git a/tests/cases/fourslash/recursiveObjectLiteral.ts b/tests/cases/fourslash/recursiveObjectLiteral.ts index a1d15d0d9a4..04cdb3ffe9b 100644 --- a/tests/cases/fourslash/recursiveObjectLiteral.ts +++ b/tests/cases/fourslash/recursiveObjectLiteral.ts @@ -3,4 +3,4 @@ ////var a = { f: /**/a goTo.marker(); -verify.quickInfoIs("var a: any", null); +verify.quickInfoIs("var a: any");