From 1d3a728e26eec67a1580f4ec2c8534a76cf228d4 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 1 Jun 2020 15:58:08 -0400 Subject: [PATCH 01/19] Initial import of the vscode semantic highlight code --- src/harness/client.ts | 2 +- src/harness/fourslashImpl.ts | 10 +- src/harness/fourslashInterfaceImpl.ts | 102 ++++++-- src/harness/harnessLanguageService.ts | 9 +- src/services/classifierVscode.ts | 246 ++++++++++++++++++ src/services/services.ts | 20 +- src/services/shims.ts | 4 +- src/services/tsconfig.json | 1 + src/services/types.ts | 21 +- tests/cases/fourslash/fourslash.ts | 64 ++--- .../fourslash/semanticClassification1.ts | 23 +- .../fourslash/semanticClassification2.ts | 2 +- .../fourslash/semanticClassificationAlias.ts | 2 +- .../semanticClassificationClassExpression.ts | 4 +- ...nticClassificationInTemplateExpressions.ts | 2 +- ...stantiatedModuleWithVariableOfSameName1.ts | 2 +- ...stantiatedModuleWithVariableOfSameName2.ts | 2 +- .../fourslash/semanticClassificationJs.ts | 2 +- .../semanticClassificationModules.ts | 4 +- ...stantiatedModuleWithVariableOfSameName1.ts | 4 +- ...stantiatedModuleWithVariableOfSameName2.ts | 2 +- .../semanticClassificationWithUnionTypes.ts | 4 +- .../semanticClassificationsCancellation1.ts | 4 +- .../semanticClassificatonTypeAlias.ts | 4 +- .../shims-pp/getSemanticClassifications.ts | 2 +- .../shims/getSemanticClassifications.ts | 2 +- 26 files changed, 443 insertions(+), 101 deletions(-) create mode 100644 src/services/classifierVscode.ts diff --git a/src/harness/client.ts b/src/harness/client.ts index bd8a1b256ff51..888edbf4483b4 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -747,7 +747,7 @@ namespace ts.server { return notImplemented(); } - getEncodedSemanticClassifications(_fileName: string, _span: TextSpan): Classifications { + getEncodedSemanticClassifications(_fileName: string, _span: TextSpan, _format?: "original" | "2020"): Classifications { return notImplemented(); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index f012c7830c647..5559ffab2e7e3 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2448,7 +2448,9 @@ namespace FourSlash { Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos)!, "**")); } - private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) { + private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) { + console.log("expected:", expected); + console.log("actual:", actual); if (actual.length !== expected.length) { this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length + ", but was " + actual.length + @@ -2511,9 +2513,9 @@ namespace FourSlash { } } - public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) { + public verifySemanticClassifications(format: "original" | "2020", expected: { classificationType: string | number; text?: string }[]) { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, - ts.createTextSpan(0, this.activeFile.content.length)); + ts.createTextSpan(0, this.activeFile.content.length), format); this.verifyClassifications(expected, actual, this.activeFile.content); } @@ -3766,7 +3768,7 @@ namespace FourSlash { const cancellation = new FourSlashInterface.Cancellation(state); // eslint-disable-next-line no-eval const f = eval(wrappedCode); - f(test, goTo, plugins, verify, edit, debug, format, cancellation, FourSlashInterface.Classification, FourSlashInterface.Completion, verifyOperationIsCancelled); + f(test, goTo, plugins, verify, edit, debug, format, cancellation, FourSlashInterface.classification, FourSlashInterface.Completion, verifyOperationIsCancelled); } catch (err) { // ensure 'source-map-support' is triggered while we still have the handler attached by accessing `error.stack`. diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index dcbd07b4dbf09..360d6c85716a7 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -504,8 +504,8 @@ namespace FourSlashInterface { /** * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. */ - public semanticClassificationsAre(...classifications: Classification[]) { - this.state.verifySemanticClassifications(classifications); + public semanticClassificationsAre(format: "original" | "2020", ...classifications: Classification[]) { + this.state.verifySemanticClassifications(format, classifications); } public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range, options?: ts.RenameInfoOptions) { @@ -749,100 +749,118 @@ namespace FourSlashInterface { } interface Classification { - classificationType: ts.ClassificationTypeNames; - text: string; + classificationType: ts.ClassificationTypeNames | number; + text?: string; textSpan?: FourSlash.TextSpan; } - export namespace Classification { - export function comment(text: string, position?: number): Classification { + + export function classification(format: "original" | "2020") { + function token(identifier: number, text: string, _position: number): Classification { + return { + classificationType: identifier, + // textSpan: { + // start: position, + // end: -1 + // }, + text + } + } + + if (format === "2020") { + return { + token + } + } + + function comment(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.comment, text, position); } - export function identifier(text: string, position?: number): Classification { + function identifier(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.identifier, text, position); } - export function keyword(text: string, position?: number): Classification { + function keyword(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.keyword, text, position); } - export function numericLiteral(text: string, position?: number): Classification { + function numericLiteral(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.numericLiteral, text, position); } - export function operator(text: string, position?: number): Classification { + function operator(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.operator, text, position); } - export function stringLiteral(text: string, position?: number): Classification { + function stringLiteral(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.stringLiteral, text, position); } - export function whiteSpace(text: string, position?: number): Classification { + function whiteSpace(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.whiteSpace, text, position); } - export function text(text: string, position?: number): Classification { + function text(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.text, text, position); } - export function punctuation(text: string, position?: number): Classification { + function punctuation(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.punctuation, text, position); } - export function docCommentTagName(text: string, position?: number): Classification { + function docCommentTagName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.docCommentTagName, text, position); } - export function className(text: string, position?: number): Classification { + function className(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.className, text, position); } - export function enumName(text: string, position?: number): Classification { + function enumName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.enumName, text, position); } - export function interfaceName(text: string, position?: number): Classification { + function interfaceName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.interfaceName, text, position); } - export function moduleName(text: string, position?: number): Classification { + function moduleName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.moduleName, text, position); } - export function typeParameterName(text: string, position?: number): Classification { + function typeParameterName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.typeParameterName, text, position); } - export function parameterName(text: string, position?: number): Classification { + function parameterName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.parameterName, text, position); } - export function typeAliasName(text: string, position?: number): Classification { + function typeAliasName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.typeAliasName, text, position); } - export function jsxOpenTagName(text: string, position?: number): Classification { + function jsxOpenTagName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.jsxOpenTagName, text, position); } - export function jsxCloseTagName(text: string, position?: number): Classification { + function jsxCloseTagName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.jsxCloseTagName, text, position); } - export function jsxSelfClosingTagName(text: string, position?: number): Classification { + function jsxSelfClosingTagName(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.jsxSelfClosingTagName, text, position); } - export function jsxAttribute(text: string, position?: number): Classification { + function jsxAttribute(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.jsxAttribute, text, position); } - export function jsxText(text: string, position?: number): Classification { + function jsxText(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.jsxText, text, position); } - export function jsxAttributeStringLiteralValue(text: string, position?: number): Classification { + function jsxAttributeStringLiteralValue(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.jsxAttributeStringLiteralValue, text, position); } @@ -850,7 +868,35 @@ namespace FourSlashInterface { const textSpan = position === undefined ? undefined : { start: position, end: position + text.length }; return { classificationType, text, textSpan }; } + + return { + comment, + identifier, + keyword, + numericLiteral, + operator, + stringLiteral, + whiteSpace, + text, + punctuation, + docCommentTagName, + className, + enumName, + interfaceName, + moduleName, + typeParameterName, + parameterName, + typeAliasName, + jsxOpenTagName, + jsxCloseTagName, + jsxSelfClosingTagName, + jsxAttribute, + jsxText, + jsxAttributeStringLiteralValue, + getClassification + } } + export namespace Completion { export import SortText = ts.Completions.SortText; export import CompletionSource = ts.Completions.CompletionSource; diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index bc3c738a6b8c6..24128e58779c5 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -448,14 +448,15 @@ namespace Harness.LanguageService { getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length)); } - getSemanticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { - return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length)); + getSemanticClassifications(fileName: string, span: ts.TextSpan, format?: "original" | "2020"): ts.ClassifiedSpan[] { + return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length, format)); } getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications { return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length)); } - getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications { - return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length)); + getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan, format?: "original" | "2020"): ts.Classifications { + const responseFormat = format || "original"; + return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length, responseFormat)); } getCompletionsAtPosition(fileName: string, position: number, preferences: ts.UserPreferences | undefined): ts.CompletionInfo { return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position, preferences)); diff --git a/src/services/classifierVscode.ts b/src/services/classifierVscode.ts new file mode 100644 index 0000000000000..4660960f15e81 --- /dev/null +++ b/src/services/classifierVscode.ts @@ -0,0 +1,246 @@ +namespace ts.classifier.vscode { + + enum TokenType { + class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ + } + + enum TokenModifier { + declaration, static, async, readonly, defaultLibrary, local, _ + } + + enum TokenEncodingConsts { + typeOffset = 8, + modifierMask = (1 << typeOffset) - 1 + } + + /** This is mainly used internally for testing */ + export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { + const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span) + + Debug.assert(classifications.spans.length % 3 === 0); + const dense = classifications.spans; + const result: ClassifiedSpan[] = []; + for (let i = 0; i < dense.length; i += 3) { + result.push({ + textSpan: createTextSpan(dense[i], dense[i + 1]), + classificationType: dense[i + 2] as any // getClassificationTypeName(dense[i + 2]) + }); + } + + return result; + } + + export function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { + return { + spans: getSemanticTokens(program, sourceFile, span), + endOfLineState: ts.EndOfLineState.None + } + } + + function getSemanticTokens(program: Program, sourceFile:SourceFile, span: TextSpan): number[] { + let resultTokens: number[] = []; + + const collector = (node: Node, typeIdx: number, modifierSet: number) => { + resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); + }; + + if (program && sourceFile) { + collectTokens(program, sourceFile, span, collector); + } + return resultTokens; + } + + function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void) { + const typeChecker = program.getTypeChecker(); + + let inJSXElement = false; + + function visit(node: Node) { + if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { + return; + } + const prevInJSXElement = inJSXElement; + if (isJsxElement(node) || isJsxSelfClosingElement(node)) { + inJSXElement = true; + } + if (isJsxExpression(node)) { + inJSXElement = false; + } + + if (isIdentifier(node) && !inJSXElement && !inImportClause(node)) { + let symbol = typeChecker.getSymbolAtLocation(node); + if (symbol) { + if (symbol.flags & SymbolFlags.Alias) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + let typeIdx = classifySymbol(symbol, getMeaningFromLocation(node)); + if (typeIdx !== undefined) { + let modifierSet = 0; + if (node.parent) { + const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); + if (parentIsDeclaration && (node.parent).name === node) { + modifierSet = 1 << TokenModifier.declaration; + } + } + + // property declaration in constructor + if (typeIdx === TokenType.parameter && isRightSideOfQualifiedNameOrPropertyAccess(node)) { + typeIdx = TokenType.property; + } + + typeIdx = reclassifyByType(typeChecker, node, typeIdx); + + const decl = symbol.valueDeclaration; + if (decl) { + const modifiers = getCombinedModifierFlags(decl); + const nodeFlags = getCombinedNodeFlags(decl); + if (modifiers & ModifierFlags.Static) { + modifierSet |= 1 << TokenModifier.static; + } + if (modifiers & ModifierFlags.Async) { + modifierSet |= 1 << TokenModifier.async; + } + if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { + if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { + modifierSet |= 1 << TokenModifier.readonly; + } + } + if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { + modifierSet |= 1 << TokenModifier.local; + } + if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + } else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + + collector(node, typeIdx, modifierSet); + + } + } + } + forEachChild(node, visit); + + inJSXElement = prevInJSXElement; + } + visit(sourceFile); + } + + function classifySymbol(symbol: Symbol, meaning: SemanticMeaning): TokenType | undefined { + const flags = symbol.getFlags(); + if (flags & SymbolFlags.Class) { + return TokenType.class; + } else if (flags & SymbolFlags.Enum) { + return TokenType.enum; + } else if (flags & SymbolFlags.TypeAlias) { + return TokenType.type; + } else if (flags & SymbolFlags.Interface) { + if (meaning & SemanticMeaning.Type) { + return TokenType.interface; + } + } else if (flags & SymbolFlags.TypeParameter) { + return TokenType.typeParameter; + } + let decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; + if (decl && isBindingElement(decl)) { + decl = getDeclarationForBindingElement(decl); + } + return decl && tokenFromDeclarationMapping[decl.kind]; + } + + function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenType): TokenType { + // type based classifications + if (typeIdx === TokenType.variable || typeIdx === TokenType.property || typeIdx === TokenType.parameter) { + const type = typeChecker.getTypeAtLocation(node); + if (type) { + const test = (condition: (type: Type) => boolean) => { + return condition(type) || type.isUnion() && type.types.some(condition); + } + if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { + return TokenType.class; + } + if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { + return typeIdx === TokenType.property ? TokenType.member : TokenType.function; + } + } + } + return typeIdx; + } + + function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean { + if (isBindingElement(decl)) { + decl = getDeclarationForBindingElement(decl); + } + if (isVariableDeclaration(decl)) { + return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; + } else if (isFunctionDeclaration(decl)) { + return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; + } + return false; + } + + function getDeclarationForBindingElement(element: BindingElement): VariableDeclaration | ParameterDeclaration { + while (true) { + if (isBindingElement(element.parent.parent)) { + element = element.parent.parent; + } else { + return element.parent.parent; + } + } + } + + function inImportClause(node: Node): boolean { + const parent = node.parent; + return parent && (isImportClause(parent) || isImportSpecifier(parent) || isNamespaceImport(parent)); + } + + function isExpressionInCallExpression(node: Node): boolean { + while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { + node = node.parent + } + return isCallExpression(node.parent) && node.parent.expression === node; + } + + function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { + return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); + } + + const enum SemanticMeaning { + None = 0x0, + Value = 0x1, + Type = 0x2, + Namespace = 0x4, + All = Value | Type | Namespace + } + + function getMeaningFromLocation(node: Node): SemanticMeaning { + const f = (ts).getMeaningFromLocation; + if (typeof f === 'function') { + return f(node); + } + return SemanticMeaning.All; + } + + const tokenFromDeclarationMapping: { [name: string]: TokenType } = { + [SyntaxKind.VariableDeclaration]: TokenType.variable, + [SyntaxKind.Parameter]: TokenType.parameter, + [SyntaxKind.PropertyDeclaration]: TokenType.property, + [SyntaxKind.ModuleDeclaration]: TokenType.namespace, + [SyntaxKind.EnumDeclaration]: TokenType.enum, + [SyntaxKind.EnumMember]: TokenType.enumMember, + [SyntaxKind.ClassDeclaration]: TokenType.class, + [SyntaxKind.MethodDeclaration]: TokenType.member, + [SyntaxKind.FunctionDeclaration]: TokenType.function, + [SyntaxKind.FunctionExpression]: TokenType.function, + [SyntaxKind.MethodSignature]: TokenType.member, + [SyntaxKind.GetAccessor]: TokenType.property, + [SyntaxKind.SetAccessor]: TokenType.property, + [SyntaxKind.PropertySignature]: TokenType.property, + [SyntaxKind.InterfaceDeclaration]: TokenType.interface, + [SyntaxKind.TypeAliasDeclaration]: TokenType.type, + [SyntaxKind.TypeParameter]: TokenType.typeParameter, + [SyntaxKind.PropertyAssignment]: TokenType.property, + [SyntaxKind.ShorthandPropertyAssignment]: TokenType.property + }; +} diff --git a/src/services/services.ts b/src/services/services.ts index dba765680197f..38dac6f137034 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1797,22 +1797,34 @@ namespace ts { return kind === ScriptKind.TS || kind === ScriptKind.TSX; } - function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { + function getSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): ClassifiedSpan[] { if (!isTsOrTsxFile(fileName)) { // do not run semantic classification on non-ts-or-tsx files return []; } synchronizeHostData(); - return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + + const responseFormat = format || "original" + if (responseFormat === "original") { + return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + } else { + return ts.classifier.vscode.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + } } - function getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications { + function getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): Classifications { if (!isTsOrTsxFile(fileName)) { // do not run semantic classification on non-ts-or-tsx files return { spans: [], endOfLineState: EndOfLineState.None }; } synchronizeHostData(); - return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + + const responseFormat = format || "original" + if (responseFormat === "original") { + return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + } else { + return ts.classifier.vscode.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + } } function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { diff --git a/src/services/shims.ts b/src/services/shims.ts index c8149620b8c6e..3714bbf21e427 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -145,9 +145,9 @@ namespace ts { getCompilerOptionsDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; - getSemanticClassifications(fileName: string, start: number, length: number): string; + getSemanticClassifications(fileName: string, start: number, length: number, format?: "original" | "2020"): string; getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string; - getEncodedSemanticClassifications(fileName: string, start: number, length: number): string; + getEncodedSemanticClassifications(fileName: string, start: number, length: number, format?: "original" | "2020"): string; getCompletionsAtPosition(fileName: string, position: number, preferences: UserPreferences | undefined): string; getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: string/*Services.FormatCodeOptions*/ | undefined, source: string | undefined, preferences: UserPreferences | undefined): string; diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index e1aab52f187f1..ded83472433dc 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -12,6 +12,7 @@ "types.ts", "utilities.ts", "classifier.ts", + "classifierVscode.ts", "stringCompletions.ts", "completions.ts", "documentHighlights.ts", diff --git a/src/services/types.ts b/src/services/types.ts index 5ccf5f49d4a89..02b11fa06e6b4 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -375,14 +375,23 @@ namespace ts { getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): ClassifiedSpan[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; - - // Encoded as triples of [start, length, ClassificationType]. + getSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): ClassifiedSpan[]; + /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; - getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications; + + /** + * Gets semantic highlights information for a particular file. Has two formats, an older + * version used by VS and a format used by VS Code. + * + * @param fileName The path to the file + * @param position A text span to return results within + * @param format Which format to use, defaults to "original" + * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. + */ + getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): Classifications; /** * Gets completion entries at a particular position in a file. @@ -589,7 +598,7 @@ namespace ts { export interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames; + classificationType: ClassificationTypeNames | number; } /** diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index a2be4e57a2e0a..633f8586fa570 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -348,14 +348,14 @@ declare namespace FourSlashInterface { */ syntacticClassificationsAre(...classifications: { classificationType: string; - text: string; + text?: string; }[]): void; /** * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. */ - semanticClassificationsAre(...classifications: { - classificationType: string; - text: string; + semanticClassificationsAre(format: "original" | "2020", ...classifications: { + classificationType: string | number; + text?: string; textSpan?: TextSpan; }[]): void; renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, range?: Range, allowRenameOfImportPath?: boolean): void; @@ -454,118 +454,123 @@ declare namespace FourSlashInterface { resetCancelled(): void; setCancelled(numberOfCalls?: number): void; } - module classification { - function comment(text: string, position?: number): { + + interface ModernClassificationFactory { + token(identifier: number, name: string, position: number) + } + + interface ClassificationFactory { + comment(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function identifier(text: string, position?: number): { + identifier(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function keyword(text: string, position?: number): { + keyword(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function numericLiteral(text: string, position?: number): { + numericLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function operator(text: string, position?: number): { + operator(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function stringLiteral(text: string, position?: number): { + stringLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function whiteSpace(text: string, position?: number): { + whiteSpace(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function text(text: string, position?: number): { + text(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function punctuation(text: string, position?: number): { + punctuation(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function docCommentTagName(text: string, position?: number): { + docCommentTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function className(text: string, position?: number): { + className(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function enumName(text: string, position?: number): { + enumName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function interfaceName(text: string, position?: number): { + interfaceName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function moduleName(text: string, position?: number): { + moduleName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function typeParameterName(text: string, position?: number): { + typeParameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function parameterName(text: string, position?: number): { + parameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function typeAliasName(text: string, position?: number): { + typeAliasName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function jsxOpenTagName(text: string, position?: number): { + jsxOpenTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function jsxCloseTagName(text: string, position?: number): { + jsxCloseTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function jsxSelfClosingTagName(text: string, position?: number): { + jsxSelfClosingTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function jsxAttribute(text: string, position?: number): { + jsxAttribute(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function jsxText(text: string, position?: number): { + jsxText(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; }; - function jsxAttributeStringLiteralValue(text: string, position?: number): { + jsxAttributeStringLiteralValue(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan; @@ -749,7 +754,8 @@ declare var edit: FourSlashInterface.edit; declare var debug: FourSlashInterface.debug; declare var format: FourSlashInterface.format; declare var cancellation: FourSlashInterface.cancellation; -declare var classification: typeof FourSlashInterface.classification; +declare function classification(format: "original"): FourSlashInterface.ClassificationFactory; +declare function classification(format: "2020"): FourSlashInterface.ModernClassificationFactory; declare namespace completion { type Entry = FourSlashInterface.ExpectedCompletionEntryObject; export const enum SortText { diff --git a/tests/cases/fourslash/semanticClassification1.ts b/tests/cases/fourslash/semanticClassification1.ts index 4eb7f2a32edab..9fa7a7e284c7a 100644 --- a/tests/cases/fourslash/semanticClassification1.ts +++ b/tests/cases/fourslash/semanticClassification1.ts @@ -6,10 +6,29 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification; -verify.semanticClassificationsAre( +var c = classification("original"); +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.interfaceName("X", test.marker("2").position), c.moduleName("M", test.marker("3").position), c.interfaceName("I", test.marker("4").position)); + + // // TODO: test like: + // // c2.token("module", "M", test.marker("0").position)) + +var c2 = classification("2020") +verify.semanticClassificationsAre("2020", + c2.token(1025, "M", test.marker("0").position), + c2.token(769, "I", test.marker("1").position), + c2.token(769, "X", test.marker("2").position), + c2.token(1024, "M", test.marker("3").position), + c2.token(768, "I", test.marker("4").position), +) +// { textSpan: { start: 7, end: 1 }, classificationType: 1025 }, +// { textSpan: { start: 32, end: 1 }, classificationType: 769 }, +// { textSpan: { start: 54, end: 1 }, classificationType: 769 }, +// { textSpan: { start: 64, end: 1 }, classificationType: 1024 }, +// { textSpan: { start: 66, end: 1 }, classificationType: 768 } ); + + diff --git a/tests/cases/fourslash/semanticClassification2.ts b/tests/cases/fourslash/semanticClassification2.ts index f7f6340e5bd6c..84cdb8fc766ed 100644 --- a/tests/cases/fourslash/semanticClassification2.ts +++ b/tests/cases/fourslash/semanticClassification2.ts @@ -8,4 +8,4 @@ //// Thing.toExponential(); var c = classification; -verify.semanticClassificationsAre(c.interfaceName("Thing", test.marker("0").position)); \ No newline at end of file +verify.semanticClassificationsAre("original", c.interfaceName("Thing", test.marker("0").position)); diff --git a/tests/cases/fourslash/semanticClassificationAlias.ts b/tests/cases/fourslash/semanticClassificationAlias.ts index 799674a211dae..7e34940cc00ca 100644 --- a/tests/cases/fourslash/semanticClassificationAlias.ts +++ b/tests/cases/fourslash/semanticClassificationAlias.ts @@ -12,7 +12,7 @@ goTo.file("/b.ts"); const [m0, m1, m2, m3] = test.markers(); const c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.typeAliasName("x", m0.position), c.className("y", m1.position), c.typeAliasName("x", m2.position), diff --git a/tests/cases/fourslash/semanticClassificationClassExpression.ts b/tests/cases/fourslash/semanticClassificationClassExpression.ts index f067265df2994..98da5a8418d3e 100644 --- a/tests/cases/fourslash/semanticClassificationClassExpression.ts +++ b/tests/cases/fourslash/semanticClassificationClassExpression.ts @@ -4,9 +4,9 @@ //// class /*1*/C {} //// class /*2*/D extends class /*3*/B{} { } var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.className("C", test.marker("0").position), c.className("C", test.marker("1").position), c.className("D", test.marker("2").position), c.className("B", test.marker("3").position) -); \ No newline at end of file +); diff --git a/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts b/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts index 7ac8bec28207f..15f822de0a82d 100644 --- a/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts +++ b/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts @@ -11,7 +11,7 @@ ////`abcd${ /*3*/M./*4*/C.x + /*5*/M./*6*/E.E1}efg` var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.className("C", test.marker("1").position), c.enumName("E", test.marker("2").position), diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts index 2061c218eac7a..cfb43136fe859 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts @@ -16,7 +16,7 @@ ////var x = /*5*/M; var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.moduleName("M", test.marker("3").position), diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts index f1f4fa8e67014..4b1745479a19a 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts @@ -19,7 +19,7 @@ ////var x = /*6*/M; var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.moduleName("M", test.marker("2").position), diff --git a/tests/cases/fourslash/semanticClassificationJs.ts b/tests/cases/fourslash/semanticClassificationJs.ts index 8105202a23fed..4232c962012f7 100644 --- a/tests/cases/fourslash/semanticClassificationJs.ts +++ b/tests/cases/fourslash/semanticClassificationJs.ts @@ -6,4 +6,4 @@ //// let x = 1; // no semantic classification in js file -verify.semanticClassificationsAre(); \ No newline at end of file +verify.semanticClassificationsAre("original", ); diff --git a/tests/cases/fourslash/semanticClassificationModules.ts b/tests/cases/fourslash/semanticClassificationModules.ts index 6992639e4c3a5..ba2798dfaf8fc 100644 --- a/tests/cases/fourslash/semanticClassificationModules.ts +++ b/tests/cases/fourslash/semanticClassificationModules.ts @@ -10,10 +10,10 @@ ////var y = /*5*/M; var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.moduleName("M", test.marker("2").position), c.interfaceName("I", test.marker("3").position), c.moduleName("M", test.marker("4").position), - c.moduleName("M", test.marker("5").position)); \ No newline at end of file + c.moduleName("M", test.marker("5").position)); diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts index 6c98c8340c38f..9b291b933d0cc 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts @@ -9,6 +9,6 @@ ////var M = { I: 10 }; var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), - c.interfaceName("I", test.marker("1").position)); \ No newline at end of file + c.interfaceName("I", test.marker("1").position)); diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts index 419692b98ce7d..2c88b59b9b40e 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts @@ -15,7 +15,7 @@ ////var x = /*5*/M; var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.moduleName("M", test.marker("3").position), diff --git a/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts b/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts index bc55c5d8253cc..4d90b6b46c520 100644 --- a/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts +++ b/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts @@ -12,7 +12,7 @@ ////var I: typeof M | typeof /*8*/C; var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.interfaceName("I", test.marker("2").position), @@ -21,4 +21,4 @@ verify.semanticClassificationsAre( c.interfaceName("I", test.marker("5").position), c.interfaceName("I", test.marker("6").position), c.className("C", test.marker("7").position), - c.className("C", test.marker("8").position)); \ No newline at end of file + c.className("C", test.marker("8").position)); diff --git a/tests/cases/fourslash/semanticClassificationsCancellation1.ts b/tests/cases/fourslash/semanticClassificationsCancellation1.ts index 9381bef5e86ce..95a63db68c74e 100644 --- a/tests/cases/fourslash/semanticClassificationsCancellation1.ts +++ b/tests/cases/fourslash/semanticClassificationsCancellation1.ts @@ -7,9 +7,9 @@ var c = classification; cancellation.setCancelled(1); -verifyOperationIsCancelled(() => verify.semanticClassificationsAre()); +verifyOperationIsCancelled(() => verify.semanticClassificationsAre("original", )); cancellation.resetCancelled(); -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M"), c.moduleName("N")); diff --git a/tests/cases/fourslash/semanticClassificatonTypeAlias.ts b/tests/cases/fourslash/semanticClassificatonTypeAlias.ts index 188a09afcbc76..d021cbe827687 100644 --- a/tests/cases/fourslash/semanticClassificatonTypeAlias.ts +++ b/tests/cases/fourslash/semanticClassificatonTypeAlias.ts @@ -6,10 +6,10 @@ ////function f(x: /*3*/Alias): /*4*/Alias { return undefined; } var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.typeAliasName("Alias", test.marker("0").position), c.typeAliasName("Alias", test.marker("1").position), c.typeAliasName("Alias", test.marker("2").position), c.typeAliasName("Alias", test.marker("3").position), c.typeAliasName("Alias", test.marker("4").position) - ); \ No newline at end of file + ); diff --git a/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts b/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts index 4eb7f2a32edab..106e7171cc6d4 100644 --- a/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts +++ b/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts @@ -7,7 +7,7 @@ //// interface /*2*/X extends /*3*/M./*4*/I { } var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.interfaceName("X", test.marker("2").position), diff --git a/tests/cases/fourslash/shims/getSemanticClassifications.ts b/tests/cases/fourslash/shims/getSemanticClassifications.ts index 4eb7f2a32edab..106e7171cc6d4 100644 --- a/tests/cases/fourslash/shims/getSemanticClassifications.ts +++ b/tests/cases/fourslash/shims/getSemanticClassifications.ts @@ -7,7 +7,7 @@ //// interface /*2*/X extends /*3*/M./*4*/I { } var c = classification; -verify.semanticClassificationsAre( +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.interfaceName("X", test.marker("2").position), From fa8a49923a2be65cd57936b1b5db8a30ac95d8cb Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 15 Jun 2020 16:42:22 -0400 Subject: [PATCH 02/19] Adds the ability to test modern semantic classification via strings instead of numbers --- src/compiler/types.ts | 5 + src/harness/client.ts | 2 +- src/harness/fourslashImpl.ts | 2 +- src/harness/fourslashInterfaceImpl.ts | 71 ++- src/harness/harnessLanguageService.ts | 6 +- src/services/classifierVscode.ts | 502 +++++++++--------- src/services/services.ts | 18 +- src/services/shims.ts | 4 +- src/services/types.ts | 10 +- tests/cases/fourslash/fourslash.ts | 2 +- .../fourslash/semanticClassification1.ts | 19 +- 11 files changed, 350 insertions(+), 291 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2472b302545cc..23d4e402fa8f5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7764,6 +7764,11 @@ namespace ts { newLength: number; } + export const enum SemanticClassificationFormat { + Original = "orginal", + TwentyTwenty = "2020" + } + /* @internal */ export interface DiagnosticCollection { // Adds a diagnostic to this diagnostic collection. diff --git a/src/harness/client.ts b/src/harness/client.ts index 888edbf4483b4..1316d13dfbaee 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -747,7 +747,7 @@ namespace ts.server { return notImplemented(); } - getEncodedSemanticClassifications(_fileName: string, _span: TextSpan, _format?: "original" | "2020"): Classifications { + getEncodedSemanticClassifications(_fileName: string, _span: TextSpan, _format?: SemanticClassificationFormat): Classifications { return notImplemented(); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 5559ffab2e7e3..04450b9e85f54 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2513,7 +2513,7 @@ namespace FourSlash { } } - public verifySemanticClassifications(format: "original" | "2020", expected: { classificationType: string | number; text?: string }[]) { + public verifySemanticClassifications(format: ts.SemanticClassificationFormat, expected: { classificationType: string | number; text?: string }[]) { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 360d6c85716a7..c0bf33e89e9c3 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -504,7 +504,7 @@ namespace FourSlashInterface { /** * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended. */ - public semanticClassificationsAre(format: "original" | "2020", ...classifications: Classification[]) { + public semanticClassificationsAre(format: ts.SemanticClassificationFormat, ...classifications: Classification[]) { this.state.verifySemanticClassifications(format, classifications); } @@ -754,22 +754,73 @@ namespace FourSlashInterface { textSpan?: FourSlash.TextSpan; } - export function classification(format: "original" | "2020") { - function token(identifier: number, text: string, _position: number): Classification { + + export function classification(format: ts.SemanticClassificationFormat) { + + function semanticToken(identifier: string, text: string, _position: number): Classification { + + const tokenTypes = { + class: ts.classifier.vscode.TokenType.class, + enum: ts.classifier.vscode.TokenType.enum, + interface: ts.classifier.vscode.TokenType.interface, + namespace: ts.classifier.vscode.TokenType.namespace, + typeParameter: ts.classifier.vscode.TokenType.typeParameter, + type: ts.classifier.vscode.TokenType.type, + parameter: ts.classifier.vscode.TokenType.parameter, + variable: ts.classifier.vscode.TokenType.variable, + enumMember: ts.classifier.vscode.TokenType.enumMember, + property: ts.classifier.vscode.TokenType.property, + function: ts.classifier.vscode.TokenType.function, + member: ts.classifier.vscode.TokenType.member + }; + + const tokenModifiers = { + async: ts.classifier.vscode.TokenModifier.async, + declaration: ts.classifier.vscode.TokenModifier.declaration, + readonly: ts.classifier.vscode.TokenModifier.readonly, + static: ts.classifier.vscode.TokenModifier.static, + local: ts.classifier.vscode.TokenModifier.local, + defaultLibrary: ts.classifier.vscode.TokenModifier.defaultLibrary, + }; + + function identifierToClassificationID(identifier: string): number { + const [tokenType, ...modifiers] = identifier.split("."); + // @ts-expect-error + const tokenValue = tokenTypes[tokenType]; + if (tokenValue === undefined) { + throw new Error(`Did not find ${tokenType} in tokenTypes for classifiers.`); + } + + let classification = (tokenValue + 1) << 8; + ts.forEach(modifiers, (modifier) => { + // @ts-expect-error + const modifierValue = tokenModifiers[modifiers]; + if (tokenValue === undefined) { + throw new Error(`Did not find ${modifier} in tokenModifiers for classifiers.`); + } + classification += modifierValue + 1; + console.log("adding: ", modifierValue); + }); + + // debugger; + + return classification; + } + return { - classificationType: identifier, - // textSpan: { + classificationType: identifierToClassificationID(identifier), + // textSpan: { // start: position, // end: -1 // }, text - } + }; } - if (format === "2020") { + if (format === ts.SemanticClassificationFormat.TwentyTwenty) { return { - token - } + semanticToken + }; } function comment(text: string, position?: number): Classification { @@ -894,7 +945,7 @@ namespace FourSlashInterface { jsxText, jsxAttributeStringLiteralValue, getClassification - } + }; } export namespace Completion { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 24128e58779c5..142d84a12c2da 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -448,14 +448,14 @@ namespace Harness.LanguageService { getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length)); } - getSemanticClassifications(fileName: string, span: ts.TextSpan, format?: "original" | "2020"): ts.ClassifiedSpan[] { + getSemanticClassifications(fileName: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat): ts.ClassifiedSpan[] { return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length, format)); } getEncodedSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.Classifications { return unwrapJSONCallResult(this.shim.getEncodedSyntacticClassifications(fileName, span.start, span.length)); } - getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan, format?: "original" | "2020"): ts.Classifications { - const responseFormat = format || "original"; + getEncodedSemanticClassifications(fileName: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat): ts.Classifications { + const responseFormat = format || ts.SemanticClassificationFormat.Original; return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length, responseFormat)); } getCompletionsAtPosition(fileName: string, position: number, preferences: ts.UserPreferences | undefined): ts.CompletionInfo { diff --git a/src/services/classifierVscode.ts b/src/services/classifierVscode.ts index 4660960f15e81..0e972870e7e60 100644 --- a/src/services/classifierVscode.ts +++ b/src/services/classifierVscode.ts @@ -1,246 +1,256 @@ -namespace ts.classifier.vscode { - - enum TokenType { - class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ - } - - enum TokenModifier { - declaration, static, async, readonly, defaultLibrary, local, _ - } - - enum TokenEncodingConsts { - typeOffset = 8, - modifierMask = (1 << typeOffset) - 1 - } - - /** This is mainly used internally for testing */ - export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { - const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span) - - Debug.assert(classifications.spans.length % 3 === 0); - const dense = classifications.spans; - const result: ClassifiedSpan[] = []; - for (let i = 0; i < dense.length; i += 3) { - result.push({ - textSpan: createTextSpan(dense[i], dense[i + 1]), - classificationType: dense[i + 2] as any // getClassificationTypeName(dense[i + 2]) - }); - } - - return result; - } - - export function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { - return { - spans: getSemanticTokens(program, sourceFile, span), - endOfLineState: ts.EndOfLineState.None - } - } - - function getSemanticTokens(program: Program, sourceFile:SourceFile, span: TextSpan): number[] { - let resultTokens: number[] = []; - - const collector = (node: Node, typeIdx: number, modifierSet: number) => { - resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); - }; - - if (program && sourceFile) { - collectTokens(program, sourceFile, span, collector); - } - return resultTokens; - } - - function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void) { - const typeChecker = program.getTypeChecker(); - - let inJSXElement = false; - - function visit(node: Node) { - if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { - return; - } - const prevInJSXElement = inJSXElement; - if (isJsxElement(node) || isJsxSelfClosingElement(node)) { - inJSXElement = true; - } - if (isJsxExpression(node)) { - inJSXElement = false; - } - - if (isIdentifier(node) && !inJSXElement && !inImportClause(node)) { - let symbol = typeChecker.getSymbolAtLocation(node); - if (symbol) { - if (symbol.flags & SymbolFlags.Alias) { - symbol = typeChecker.getAliasedSymbol(symbol); - } - let typeIdx = classifySymbol(symbol, getMeaningFromLocation(node)); - if (typeIdx !== undefined) { - let modifierSet = 0; - if (node.parent) { - const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); - if (parentIsDeclaration && (node.parent).name === node) { - modifierSet = 1 << TokenModifier.declaration; - } - } - - // property declaration in constructor - if (typeIdx === TokenType.parameter && isRightSideOfQualifiedNameOrPropertyAccess(node)) { - typeIdx = TokenType.property; - } - - typeIdx = reclassifyByType(typeChecker, node, typeIdx); - - const decl = symbol.valueDeclaration; - if (decl) { - const modifiers = getCombinedModifierFlags(decl); - const nodeFlags = getCombinedNodeFlags(decl); - if (modifiers & ModifierFlags.Static) { - modifierSet |= 1 << TokenModifier.static; - } - if (modifiers & ModifierFlags.Async) { - modifierSet |= 1 << TokenModifier.async; - } - if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { - if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { - modifierSet |= 1 << TokenModifier.readonly; - } - } - if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { - modifierSet |= 1 << TokenModifier.local; - } - if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { - modifierSet |= 1 << TokenModifier.defaultLibrary; - } - } else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { - modifierSet |= 1 << TokenModifier.defaultLibrary; - } - - collector(node, typeIdx, modifierSet); - - } - } - } - forEachChild(node, visit); - - inJSXElement = prevInJSXElement; - } - visit(sourceFile); - } - - function classifySymbol(symbol: Symbol, meaning: SemanticMeaning): TokenType | undefined { - const flags = symbol.getFlags(); - if (flags & SymbolFlags.Class) { - return TokenType.class; - } else if (flags & SymbolFlags.Enum) { - return TokenType.enum; - } else if (flags & SymbolFlags.TypeAlias) { - return TokenType.type; - } else if (flags & SymbolFlags.Interface) { - if (meaning & SemanticMeaning.Type) { - return TokenType.interface; - } - } else if (flags & SymbolFlags.TypeParameter) { - return TokenType.typeParameter; - } - let decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; - if (decl && isBindingElement(decl)) { - decl = getDeclarationForBindingElement(decl); - } - return decl && tokenFromDeclarationMapping[decl.kind]; - } - - function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenType): TokenType { - // type based classifications - if (typeIdx === TokenType.variable || typeIdx === TokenType.property || typeIdx === TokenType.parameter) { - const type = typeChecker.getTypeAtLocation(node); - if (type) { - const test = (condition: (type: Type) => boolean) => { - return condition(type) || type.isUnion() && type.types.some(condition); - } - if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { - return TokenType.class; - } - if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { - return typeIdx === TokenType.property ? TokenType.member : TokenType.function; - } - } - } - return typeIdx; - } - - function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean { - if (isBindingElement(decl)) { - decl = getDeclarationForBindingElement(decl); - } - if (isVariableDeclaration(decl)) { - return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; - } else if (isFunctionDeclaration(decl)) { - return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; - } - return false; - } - - function getDeclarationForBindingElement(element: BindingElement): VariableDeclaration | ParameterDeclaration { - while (true) { - if (isBindingElement(element.parent.parent)) { - element = element.parent.parent; - } else { - return element.parent.parent; - } - } - } - - function inImportClause(node: Node): boolean { - const parent = node.parent; - return parent && (isImportClause(parent) || isImportSpecifier(parent) || isNamespaceImport(parent)); - } - - function isExpressionInCallExpression(node: Node): boolean { - while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { - node = node.parent - } - return isCallExpression(node.parent) && node.parent.expression === node; - } - - function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { - return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); - } - - const enum SemanticMeaning { - None = 0x0, - Value = 0x1, - Type = 0x2, - Namespace = 0x4, - All = Value | Type | Namespace - } - - function getMeaningFromLocation(node: Node): SemanticMeaning { - const f = (ts).getMeaningFromLocation; - if (typeof f === 'function') { - return f(node); - } - return SemanticMeaning.All; - } - - const tokenFromDeclarationMapping: { [name: string]: TokenType } = { - [SyntaxKind.VariableDeclaration]: TokenType.variable, - [SyntaxKind.Parameter]: TokenType.parameter, - [SyntaxKind.PropertyDeclaration]: TokenType.property, - [SyntaxKind.ModuleDeclaration]: TokenType.namespace, - [SyntaxKind.EnumDeclaration]: TokenType.enum, - [SyntaxKind.EnumMember]: TokenType.enumMember, - [SyntaxKind.ClassDeclaration]: TokenType.class, - [SyntaxKind.MethodDeclaration]: TokenType.member, - [SyntaxKind.FunctionDeclaration]: TokenType.function, - [SyntaxKind.FunctionExpression]: TokenType.function, - [SyntaxKind.MethodSignature]: TokenType.member, - [SyntaxKind.GetAccessor]: TokenType.property, - [SyntaxKind.SetAccessor]: TokenType.property, - [SyntaxKind.PropertySignature]: TokenType.property, - [SyntaxKind.InterfaceDeclaration]: TokenType.interface, - [SyntaxKind.TypeAliasDeclaration]: TokenType.type, - [SyntaxKind.TypeParameter]: TokenType.typeParameter, - [SyntaxKind.PropertyAssignment]: TokenType.property, - [SyntaxKind.ShorthandPropertyAssignment]: TokenType.property - }; -} +namespace ts.classifier.vscode { + + /** @internal */ + export enum TokenType { + class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ + } + + /** @internal */ + export enum TokenModifier { + declaration, static, async, readonly, defaultLibrary, local, _ + } + + /** @internal */ + export enum TokenEncodingConsts { + typeOffset = 8, + modifierMask = (1 << typeOffset) - 1 + } + + /** This is mainly used internally for testing */ + export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { + const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span); + + Debug.assert(classifications.spans.length % 3 === 0); + const dense = classifications.spans; + const result: ClassifiedSpan[] = []; + for (let i = 0; i < dense.length; i += 3) { + result.push({ + textSpan: createTextSpan(dense[i], dense[i + 1]), + classificationType: dense[i + 2] + }); + } + + return result; + } + + export function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { + return { + spans: getSemanticTokens(program, sourceFile, span), + endOfLineState: EndOfLineState.None + }; + } + + function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan): number[] { + const resultTokens: number[] = []; + + const collector = (node: Node, typeIdx: number, modifierSet: number) => { + resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); + }; + + if (program && sourceFile) { + collectTokens(program, sourceFile, span, collector); + } + return resultTokens; + } + + function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void) { + const typeChecker = program.getTypeChecker(); + + let inJSXElement = false; + + function visit(node: Node) { + if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { + return; + } + const prevInJSXElement = inJSXElement; + if (isJsxElement(node) || isJsxSelfClosingElement(node)) { + inJSXElement = true; + } + if (isJsxExpression(node)) { + inJSXElement = false; + } + + if (isIdentifier(node) && !inJSXElement && !inImportClause(node)) { + let symbol = typeChecker.getSymbolAtLocation(node); + if (symbol) { + if (symbol.flags & SymbolFlags.Alias) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + let typeIdx = classifySymbol(symbol, getMeaningFromLocation(node)); + if (typeIdx !== undefined) { + let modifierSet = 0; + if (node.parent) { + const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); + if (parentIsDeclaration && (node.parent).name === node) { + modifierSet = 1 << TokenModifier.declaration; + } + } + + // property declaration in constructor + if (typeIdx === TokenType.parameter && isRightSideOfQualifiedNameOrPropertyAccess(node)) { + typeIdx = TokenType.property; + } + + typeIdx = reclassifyByType(typeChecker, node, typeIdx); + + const decl = symbol.valueDeclaration; + if (decl) { + const modifiers = getCombinedModifierFlags(decl); + const nodeFlags = getCombinedNodeFlags(decl); + if (modifiers & ModifierFlags.Static) { + modifierSet |= 1 << TokenModifier.static; + } + if (modifiers & ModifierFlags.Async) { + modifierSet |= 1 << TokenModifier.async; + } + if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { + if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { + modifierSet |= 1 << TokenModifier.readonly; + } + } + if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { + modifierSet |= 1 << TokenModifier.local; + } + if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + } + else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + + collector(node, typeIdx, modifierSet); + + } + } + } + forEachChild(node, visit); + + inJSXElement = prevInJSXElement; + } + visit(sourceFile); + } + + function classifySymbol(symbol: Symbol, meaning: SemanticMeaning): TokenType | undefined { + const flags = symbol.getFlags(); + if (flags & SymbolFlags.Class) { + return TokenType.class; + } + else if (flags & SymbolFlags.Enum) { + return TokenType.enum; + } + else if (flags & SymbolFlags.TypeAlias) { + return TokenType.type; + } + else if (flags & SymbolFlags.Interface) { + if (meaning & SemanticMeaning.Type) { + return TokenType.interface; + } + } + else if (flags & SymbolFlags.TypeParameter) { + return TokenType.typeParameter; + } + let decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; + if (decl && isBindingElement(decl)) { + decl = getDeclarationForBindingElement(decl); + } + return decl && tokenFromDeclarationMapping[decl.kind]; + } + + function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenType): TokenType { + // type based classifications + if (typeIdx === TokenType.variable || typeIdx === TokenType.property || typeIdx === TokenType.parameter) { + const type = typeChecker.getTypeAtLocation(node); + if (type) { + const test = (condition: (type: Type) => boolean) => { + return condition(type) || type.isUnion() && type.types.some(condition); + }; + if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { + return TokenType.class; + } + if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { + return typeIdx === TokenType.property ? TokenType.member : TokenType.function; + } + } + } + return typeIdx; + } + + function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean { + if (isBindingElement(decl)) { + decl = getDeclarationForBindingElement(decl); + } + if (isVariableDeclaration(decl)) { + return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; + } + else if (isFunctionDeclaration(decl)) { + return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; + } + return false; + } + + function getDeclarationForBindingElement(element: BindingElement): VariableDeclaration | ParameterDeclaration { + while (true) { + if (isBindingElement(element.parent.parent)) { + element = element.parent.parent; + } + else { + return element.parent.parent; + } + } + } + + function inImportClause(node: Node): boolean { + const parent = node.parent; + return parent && (isImportClause(parent) || isImportSpecifier(parent) || isNamespaceImport(parent)); + } + + function isExpressionInCallExpression(node: Node): boolean { + while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { + node = node.parent; + } + return isCallExpression(node.parent) && node.parent.expression === node; + } + + function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { + return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); + } + + const enum SemanticMeaning { + None = 0x0, + Value = 0x1, + Type = 0x2, + Namespace = 0x4, + All = Value | Type | Namespace + } + + function getMeaningFromLocation(node: Node): SemanticMeaning { + const f = (ts).getMeaningFromLocation; + if (typeof f === "function") { + return f(node); + } + return SemanticMeaning.All; + } + + const tokenFromDeclarationMapping: { [name: string]: TokenType } = { + [SyntaxKind.VariableDeclaration]: TokenType.variable, + [SyntaxKind.Parameter]: TokenType.parameter, + [SyntaxKind.PropertyDeclaration]: TokenType.property, + [SyntaxKind.ModuleDeclaration]: TokenType.namespace, + [SyntaxKind.EnumDeclaration]: TokenType.enum, + [SyntaxKind.EnumMember]: TokenType.enumMember, + [SyntaxKind.ClassDeclaration]: TokenType.class, + [SyntaxKind.MethodDeclaration]: TokenType.member, + [SyntaxKind.FunctionDeclaration]: TokenType.function, + [SyntaxKind.FunctionExpression]: TokenType.function, + [SyntaxKind.MethodSignature]: TokenType.member, + [SyntaxKind.GetAccessor]: TokenType.property, + [SyntaxKind.SetAccessor]: TokenType.property, + [SyntaxKind.PropertySignature]: TokenType.property, + [SyntaxKind.InterfaceDeclaration]: TokenType.interface, + [SyntaxKind.TypeAliasDeclaration]: TokenType.type, + [SyntaxKind.TypeParameter]: TokenType.typeParameter, + [SyntaxKind.PropertyAssignment]: TokenType.property, + [SyntaxKind.ShorthandPropertyAssignment]: TokenType.property + }; +} diff --git a/src/services/services.ts b/src/services/services.ts index 38dac6f137034..6921012264209 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1797,33 +1797,35 @@ namespace ts { return kind === ScriptKind.TS || kind === ScriptKind.TSX; } - function getSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): ClassifiedSpan[] { + function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] { if (!isTsOrTsxFile(fileName)) { // do not run semantic classification on non-ts-or-tsx files return []; } synchronizeHostData(); - const responseFormat = format || "original" + const responseFormat = format || "original"; if (responseFormat === "original") { return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); - } else { - return ts.classifier.vscode.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + } + else { + return classifier.vscode.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } - function getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): Classifications { + function getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications { if (!isTsOrTsxFile(fileName)) { // do not run semantic classification on non-ts-or-tsx files return { spans: [], endOfLineState: EndOfLineState.None }; } synchronizeHostData(); - const responseFormat = format || "original" + const responseFormat = format || "original"; if (responseFormat === "original") { return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); - } else { - return ts.classifier.vscode.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + } + else { + return classifier.vscode.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } diff --git a/src/services/shims.ts b/src/services/shims.ts index 3714bbf21e427..f855a82ed2b0e 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -145,9 +145,9 @@ namespace ts { getCompilerOptionsDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; - getSemanticClassifications(fileName: string, start: number, length: number, format?: "original" | "2020"): string; + getSemanticClassifications(fileName: string, start: number, length: number, format?: SemanticClassificationFormat): string; getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string; - getEncodedSemanticClassifications(fileName: string, start: number, length: number, format?: "original" | "2020"): string; + getEncodedSemanticClassifications(fileName: string, start: number, length: number, format?: SemanticClassificationFormat): string; getCompletionsAtPosition(fileName: string, position: number, preferences: UserPreferences | undefined): string; getCompletionEntryDetails(fileName: string, position: number, entryName: string, formatOptions: string/*Services.FormatCodeOptions*/ | undefined, source: string | undefined, preferences: UserPreferences | undefined): string; diff --git a/src/services/types.ts b/src/services/types.ts index 02b11fa06e6b4..5d53fc9a666ee 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -375,23 +375,23 @@ namespace ts { getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; /** * Gets semantic highlights information for a particular file. Has two formats, an older * version used by VS and a format used by VS Code. - * + * * @param fileName The path to the file * @param position A text span to return results within * @param format Which format to use, defaults to "original" - * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. + * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. */ - getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: "original" | "2020"): Classifications; + getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications; /** * Gets completion entries at a particular position in a file. diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 633f8586fa570..4d67dc3919ca0 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -456,7 +456,7 @@ declare namespace FourSlashInterface { } interface ModernClassificationFactory { - token(identifier: number, name: string, position: number) + semanticToken(identifier: string, name: string, position: number) } interface ClassificationFactory { diff --git a/tests/cases/fourslash/semanticClassification1.ts b/tests/cases/fourslash/semanticClassification1.ts index 9fa7a7e284c7a..de96daee2091a 100644 --- a/tests/cases/fourslash/semanticClassification1.ts +++ b/tests/cases/fourslash/semanticClassification1.ts @@ -14,21 +14,12 @@ verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("3").position), c.interfaceName("I", test.marker("4").position)); - // // TODO: test like: - // // c2.token("module", "M", test.marker("0").position)) - var c2 = classification("2020") verify.semanticClassificationsAre("2020", - c2.token(1025, "M", test.marker("0").position), - c2.token(769, "I", test.marker("1").position), - c2.token(769, "X", test.marker("2").position), - c2.token(1024, "M", test.marker("3").position), - c2.token(768, "I", test.marker("4").position), + c2.semanticToken("namespace.declaration", "M", test.marker("0").position), + c2.semanticToken("interface.declaration", "I", test.marker("1").position), + c2.semanticToken("interface.declaration", "X", test.marker("2").position), + c2.semanticToken("namespace", "M", test.marker("3").position), + c2.semanticToken("interface", "I", test.marker("4").position), ) -// { textSpan: { start: 7, end: 1 }, classificationType: 1025 }, -// { textSpan: { start: 32, end: 1 }, classificationType: 769 }, -// { textSpan: { start: 54, end: 1 }, classificationType: 769 }, -// { textSpan: { start: 64, end: 1 }, classificationType: 1024 }, -// { textSpan: { start: 66, end: 1 }, classificationType: 768 } ); - From 8a5c3b390b37582baf3029b540e107a030c9fe8f Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 16 Jun 2020 16:29:38 -0400 Subject: [PATCH 03/19] Adds existing tests --- src/compiler/types.ts | 2 +- src/harness/fourslashImpl.ts | 74 ++++++++++++++++++- src/harness/fourslashInterfaceImpl.ts | 61 ++------------- src/services/classifierVscode.ts | 12 +-- src/services/services.ts | 12 +-- .../cases/fourslash/classifyThisParameter.ts | 2 +- tests/cases/fourslash/fourslash.ts | 4 +- .../incrementalJsDocAdjustsLengthsRight.ts | 2 +- .../fourslash/semanticClassification1.ts | 12 +-- .../fourslash/semanticClassification2.ts | 11 ++- .../fourslash/semanticClassificationAlias.ts | 10 ++- .../semanticClassificationClassExpression.ts | 11 ++- ...nticClassificationInTemplateExpressions.ts | 17 ++++- ...stantiatedModuleWithVariableOfSameName1.ts | 18 ++++- ...stantiatedModuleWithVariableOfSameName2.ts | 18 ++++- .../fourslash/semanticClassificationJs.ts | 2 + .../semanticClassificationModules.ts | 16 +++- ...stantiatedModuleWithVariableOfSameName1.ts | 11 ++- ...stantiatedModuleWithVariableOfSameName2.ts | 17 ++++- .../semanticClassificationWithUnionTypes.ts | 18 ++++- .../semanticClassificationsCancellation1.ts | 11 ++- .../semanticClassificatonTypeAlias.ts | 15 +++- .../shims-pp/getSemanticClassifications.ts | 2 +- .../shims-pp/getSyntacticClassifications.ts | 4 +- .../shims/getSemanticClassifications.ts | 2 +- .../shims/getSyntacticClassifications.ts | 4 +- ...tacticClassificationForJSDocTemplateTag.ts | 9 ++- .../syntacticClassificationWithErrors.ts | 11 ++- .../fourslash/syntacticClassifications1.ts | 18 ++++- .../syntacticClassificationsCancellation1.ts | 8 +- ...ticClassificationsConflictDiff3Markers1.ts | 10 ++- ...ticClassificationsConflictDiff3Markers2.ts | 9 ++- ...yntacticClassificationsConflictMarkers1.ts | 10 ++- ...yntacticClassificationsConflictMarkers2.ts | 9 ++- .../syntacticClassificationsDocComment1.ts | 8 +- .../syntacticClassificationsDocComment2.ts | 7 +- .../syntacticClassificationsDocComment3.ts | 8 +- .../syntacticClassificationsDocComment4.ts | 8 +- .../syntacticClassificationsForOfKeyword.ts | 10 ++- .../syntacticClassificationsForOfKeyword2.ts | 10 ++- .../syntacticClassificationsForOfKeyword3.ts | 11 ++- ...cticClassificationsFunctionWithComments.ts | 14 +++- .../fourslash/syntacticClassificationsJsx1.ts | 10 ++- .../fourslash/syntacticClassificationsJsx2.ts | 10 ++- ...cticClassificationsMergeConflictMarker1.ts | 8 +- .../syntacticClassificationsObjectLiteral.ts | 19 ++++- .../syntacticClassificationsTemplates1.ts | 12 ++- .../syntacticClassificationsTemplates2.ts | 9 ++- .../syntacticClassificationsTripleSlash1.ts | 6 +- .../syntacticClassificationsTripleSlash10.ts | 4 +- .../syntacticClassificationsTripleSlash11.ts | 4 +- .../syntacticClassificationsTripleSlash12.ts | 4 +- .../syntacticClassificationsTripleSlash13.ts | 4 +- .../syntacticClassificationsTripleSlash14.ts | 4 +- .../syntacticClassificationsTripleSlash15.ts | 4 +- .../syntacticClassificationsTripleSlash16.ts | 4 +- .../syntacticClassificationsTripleSlash17.ts | 4 +- .../syntacticClassificationsTripleSlash18.ts | 4 +- .../syntacticClassificationsTripleSlash2.ts | 6 +- .../syntacticClassificationsTripleSlash3.ts | 6 +- .../syntacticClassificationsTripleSlash4.ts | 6 +- .../syntacticClassificationsTripleSlash5.ts | 6 +- .../syntacticClassificationsTripleSlash6.ts | 6 +- .../syntacticClassificationsTripleSlash7.ts | 6 +- .../syntacticClassificationsTripleSlash8.ts | 6 +- .../syntacticClassificationsTripleSlash9.ts | 6 +- 66 files changed, 513 insertions(+), 173 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 23d4e402fa8f5..4473e494d4357 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7765,7 +7765,7 @@ namespace ts { } export const enum SemanticClassificationFormat { - Original = "orginal", + Original = "original", TwentyTwenty = "2020" } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 04450b9e85f54..f051761ee44bf 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2448,9 +2448,50 @@ namespace FourSlash { Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos)!, "**")); } + private classificationToIdentifier(classification: number){ + + const tokenTypes: string[] = []; + tokenTypes[ts.classifier.vscode.TokenType.class] = "class"; + tokenTypes[ts.classifier.vscode.TokenType.enum] = "enum"; + tokenTypes[ts.classifier.vscode.TokenType.interface] = "interface"; + tokenTypes[ts.classifier.vscode.TokenType.namespace] = "namespace"; + tokenTypes[ts.classifier.vscode.TokenType.typeParameter] = "typeParameter"; + tokenTypes[ts.classifier.vscode.TokenType.type] = "type"; + tokenTypes[ts.classifier.vscode.TokenType.parameter] = "parameter"; + tokenTypes[ts.classifier.vscode.TokenType.variable] = "variable"; + tokenTypes[ts.classifier.vscode.TokenType.enumMember] = "enumMember"; + tokenTypes[ts.classifier.vscode.TokenType.property] = "property"; + tokenTypes[ts.classifier.vscode.TokenType.function] = "function"; + tokenTypes[ts.classifier.vscode.TokenType.member] = "member"; + + const tokenModifiers: string[] = []; + tokenModifiers[ts.classifier.vscode.TokenModifier.async] = "async"; + tokenModifiers[ts.classifier.vscode.TokenModifier.declaration] = "declaration"; + tokenModifiers[ts.classifier.vscode.TokenModifier.readonly] = "readonly"; + tokenModifiers[ts.classifier.vscode.TokenModifier.static] = "static"; + tokenModifiers[ts.classifier.vscode.TokenModifier.local] = "local"; + tokenModifiers[ts.classifier.vscode.TokenModifier.defaultLibrary] = "defaultLibrary"; + + + function getTokenTypeFromClassification(tsClassification: number): number | undefined { + if (tsClassification > ts.classifier.vscode.TokenEncodingConsts.modifierMask) { + return (tsClassification >> ts.classifier.vscode.TokenEncodingConsts.typeOffset) - 1; + } + return undefined; + } + + function getTokenModifierFromClassification(tsClassification: number) { + return tsClassification & ts.classifier.vscode.TokenEncodingConsts.modifierMask; + } + + const typeIdx = getTokenTypeFromClassification(classification) || 0; + const modSet = getTokenModifierFromClassification(classification); + + const tokenClassifiction = [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join("."); + return tokenClassifiction; + } + private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) { - console.log("expected:", expected); - console.log("actual:", actual); if (actual.length !== expected.length) { this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length + ", but was " + actual.length + @@ -2459,10 +2500,12 @@ namespace FourSlash { ts.zipWith(expected, actual, (expectedClassification, actualClassification) => { const expectedType = expectedClassification.classificationType; - if (expectedType !== actualClassification.classificationType) { + const actualType = typeof actualClassification.classificationType === "number" ? this.classificationToIdentifier(actualClassification.classificationType) : actualClassification.classificationType; + + if (expectedType !== actualType) { this.raiseError("verifyClassifications failed - expected classifications type to be " + expectedType + ", but was " + - actualClassification.classificationType + + actualType + jsonMismatchString()); } @@ -2513,6 +2556,29 @@ namespace FourSlash { } } + public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) { + const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, + ts.createTextSpan(0, this.activeFile.content.length), format); + const replacement = [`const c2 = classification("2020");`,`verify.semanticClassificationsAre("2020",`]; + actual.forEach(a => { + const identifier = this.classificationToIdentifier(a.classificationType as number); + const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length); + replacement.push(` c2.semanticToken("${identifier}", "${text}"), `); + }); + replacement.push(");"); + + throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); + + /** + const fs = require("fs"); + const testfilePath = this.originalInputFileName.slice(1); + const testfile = fs.readFileSync(testfilePath, "utf8"); + const newfile = testfile.replace("verify.replaceWithSemanticClassifications(\"2020\")", replacement.join("\n")); + fs.writeFileSync(testfilePath, newfile); + */ + } + + public verifySemanticClassifications(format: ts.SemanticClassificationFormat, expected: { classificationType: string | number; text?: string }[]) { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index c0bf33e89e9c3..6a7c3ae838939 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -508,6 +508,10 @@ namespace FourSlashInterface { this.state.verifySemanticClassifications(format, classifications); } + public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) { + this.state.replaceWithSemanticClassifications(format); + } + public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range, options?: ts.RenameInfoOptions) { this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange, options); } @@ -749,7 +753,7 @@ namespace FourSlashInterface { } interface Classification { - classificationType: ts.ClassificationTypeNames | number; + classificationType: ts.ClassificationTypeNames | string; text?: string; textSpan?: FourSlash.TextSpan; } @@ -758,61 +762,8 @@ namespace FourSlashInterface { export function classification(format: ts.SemanticClassificationFormat) { function semanticToken(identifier: string, text: string, _position: number): Classification { - - const tokenTypes = { - class: ts.classifier.vscode.TokenType.class, - enum: ts.classifier.vscode.TokenType.enum, - interface: ts.classifier.vscode.TokenType.interface, - namespace: ts.classifier.vscode.TokenType.namespace, - typeParameter: ts.classifier.vscode.TokenType.typeParameter, - type: ts.classifier.vscode.TokenType.type, - parameter: ts.classifier.vscode.TokenType.parameter, - variable: ts.classifier.vscode.TokenType.variable, - enumMember: ts.classifier.vscode.TokenType.enumMember, - property: ts.classifier.vscode.TokenType.property, - function: ts.classifier.vscode.TokenType.function, - member: ts.classifier.vscode.TokenType.member - }; - - const tokenModifiers = { - async: ts.classifier.vscode.TokenModifier.async, - declaration: ts.classifier.vscode.TokenModifier.declaration, - readonly: ts.classifier.vscode.TokenModifier.readonly, - static: ts.classifier.vscode.TokenModifier.static, - local: ts.classifier.vscode.TokenModifier.local, - defaultLibrary: ts.classifier.vscode.TokenModifier.defaultLibrary, - }; - - function identifierToClassificationID(identifier: string): number { - const [tokenType, ...modifiers] = identifier.split("."); - // @ts-expect-error - const tokenValue = tokenTypes[tokenType]; - if (tokenValue === undefined) { - throw new Error(`Did not find ${tokenType} in tokenTypes for classifiers.`); - } - - let classification = (tokenValue + 1) << 8; - ts.forEach(modifiers, (modifier) => { - // @ts-expect-error - const modifierValue = tokenModifiers[modifiers]; - if (tokenValue === undefined) { - throw new Error(`Did not find ${modifier} in tokenModifiers for classifiers.`); - } - classification += modifierValue + 1; - console.log("adding: ", modifierValue); - }); - - // debugger; - - return classification; - } - return { - classificationType: identifierToClassificationID(identifier), - // textSpan: { - // start: position, - // end: -1 - // }, + classificationType: identifier, text }; } diff --git a/src/services/classifierVscode.ts b/src/services/classifierVscode.ts index 0e972870e7e60..2d3a382cc9574 100644 --- a/src/services/classifierVscode.ts +++ b/src/services/classifierVscode.ts @@ -1,5 +1,11 @@ namespace ts.classifier.vscode { + /** @internal */ + export enum TokenEncodingConsts { + typeOffset = 8, + modifierMask = (1 << typeOffset) - 1 + } + /** @internal */ export enum TokenType { class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ @@ -10,12 +16,6 @@ namespace ts.classifier.vscode { declaration, static, async, readonly, defaultLibrary, local, _ } - /** @internal */ - export enum TokenEncodingConsts { - typeOffset = 8, - modifierMask = (1 << typeOffset) - 1 - } - /** This is mainly used internally for testing */ export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span); diff --git a/src/services/services.ts b/src/services/services.ts index 6921012264209..9939bdc787363 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1804,11 +1804,11 @@ namespace ts { } synchronizeHostData(); - const responseFormat = format || "original"; - if (responseFormat === "original") { + const responseFormat = format || SemanticClassificationFormat.Original; + if (responseFormat === SemanticClassificationFormat.Original) { return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } - else { + else { return classifier.vscode.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } @@ -1820,11 +1820,11 @@ namespace ts { } synchronizeHostData(); - const responseFormat = format || "original"; - if (responseFormat === "original") { + const responseFormat = format || SemanticClassificationFormat.Original; + if (responseFormat === SemanticClassificationFormat.Original) { return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } - else { + else { return classifier.vscode.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } diff --git a/tests/cases/fourslash/classifyThisParameter.ts b/tests/cases/fourslash/classifyThisParameter.ts index 5e0c9a9d4b666..e28e5c2e67c9d 100644 --- a/tests/cases/fourslash/classifyThisParameter.ts +++ b/tests/cases/fourslash/classifyThisParameter.ts @@ -2,7 +2,7 @@ ////function f(this){} -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("function"), c.identifier("f"), diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 4d67dc3919ca0..7614c221be460 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -358,6 +358,8 @@ declare namespace FourSlashInterface { text?: string; textSpan?: TextSpan; }[]): void; + /** Edits the current testfile and replaces with the semantic classifications */ + replaceWithSemanticClassifications(format: "2020") renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, range?: Range, allowRenameOfImportPath?: boolean): void; renameInfoFailed(message?: string, allowRenameOfImportPath?: boolean): void; renameLocations(startRanges: ArrayOrSingle, options: RenameLocationsOptions): void; @@ -456,7 +458,7 @@ declare namespace FourSlashInterface { } interface ModernClassificationFactory { - semanticToken(identifier: string, name: string, position: number) + semanticToken(identifier: string, name: string) } interface ClassificationFactory { diff --git a/tests/cases/fourslash/incrementalJsDocAdjustsLengthsRight.ts b/tests/cases/fourslash/incrementalJsDocAdjustsLengthsRight.ts index 626a1e372588a..e4d438171a964 100644 --- a/tests/cases/fourslash/incrementalJsDocAdjustsLengthsRight.ts +++ b/tests/cases/fourslash/incrementalJsDocAdjustsLengthsRight.ts @@ -9,7 +9,7 @@ //// * @param {Number} wid/*1*/ goTo.marker('1'); edit.insert("th\n@"); -const c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/**\n * Pad `str` to `width`.\n *\n * "), c.punctuation("@"), diff --git a/tests/cases/fourslash/semanticClassification1.ts b/tests/cases/fourslash/semanticClassification1.ts index de96daee2091a..25f5557542a07 100644 --- a/tests/cases/fourslash/semanticClassification1.ts +++ b/tests/cases/fourslash/semanticClassification1.ts @@ -6,7 +6,7 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification("original"); +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), @@ -16,10 +16,10 @@ verify.semanticClassificationsAre("original", var c2 = classification("2020") verify.semanticClassificationsAre("2020", - c2.semanticToken("namespace.declaration", "M", test.marker("0").position), - c2.semanticToken("interface.declaration", "I", test.marker("1").position), - c2.semanticToken("interface.declaration", "X", test.marker("2").position), - c2.semanticToken("namespace", "M", test.marker("3").position), - c2.semanticToken("interface", "I", test.marker("4").position), + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("interface.declaration", "X"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("interface", "I"), ) diff --git a/tests/cases/fourslash/semanticClassification2.ts b/tests/cases/fourslash/semanticClassification2.ts index 84cdb8fc766ed..f250b7d690047 100644 --- a/tests/cases/fourslash/semanticClassification2.ts +++ b/tests/cases/fourslash/semanticClassification2.ts @@ -7,5 +7,14 @@ //// var Thing = 0; //// Thing.toExponential(); -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.interfaceName("Thing", test.marker("0").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("interface.declaration", "Thing"), + c2.semanticToken("member.declaration", "toExponential"), + c2.semanticToken("variable.declaration", "Thing"), + c2.semanticToken("variable", "Thing"), + c2.semanticToken("member.defaultLibrary", "toExponential") +); diff --git a/tests/cases/fourslash/semanticClassificationAlias.ts b/tests/cases/fourslash/semanticClassificationAlias.ts index 7e34940cc00ca..eef56f91830d5 100644 --- a/tests/cases/fourslash/semanticClassificationAlias.ts +++ b/tests/cases/fourslash/semanticClassificationAlias.ts @@ -11,10 +11,18 @@ goTo.file("/b.ts"); const [m0, m1, m2, m3] = test.markers(); -const c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.typeAliasName("x", m0.position), c.className("y", m1.position), c.typeAliasName("x", m2.position), c.className("y", m3.position), ); + +const c2 = classification("2020"); + verify.semanticClassificationsAre("2020", + + c2.semanticToken("variable.declaration.readonly", "v"), + c2.semanticToken("type", "x"), + c2.semanticToken("class", "y"), +); diff --git a/tests/cases/fourslash/semanticClassificationClassExpression.ts b/tests/cases/fourslash/semanticClassificationClassExpression.ts index 98da5a8418d3e..eda79ce8f3d39 100644 --- a/tests/cases/fourslash/semanticClassificationClassExpression.ts +++ b/tests/cases/fourslash/semanticClassificationClassExpression.ts @@ -3,10 +3,19 @@ //// var x = class /*0*/C {} //// class /*1*/C {} //// class /*2*/D extends class /*3*/B{} { } -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.className("C", test.marker("0").position), c.className("C", test.marker("1").position), c.className("D", test.marker("2").position), c.className("B", test.marker("3").position) ); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "x"), + c2.semanticToken("class", "C"), + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("class.declaration", "D"), + c2.semanticToken("class", "B"), +); diff --git a/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts b/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts index 15f822de0a82d..5866529de3da8 100644 --- a/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts +++ b/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts @@ -10,7 +10,7 @@ ////} ////`abcd${ /*3*/M./*4*/C.x + /*5*/M./*6*/E.E1}efg` -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.className("C", test.marker("1").position), @@ -19,3 +19,18 @@ verify.semanticClassificationsAre("original", c.className("C", test.marker("4").position), c.moduleName("M", test.marker("5").position), c.enumName("E", test.marker("6").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("property.declaration.static", "x"), + c2.semanticToken("enum.declaration", "E"), + c2.semanticToken("enumMember.declaration.readonly", "E1"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("class", "C"), + c2.semanticToken("property.static", "x"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("enum", "E"), + c2.semanticToken("enumMember.readonly", "E1"), +); diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts index cfb43136fe859..ab5de2ba6f175 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts @@ -15,10 +15,26 @@ //// ////var x = /*5*/M; -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.moduleName("M", test.marker("3").position), c.interfaceName("I", test.marker("4").position), c.moduleName("M", test.marker("5").position)); + + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("variable.declaration.local", "x"), + c2.semanticToken("variable.declaration", "M"), + c2.semanticToken("property.declaration", "foo"), + c2.semanticToken("property.declaration", "bar"), + c2.semanticToken("variable.declaration", "v"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("interface", "I"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("namespace", "M"), +); diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts index 4b1745479a19a..5f9de7227d9b3 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts @@ -18,7 +18,7 @@ //// ////var x = /*6*/M; -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), @@ -26,3 +26,19 @@ verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("4").position), c.interfaceName("I", test.marker("5").position), c.moduleName("M", test.marker("6").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("variable.declaration.local", "x"), + c2.semanticToken("variable.declaration", "M"), + c2.semanticToken("property.declaration", "foo"), + c2.semanticToken("property.declaration", "bar"), + c2.semanticToken("variable.declaration", "v"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("interface", "I"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("namespace", "M"), +); diff --git a/tests/cases/fourslash/semanticClassificationJs.ts b/tests/cases/fourslash/semanticClassificationJs.ts index 4232c962012f7..69683d6669511 100644 --- a/tests/cases/fourslash/semanticClassificationJs.ts +++ b/tests/cases/fourslash/semanticClassificationJs.ts @@ -7,3 +7,5 @@ // no semantic classification in js file verify.semanticClassificationsAre("original", ); + + diff --git a/tests/cases/fourslash/semanticClassificationModules.ts b/tests/cases/fourslash/semanticClassificationModules.ts index ba2798dfaf8fc..5a57251b3a599 100644 --- a/tests/cases/fourslash/semanticClassificationModules.ts +++ b/tests/cases/fourslash/semanticClassificationModules.ts @@ -9,7 +9,7 @@ ////var x: /*2*/M./*3*/I = /*4*/M.v; ////var y = /*5*/M; -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), @@ -17,3 +17,17 @@ verify.semanticClassificationsAre("original", c.interfaceName("I", test.marker("3").position), c.moduleName("M", test.marker("4").position), c.moduleName("M", test.marker("5").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("variable.declaration.local", "v"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("interface", "I"), + c2.semanticToken("namespace", "M"), + c2.semanticToken("variable.local", "v"), + c2.semanticToken("variable.declaration", "y"), + c2.semanticToken("namespace", "M"), +); diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts index 9b291b933d0cc..6c1e24e2d94f0 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts @@ -8,7 +8,16 @@ //// ////var M = { I: 10 }; -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("variable.declaration", "M"), + c2.semanticToken("property.declaration", "I"), +); + \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts index 2c88b59b9b40e..1566d333c4e37 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts @@ -14,9 +14,24 @@ //// ////var x = /*5*/M; -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), c.moduleName("M", test.marker("3").position), c.interfaceName("I", test.marker("4").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("variable.declaration", "M"), + c2.semanticToken("property.declaration", "foo"), + c2.semanticToken("property.declaration", "bar"), + c2.semanticToken("variable.declaration", "v"), + c2.semanticToken("variable", "M"), + c2.semanticToken("interface", "I"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("variable", "M"), +); + \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts b/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts index 4d90b6b46c520..257130392df1f 100644 --- a/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts +++ b/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts @@ -11,7 +11,7 @@ ////var M: /*4*/M./*5*/I | /*6*/I | /*7*/C; ////var I: typeof M | typeof /*8*/C; -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), @@ -22,3 +22,19 @@ verify.semanticClassificationsAre("original", c.interfaceName("I", test.marker("6").position), c.className("C", test.marker("7").position), c.className("C", test.marker("8").position)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("variable.declaration", "M"), + c2.semanticToken("variable", "M"), + c2.semanticToken("interface", "I"), + c2.semanticToken("interface", "I"), + c2.semanticToken("class", "C"), + c2.semanticToken("class.declaration", "I"), + c2.semanticToken("variable", "M"), + c2.semanticToken("class", "C"), +); diff --git a/tests/cases/fourslash/semanticClassificationsCancellation1.ts b/tests/cases/fourslash/semanticClassificationsCancellation1.ts index 95a63db68c74e..84a0dafe17681 100644 --- a/tests/cases/fourslash/semanticClassificationsCancellation1.ts +++ b/tests/cases/fourslash/semanticClassificationsCancellation1.ts @@ -5,7 +5,7 @@ ////module N { ////} -var c = classification; +const c = classification("original"); cancellation.setCancelled(1); verifyOperationIsCancelled(() => verify.semanticClassificationsAre("original", )); cancellation.resetCancelled(); @@ -13,3 +13,12 @@ cancellation.resetCancelled(); verify.semanticClassificationsAre("original", c.moduleName("M"), c.moduleName("N")); + + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("namespace.declaration", "N"), +); + + \ No newline at end of file diff --git a/tests/cases/fourslash/semanticClassificatonTypeAlias.ts b/tests/cases/fourslash/semanticClassificatonTypeAlias.ts index d021cbe827687..01e390b33a85d 100644 --- a/tests/cases/fourslash/semanticClassificatonTypeAlias.ts +++ b/tests/cases/fourslash/semanticClassificatonTypeAlias.ts @@ -5,7 +5,7 @@ ////var y = {}; ////function f(x: /*3*/Alias): /*4*/Alias { return undefined; } -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.typeAliasName("Alias", test.marker("0").position), c.typeAliasName("Alias", test.marker("1").position), @@ -13,3 +13,16 @@ verify.semanticClassificationsAre("original", c.typeAliasName("Alias", test.marker("3").position), c.typeAliasName("Alias", test.marker("4").position) ); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("type.declaration", "Alias"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("type", "Alias"), + c2.semanticToken("variable.declaration", "y"), + c2.semanticToken("type", "Alias"), + c2.semanticToken("function.declaration", "f"), + c2.semanticToken("parameter.declaration", "x"), + c2.semanticToken("type", "Alias"), + c2.semanticToken("type", "Alias"), +); diff --git a/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts b/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts index 106e7171cc6d4..1bbc4eec21a3e 100644 --- a/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts +++ b/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts @@ -6,7 +6,7 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), diff --git a/tests/cases/fourslash/shims-pp/getSyntacticClassifications.ts b/tests/cases/fourslash/shims-pp/getSyntacticClassifications.ts index 1dbe2944b8ae5..897d42cbea729 100644 --- a/tests/cases/fourslash/shims-pp/getSyntacticClassifications.ts +++ b/tests/cases/fourslash/shims-pp/getSyntacticClassifications.ts @@ -18,7 +18,7 @@ //// } //// } -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("// comment"), c.keyword("module"), c.moduleName("M"), c.punctuation("{"), @@ -32,4 +32,4 @@ verify.syntacticClassificationsAre( 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 + c.punctuation("}")); diff --git a/tests/cases/fourslash/shims/getSemanticClassifications.ts b/tests/cases/fourslash/shims/getSemanticClassifications.ts index 106e7171cc6d4..1bbc4eec21a3e 100644 --- a/tests/cases/fourslash/shims/getSemanticClassifications.ts +++ b/tests/cases/fourslash/shims/getSemanticClassifications.ts @@ -6,7 +6,7 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification; +const c = classification("original"); verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.interfaceName("I", test.marker("1").position), diff --git a/tests/cases/fourslash/shims/getSyntacticClassifications.ts b/tests/cases/fourslash/shims/getSyntacticClassifications.ts index 1dbe2944b8ae5..897d42cbea729 100644 --- a/tests/cases/fourslash/shims/getSyntacticClassifications.ts +++ b/tests/cases/fourslash/shims/getSyntacticClassifications.ts @@ -18,7 +18,7 @@ //// } //// } -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("// comment"), c.keyword("module"), c.moduleName("M"), c.punctuation("{"), @@ -32,4 +32,4 @@ verify.syntacticClassificationsAre( 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 + c.punctuation("}")); diff --git a/tests/cases/fourslash/syntacticClassificationForJSDocTemplateTag.ts b/tests/cases/fourslash/syntacticClassificationForJSDocTemplateTag.ts index c3368207d2cc2..0f8169828b30d 100644 --- a/tests/cases/fourslash/syntacticClassificationForJSDocTemplateTag.ts +++ b/tests/cases/fourslash/syntacticClassificationForJSDocTemplateTag.ts @@ -4,7 +4,7 @@ ////function ident: T { ////} -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/** "), c.punctuation("@"), @@ -20,3 +20,10 @@ verify.syntacticClassificationsAre( c.identifier("T"), c.punctuation("{"), c.punctuation("}")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("function.declaration", "ident"), + c2.semanticToken("typeParameter.declaration", "T"), + c2.semanticToken("typeParameter", "T"), +); diff --git a/tests/cases/fourslash/syntacticClassificationWithErrors.ts b/tests/cases/fourslash/syntacticClassificationWithErrors.ts index 166a22a1a5127..d21f8f9955ba7 100644 --- a/tests/cases/fourslash/syntacticClassificationWithErrors.ts +++ b/tests/cases/fourslash/syntacticClassificationWithErrors.ts @@ -5,10 +5,17 @@ ////} ////c = -let c = classification +const c = classification("original") + verify.syntacticClassificationsAre( c.keyword("class"), c.className("A"), c.punctuation("{"), c.identifier("a"), c.punctuation(":"), c.punctuation("}"), c.identifier("c"), c.operator("=") - ); \ No newline at end of file + ); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "A"), + c2.semanticToken("property.declaration", "a"), +); diff --git a/tests/cases/fourslash/syntacticClassifications1.ts b/tests/cases/fourslash/syntacticClassifications1.ts index 1dbe2944b8ae5..23c1460dcff3a 100644 --- a/tests/cases/fourslash/syntacticClassifications1.ts +++ b/tests/cases/fourslash/syntacticClassifications1.ts @@ -18,7 +18,7 @@ //// } //// } -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("// comment"), c.keyword("module"), c.moduleName("M"), c.punctuation("{"), @@ -32,4 +32,18 @@ verify.syntacticClassificationsAre( 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 + c.punctuation("}")); + + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("variable.declaration.local", "v"), + c2.semanticToken("variable.declaration.local", "s"), + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("typeParameter.declaration", "T"), + c2.semanticToken("enum.declaration", "E"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("namespace.declaration", "M1"), + c2.semanticToken("namespace.declaration", "M2"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsCancellation1.ts b/tests/cases/fourslash/syntacticClassificationsCancellation1.ts index f15ce5f9984c8..9b483463bec84 100644 --- a/tests/cases/fourslash/syntacticClassificationsCancellation1.ts +++ b/tests/cases/fourslash/syntacticClassificationsCancellation1.ts @@ -5,7 +5,7 @@ ////module N { ////} -var c = classification; +const c = classification("original"); cancellation.setCancelled(1); verifyOperationIsCancelled(() => verify.syntacticClassificationsAre()); cancellation.resetCancelled(); @@ -19,3 +19,9 @@ verify.syntacticClassificationsAre( c.moduleName("N"), c.punctuation("{"), c.punctuation("}")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("namespace.declaration", "N"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts index 669705307a96a..b63271f096b0f 100644 --- a/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts +++ b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers1.ts @@ -10,7 +10,7 @@ ////>>>>>>> Branch - a ////} -const c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("class"), c.className("C"), c.punctuation("{"), c.comment("<<<<<<< HEAD"), @@ -20,4 +20,10 @@ verify.syntacticClassificationsAre( c.comment("======="), c.identifier("v"), c.punctuation("="), c.numericLiteral("2"), c.punctuation(";"), c.comment(">>>>>>> Branch - a"), - c.punctuation("}")); \ No newline at end of file + c.punctuation("}")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("property.declaration", "v"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts index 17144397184c6..c75bb2130f5b9 100644 --- a/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts +++ b/tests/cases/fourslash/syntacticClassificationsConflictDiff3Markers2.ts @@ -8,7 +8,7 @@ ////class D { } ////>>>>>>> Branch - a -const c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("<<<<<<< HEAD"), c.keyword("class"), c.className("C"), c.punctuation("{"), c.punctuation("}"), @@ -16,4 +16,9 @@ verify.syntacticClassificationsAre( c.keyword("class"), c.identifier("E"), c.punctuation("{"), c.punctuation("}"), c.comment("======="), c.keyword("class"), c.identifier("D"), c.punctuation("{"), c.punctuation("}"), - c.comment(">>>>>>> Branch - a")); \ No newline at end of file + c.comment(">>>>>>> Branch - a")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "C"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts b/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts index 99db7443a4c73..54f40b2cc61ab 100644 --- a/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts +++ b/tests/cases/fourslash/syntacticClassificationsConflictMarkers1.ts @@ -8,7 +8,7 @@ ////>>>>>>> Branch - a ////} -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("class"), c.className("C"), c.punctuation("{"), c.comment("<<<<<<< HEAD"), @@ -16,4 +16,10 @@ verify.syntacticClassificationsAre( c.comment("======="), c.identifier("v"), c.punctuation("="), c.numericLiteral("2"), c.punctuation(";"), c.comment(">>>>>>> Branch - a"), - c.punctuation("}")); \ No newline at end of file + c.punctuation("}")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("property.declaration", "v"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts b/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts index 18363c0389e04..e787c832fa72a 100644 --- a/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts +++ b/tests/cases/fourslash/syntacticClassificationsConflictMarkers2.ts @@ -6,10 +6,15 @@ ////class D { } ////>>>>>>> Branch - a -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("<<<<<<< HEAD"), c.keyword("class"), c.className("C"), c.punctuation("{"), c.punctuation("}"), c.comment("======="), c.keyword("class"), c.identifier("D"), c.punctuation("{"), c.punctuation("}"), - c.comment(">>>>>>> Branch - a")); \ No newline at end of file + c.comment(">>>>>>> Branch - a")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "C"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment1.ts b/tests/cases/fourslash/syntacticClassificationsDocComment1.ts index 1ea3bf9684a61..5a0194e8c5ad2 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment1.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment1.ts @@ -3,7 +3,7 @@ //// /** @type {number} */ //// var v; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/** "), c.punctuation("@"), @@ -15,3 +15,9 @@ verify.syntacticClassificationsAre( c.keyword("var"), c.identifier("v"), c.punctuation(";")); + + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "v"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment2.ts b/tests/cases/fourslash/syntacticClassificationsDocComment2.ts index 38dca4edcf20d..d0e3eeba83645 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment2.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment2.ts @@ -4,7 +4,7 @@ //// var v; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/** "), c.punctuation("@"), @@ -24,3 +24,8 @@ verify.syntacticClassificationsAre( c.keyword("var"), c.identifier("v"), c.punctuation(";")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "v"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment3.ts b/tests/cases/fourslash/syntacticClassificationsDocComment3.ts index d7996fbbc54e5..94009e799224b 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment3.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment3.ts @@ -3,7 +3,7 @@ //// /** @param foo { number /* } */ //// var v; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/** "), c.punctuation("@"), @@ -17,3 +17,9 @@ verify.syntacticClassificationsAre( c.keyword("var"), c.identifier("v"), c.punctuation(";")); + + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "v"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsDocComment4.ts b/tests/cases/fourslash/syntacticClassificationsDocComment4.ts index d8ac2f12d8b32..ee8eaa933635c 100644 --- a/tests/cases/fourslash/syntacticClassificationsDocComment4.ts +++ b/tests/cases/fourslash/syntacticClassificationsDocComment4.ts @@ -3,7 +3,7 @@ //// /** @param {number} p1 */ //// function foo(p1) {} -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/** "), c.punctuation("@"), @@ -22,3 +22,9 @@ verify.syntacticClassificationsAre( c.punctuation(")"), c.punctuation("{"), c.punctuation("}")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("function.declaration", "foo"), + c2.semanticToken("parameter.declaration", "p1"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts index 22d7aa8ba946d..5a2354b380582 100644 --- a/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts +++ b/tests/cases/fourslash/syntacticClassificationsForOfKeyword.ts @@ -2,7 +2,7 @@ //// for (var of of of) { } -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("for"), c.punctuation("("), @@ -13,4 +13,10 @@ verify.syntacticClassificationsAre( c.punctuation(")"), c.punctuation("{"), c.punctuation("}") - ); \ No newline at end of file + ); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "of"), + c2.semanticToken("variable", "of"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts index 190663caa995e..1d8ba78579b93 100644 --- a/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts +++ b/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts @@ -2,7 +2,7 @@ //// for (var of in of) { } -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("for"), c.punctuation("("), @@ -13,4 +13,10 @@ verify.syntacticClassificationsAre( c.punctuation(")"), c.punctuation("{"), c.punctuation("}") - ); \ No newline at end of file + ); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "of"), + c2.semanticToken("variable", "of"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts index ef96c99fed45b..1e5f8481e5891 100644 --- a/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts +++ b/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts @@ -2,7 +2,7 @@ //// for (var of; of; of) { } -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("for"), c.punctuation("("), @@ -15,4 +15,11 @@ verify.syntacticClassificationsAre( c.punctuation(")"), c.punctuation("{"), c.punctuation("}") - ); \ No newline at end of file + ); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "of"), + c2.semanticToken("variable", "of"), + c2.semanticToken("variable", "of"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts b/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts index 05a5aaa173e0e..b9bde2d5df321 100644 --- a/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts +++ b/tests/cases/fourslash/syntacticClassificationsFunctionWithComments.ts @@ -16,10 +16,20 @@ var firstCommentText = * There are many like it, but this one is mine.\n\ */"; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment(firstCommentText), c.keyword("function"), c.identifier("myFunction"), c.punctuation("("), c.comment("/* x */"), c.parameterName("x"), c.punctuation(":"), c.keyword("any"), c.punctuation(")"), c.punctuation("{"), c.keyword("var"), c.identifier("y"), c.operator("="), c.identifier("x"), c.operator("?"), c.identifier("x"), c.operator("++"), c.operator(":"), c.operator("++"), c.identifier("x"), c.punctuation(";"), c.punctuation("}"), - c.comment("// end of file")); \ No newline at end of file + c.comment("// end of file")); + + const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("function.declaration", "myFunction"), + c2.semanticToken("parameter.declaration", "x"), + c2.semanticToken("variable.declaration.local", "y"), + c2.semanticToken("parameter", "x"), + c2.semanticToken("parameter", "x"), + c2.semanticToken("parameter", "x"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsJsx1.ts b/tests/cases/fourslash/syntacticClassificationsJsx1.ts index e9de07c759b7b..8e6bfc6462ec1 100644 --- a/tests/cases/fourslash/syntacticClassificationsJsx1.ts +++ b/tests/cases/fourslash/syntacticClassificationsJsx1.ts @@ -7,7 +7,7 @@ //// ////let y = -const c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("let"), c.identifier("x"), c.operator("="), c.punctuation("<"), @@ -24,4 +24,10 @@ verify.syntacticClassificationsAre( c.jsxSelfClosingTagName("element"), c.jsxAttribute("attr"), c.operator("="), c.jsxAttributeStringLiteralValue(`"123"`), c.punctuation("/"), c.punctuation(">") -) \ No newline at end of file +) + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("variable.declaration", "y"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsJsx2.ts b/tests/cases/fourslash/syntacticClassificationsJsx2.ts index 9110c6ce4b934..6c244ef4b6598 100644 --- a/tests/cases/fourslash/syntacticClassificationsJsx2.ts +++ b/tests/cases/fourslash/syntacticClassificationsJsx2.ts @@ -7,7 +7,7 @@ //// ////let y = -const c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("let"), c.identifier("x"), c.operator("="), c.punctuation("<"), @@ -24,4 +24,10 @@ verify.syntacticClassificationsAre( c.jsxSelfClosingTagName("element.name"), c.jsxAttribute("attr"), c.operator("="), c.jsxAttributeStringLiteralValue(`"123"`), c.punctuation("/"), c.punctuation(">") -) \ No newline at end of file +) + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("variable.declaration", "y"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsMergeConflictMarker1.ts b/tests/cases/fourslash/syntacticClassificationsMergeConflictMarker1.ts index b78a6f35982a6..49610740bc266 100644 --- a/tests/cases/fourslash/syntacticClassificationsMergeConflictMarker1.ts +++ b/tests/cases/fourslash/syntacticClassificationsMergeConflictMarker1.ts @@ -7,10 +7,14 @@ //// >>>>>>> Feature -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("<<<<<<< HEAD"), c.stringLiteral("\"AAAA\""), c.comment("======="), c.stringLiteral("\"BBBB\""), - c.comment(">>>>>>> Feature")); \ No newline at end of file + c.comment(">>>>>>> Feature")); + +const c2 = classification("2020"); + verify.semanticClassificationsAre("2020", +); diff --git a/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts b/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts index c5bab5181a3a7..6d5690b4d17bc 100644 --- a/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts +++ b/tests/cases/fourslash/syntacticClassificationsObjectLiteral.ts @@ -11,7 +11,7 @@ //// v: v += v, ////}; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("var"), c.identifier("v"), c.operator("="), c.numericLiteral("10e0"), c.punctuation(";"), c.keyword("var"), c.identifier("x"), c.operator("="), c.punctuation("{"), @@ -22,4 +22,19 @@ verify.syntacticClassificationsAre( c.identifier("var"), c.punctuation(":"), c.numericLiteral("5"), c.punctuation(","), c.identifier("void"), c.punctuation(":"), c.keyword("void"), c.numericLiteral("0"), c.punctuation(","), c.identifier("v"), c.punctuation(":"), c.identifier("v"), c.operator("+="), c.identifier("v"), c.punctuation(","), - c.punctuation("}"), c.punctuation(";")); \ No newline at end of file + c.punctuation("}"), c.punctuation(";")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "v"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("property.declaration", "p1"), + c2.semanticToken("property.declaration", "p2"), + c2.semanticToken("property.declaration", "any"), + c2.semanticToken("property.declaration", "function"), + c2.semanticToken("property.declaration", "var"), + c2.semanticToken("property.declaration", "void"), + c2.semanticToken("property.declaration", "v"), + c2.semanticToken("variable", "v"), + c2.semanticToken("variable", "v"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsTemplates1.ts b/tests/cases/fourslash/syntacticClassificationsTemplates1.ts index 6c27aab3f40e8..f4864d56e0b21 100644 --- a/tests/cases/fourslash/syntacticClassificationsTemplates1.ts +++ b/tests/cases/fourslash/syntacticClassificationsTemplates1.ts @@ -6,10 +6,18 @@ //// p2: `goodbye ${0} cruel ${0} world`, ////}; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("var"), c.identifier("v"), c.operator("="), c.numericLiteral("10e0"), c.punctuation(";"), c.keyword("var"), c.identifier("x"), c.operator("="), c.punctuation("{"), c.identifier("p1"), c.punctuation(":"), c.stringLiteral("`hello world`"), c.punctuation(","), c.identifier("p2"), c.punctuation(":"), c.stringLiteral("`goodbye ${"), c.numericLiteral("0"), c.stringLiteral("} cruel ${"), c.numericLiteral("0"), c.stringLiteral("} world`"), c.punctuation(","), - c.punctuation("}"), c.punctuation(";")); \ No newline at end of file + c.punctuation("}"), c.punctuation(";")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "v"), + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("property.declaration", "p1"), + c2.semanticToken("property.declaration", "p2"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsTemplates2.ts b/tests/cases/fourslash/syntacticClassificationsTemplates2.ts index 25bb64e78ba37..fc3b655d0257c 100644 --- a/tests/cases/fourslash/syntacticClassificationsTemplates2.ts +++ b/tests/cases/fourslash/syntacticClassificationsTemplates2.ts @@ -4,8 +4,13 @@ ////`goodbye "${ `hello world` }" ////and ${ `good${ " " }riddance` }`; -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.keyword("var"), c.identifier("tiredOfCanonicalExamples"), c.operator("="), c.stringLiteral("`goodbye \"${"), c.stringLiteral("`hello world`"), - c.stringLiteral("}\" \nand ${"), c.stringLiteral("`good${"), c.stringLiteral("\" \""), c.stringLiteral("}riddance`"), c.stringLiteral("}`"), c.punctuation(";")); \ No newline at end of file + c.stringLiteral("}\" \nand ${"), c.stringLiteral("`good${"), c.stringLiteral("\" \""), c.stringLiteral("}riddance`"), c.stringLiteral("}`"), c.punctuation(";")); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "tiredOfCanonicalExamples"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts index 13c27669ad5e6..daebae06adc73 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash1.ts @@ -2,7 +2,7 @@ //// /// -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/// "), c.punctuation("<"), @@ -12,4 +12,6 @@ verify.syntacticClassificationsAre( c.operator("="), c.jsxAttributeStringLiteralValue("\"./module.ts\""), c.comment(" "), - c.punctuation("/>")); \ No newline at end of file + c.punctuation("/>")); + + diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts index d1bb681b92ee9..25fd4cf0380cc 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash10.ts @@ -2,7 +2,7 @@ //// /// -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/// "), c.punctuation("<"), @@ -16,4 +16,4 @@ verify.syntacticClassificationsAre( c.operator("="), c.jsxAttributeStringLiteralValue("\"node\""), c.comment(" "), - c.punctuation("/>")); \ No newline at end of file + c.punctuation("/>")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts index 182b01f756017..877827e9753da 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash13.ts @@ -2,7 +2,7 @@ //// /// trailing -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/// "), c.punctuation("<"), @@ -13,4 +13,4 @@ verify.syntacticClassificationsAre( c.jsxAttributeStringLiteralValue("\"./module.ts\""), c.comment(" "), c.punctuation("/>"), - c.comment(" trailing")); \ No newline at end of file + c.comment(" trailing")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts index a7d16fea02ceb..197bc0d1579e7 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash14.ts @@ -2,6 +2,6 @@ //// /// nonElement -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( - c.comment("/// nonElement")); \ No newline at end of file + c.comment("/// nonElement")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts index 8ec5ebbea5d08..382fc3054a44a 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash15.ts @@ -3,7 +3,7 @@ //// /// //// /// -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/// "), c.punctuation("<"), @@ -22,4 +22,4 @@ verify.syntacticClassificationsAre( c.operator("="), c.jsxAttributeStringLiteralValue("\"./module2.ts\""), c.comment(" "), - c.punctuation("/>")); \ No newline at end of file + c.punctuation("/>")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts index 1dbee22cb594f..6315f74101341 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash16.ts @@ -3,7 +3,7 @@ //// /// //// 1 -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/// "), c.punctuation("<"), @@ -14,4 +14,4 @@ verify.syntacticClassificationsAre( c.jsxAttributeStringLiteralValue("\"./module.ts\""), c.comment(" "), c.punctuation("/>"), - c.numericLiteral("1")); \ No newline at end of file + c.numericLiteral("1")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash17.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash17.ts index b95cdd6b6c0f0..3b11eec9df11f 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash17.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash17.ts @@ -2,6 +2,6 @@ //// /// Text -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( - c.comment("/// Text")); \ No newline at end of file + c.comment("/// Text")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash18.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash18.ts index 148b17f6e4565..90dbd2b1d7678 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash18.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash18.ts @@ -2,6 +2,6 @@ //// /// Text -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( - c.comment("/// Text")); \ No newline at end of file + c.comment("/// Text")); diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts index 278d66dcb4a7f..618a5216537ba 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash2.ts @@ -2,7 +2,7 @@ //// /// -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("///"), c.punctuation("<"), @@ -13,4 +13,6 @@ verify.syntacticClassificationsAre( c.operator("="), c.comment(" "), c.jsxAttributeStringLiteralValue("\"./module.ts\""), - c.punctuation("/>")); \ No newline at end of file + c.punctuation("/>")); + + diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts index 11d3b2462be5b..1dea4b6968012 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash3.ts @@ -2,7 +2,7 @@ //// /// -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( c.comment("/// "), c.punctuation("<"), @@ -16,4 +16,6 @@ verify.syntacticClassificationsAre( c.operator("="), c.jsxAttributeStringLiteralValue("\"node\""), c.comment(" "), - c.punctuation("/>")); \ No newline at end of file + c.punctuation("/>")); + + diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts index d407bcee5032b..9d6267ecbcda1 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash4.ts @@ -2,6 +2,8 @@ //// /// < -var c = classification; +const c = classification("original"); verify.syntacticClassificationsAre( - c.comment("/// <")); // Don't classify until we recognize the element name \ No newline at end of file + c.comment("/// <")); // Don't classify until we recognize the element name + + diff --git a/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts b/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts index c6f1de38f2890..b3bab4bde6497 100644 --- a/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts +++ b/tests/cases/fourslash/syntacticClassificationsTripleSlash5.ts @@ -2,8 +2,10 @@ //// /// Date: Wed, 17 Jun 2020 12:39:39 -0400 Subject: [PATCH 04/19] Port over the semantic classification tests --- src/harness/fourslashImpl.ts | 6 ++-- ...icModernClassificationCallableVariables.ts | 31 +++++++++++++++++++ ...cModernClassificationCallableVariables2.ts | 25 +++++++++++++++ ...nticModernClassificationClassProperties.ts | 21 +++++++++++++ ...ticModernClassificationConstructorTypes.ts | 13 ++++++++ .../semanticModernClassificationFunctions.ts | 19 ++++++++++++ .../semanticModernClassificationInterfaces.ts | 21 +++++++++++++ .../semanticModernClassificationMembers.ts | 24 ++++++++++++++ ...ticModernClassificationObjectProperties.ts | 13 ++++++++ .../semanticModernClassificationVariables.ts | 19 ++++++++++++ 10 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/semanticModernClassificationCallableVariables.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationCallableVariables2.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationClassProperties.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationConstructorTypes.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationFunctions.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationInterfaces.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationMembers.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationObjectProperties.ts create mode 100644 tests/cases/fourslash/semanticModernClassificationVariables.ts diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index f051761ee44bf..3b774692cfd33 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2567,15 +2567,15 @@ namespace FourSlash { }); replacement.push(");"); - throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); + // throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); + - /** const fs = require("fs"); const testfilePath = this.originalInputFileName.slice(1); const testfile = fs.readFileSync(testfilePath, "utf8"); const newfile = testfile.replace("verify.replaceWithSemanticClassifications(\"2020\")", replacement.join("\n")); fs.writeFileSync(testfilePath, newfile); - */ + } diff --git a/tests/cases/fourslash/semanticModernClassificationCallableVariables.ts b/tests/cases/fourslash/semanticModernClassificationCallableVariables.ts new file mode 100644 index 0000000000000..c98204baf8c75 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationCallableVariables.ts @@ -0,0 +1,31 @@ +//// class A { onEvent: () => void; } +//// const x = new A().onEvent; +//// const match = (s: any) => x(); +//// const other = match; +//// match({ other }); +//// interface B = { (): string; }; var b: B +//// var s: String; +//// var t: { (): string; foo: string}; + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "A"), + c2.semanticToken("member.declaration", "onEvent"), + c2.semanticToken("function.declaration.readonly", "x"), + c2.semanticToken("class", "A"), + c2.semanticToken("member", "onEvent"), + c2.semanticToken("function.declaration.readonly", "match"), + c2.semanticToken("parameter.declaration", "s"), + c2.semanticToken("function.readonly", "x"), + c2.semanticToken("function.declaration.readonly", "other"), + c2.semanticToken("function.readonly", "match"), + c2.semanticToken("function.readonly", "match"), + c2.semanticToken("member.declaration", "other"), + c2.semanticToken("interface.declaration", "B"), + c2.semanticToken("variable.declaration", "b"), + c2.semanticToken("interface", "B"), + c2.semanticToken("variable.declaration", "s"), + c2.semanticToken("interface.defaultLibrary", "String"), + c2.semanticToken("variable.declaration", "t"), + c2.semanticToken("property.declaration", "foo"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationCallableVariables2.ts b/tests/cases/fourslash/semanticModernClassificationCallableVariables2.ts new file mode 100644 index 0000000000000..d108398c02327 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationCallableVariables2.ts @@ -0,0 +1,25 @@ +//// import "node"; +//// var fs = require("fs") +//// require.resolve('react'); +//// require.resolve.paths; +//// interface LanguageMode { getFoldingRanges?: (d: string) => number[]; }; +//// function (mode: LanguageMode | undefined) { if (mode && mode.getFoldingRanges) { return mode.getFoldingRanges('a'); }}; +//// function b(a: () => void) { a(); }; + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "fs"), + c2.semanticToken("interface.declaration", "LanguageMode"), + c2.semanticToken("member.declaration", "getFoldingRanges"), + c2.semanticToken("parameter.declaration", "d"), + c2.semanticToken("parameter.declaration", "mode"), + c2.semanticToken("interface", "LanguageMode"), + c2.semanticToken("parameter", "mode"), + c2.semanticToken("parameter", "mode"), + c2.semanticToken("member", "getFoldingRanges"), + c2.semanticToken("parameter", "mode"), + c2.semanticToken("member", "getFoldingRanges"), + c2.semanticToken("function.declaration", "b"), + c2.semanticToken("function.declaration", "a"), + c2.semanticToken("function", "a"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationClassProperties.ts b/tests/cases/fourslash/semanticModernClassificationClassProperties.ts new file mode 100644 index 0000000000000..e2c3318dc2e74 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationClassProperties.ts @@ -0,0 +1,21 @@ +//// class A { +//// private y: number; +//// constructor(public x : number, _y : number) { this.y = _y; } +//// get z() : number { return this.x + this.y; } +//// set a(v: number) { } +//// } + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "A"), + c2.semanticToken("property.declaration", "y"), + c2.semanticToken("parameter.declaration", "x"), + c2.semanticToken("parameter.declaration", "_y"), + c2.semanticToken("property", "y"), + c2.semanticToken("parameter", "_y"), + c2.semanticToken("property.declaration", "z"), + c2.semanticToken("property", "x"), + c2.semanticToken("property", "y"), + c2.semanticToken("property.declaration", "a"), + c2.semanticToken("parameter.declaration", "v"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationConstructorTypes.ts b/tests/cases/fourslash/semanticModernClassificationConstructorTypes.ts new file mode 100644 index 0000000000000..25ef45b29b628 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationConstructorTypes.ts @@ -0,0 +1,13 @@ +//// Object.create(null); +//// const x = Promise.resolve(Number.MAX_VALUE); +//// if (x instanceof Promise) {} + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.defaultLibrary", "Object"), + c2.semanticToken("member.defaultLibrary", "create"), + c2.semanticToken("variable.declaration.readonly", "x"), + c2.semanticToken("class.defaultLibrary", "Number"), + c2.semanticToken("property.readonly.defaultLibrary", "MAX_VALUE"), + c2.semanticToken("variable.readonly", "x"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationFunctions.ts b/tests/cases/fourslash/semanticModernClassificationFunctions.ts new file mode 100644 index 0000000000000..730fe9aad206c --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationFunctions.ts @@ -0,0 +1,19 @@ +//// function foo(p1) { +//// return foo(Math.abs(p1)) +//// } +//// `/${window.location}`.split("/").forEach(s => foo(s)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("function.declaration", "foo"), + c2.semanticToken("parameter.declaration", "p1"), + c2.semanticToken("function", "foo"), + c2.semanticToken("variable.defaultLibrary", "Math"), + c2.semanticToken("member.defaultLibrary", "abs"), + c2.semanticToken("parameter", "p1"), + c2.semanticToken("member.defaultLibrary", "split"), + c2.semanticToken("member.defaultLibrary", "forEach"), + c2.semanticToken("parameter.declaration", "s"), + c2.semanticToken("function", "foo"), + c2.semanticToken("parameter", "s"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationInterfaces.ts b/tests/cases/fourslash/semanticModernClassificationInterfaces.ts new file mode 100644 index 0000000000000..a2967fd213a59 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationInterfaces.ts @@ -0,0 +1,21 @@ +//// interface Pos { x: number, y: number }; +//// const p = { x: 1, y: 2 } as Pos; +//// const foo = (o: Pos) => o.x + o.y; + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("interface.declaration", "Pos"), + c2.semanticToken("property.declaration", "x"), + c2.semanticToken("property.declaration", "y"), + c2.semanticToken("variable.declaration.readonly", "p"), + c2.semanticToken("property.declaration", "x"), + c2.semanticToken("property.declaration", "y"), + c2.semanticToken("interface", "Pos"), + c2.semanticToken("function.declaration.readonly", "foo"), + c2.semanticToken("parameter.declaration", "o"), + c2.semanticToken("interface", "Pos"), + c2.semanticToken("parameter", "o"), + c2.semanticToken("property", "x"), + c2.semanticToken("parameter", "o"), + c2.semanticToken("property", "y"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationMembers.ts b/tests/cases/fourslash/semanticModernClassificationMembers.ts new file mode 100644 index 0000000000000..0492b24955f67 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationMembers.ts @@ -0,0 +1,24 @@ +//// class A { +//// static x = 9; +//// f = 9; +//// async m() { return A.x + await this.m(); }; +//// get s() { return this.f; +//// static t() { return new A().f; }; +//// constructor() {} +//// } + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "A"), + c2.semanticToken("property.declaration.static", "x"), + c2.semanticToken("property.declaration", "f"), + c2.semanticToken("member.declaration.async", "m"), + c2.semanticToken("class", "A"), + c2.semanticToken("property.static", "x"), + c2.semanticToken("member.async", "m"), + c2.semanticToken("property.declaration", "s"), + c2.semanticToken("property", "f"), + c2.semanticToken("member.declaration.static", "t"), + c2.semanticToken("class", "A"), + c2.semanticToken("property", "f"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationObjectProperties.ts b/tests/cases/fourslash/semanticModernClassificationObjectProperties.ts new file mode 100644 index 0000000000000..31dc8f30f10f4 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationObjectProperties.ts @@ -0,0 +1,13 @@ +//// let x = 1, y = 1; +//// const a1 = { e: 1 }; +//// var a2 = { x }; + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("variable.declaration", "y"), + c2.semanticToken("variable.declaration.readonly", "a1"), + c2.semanticToken("property.declaration", "e"), + c2.semanticToken("variable.declaration", "a2"), + c2.semanticToken("property.declaration", "x"), +);; \ No newline at end of file diff --git a/tests/cases/fourslash/semanticModernClassificationVariables.ts b/tests/cases/fourslash/semanticModernClassificationVariables.ts new file mode 100644 index 0000000000000..6c4e9c1567187 --- /dev/null +++ b/tests/cases/fourslash/semanticModernClassificationVariables.ts @@ -0,0 +1,19 @@ +//// var x = 9, y1 = [x]; +//// try { +//// for (const s of y1) { x = s } +//// } catch (e) { +//// throw y1; +//// } + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("variable.declaration", "x"), + c2.semanticToken("variable.declaration", "y1"), + c2.semanticToken("variable", "x"), + c2.semanticToken("variable.declaration.readonly.local", "s"), + c2.semanticToken("variable", "y1"), + c2.semanticToken("variable", "x"), + c2.semanticToken("variable.readonly.local", "s"), + c2.semanticToken("variable.declaration.local", "e"), + c2.semanticToken("variable", "y1"), +);; \ No newline at end of file From 8728a1e5c84003222dcab6a7230ae628f092bf99 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Fri, 19 Jun 2020 07:52:41 -0400 Subject: [PATCH 05/19] Update baselines --- .../reference/api/tsserverlibrary.d.ts | 27 ++++++++++++++++--- tests/baselines/reference/api/typescript.d.ts | 27 ++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 83b03093da4b0..f9ab007e35e3c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3733,6 +3733,10 @@ declare namespace ts { span: TextSpan; newLength: number; } + export enum SemanticClassificationFormat { + Original = "original", + TwentyTwenty = "2020" + } export interface SyntaxList extends Node { kind: SyntaxKind.SyntaxList; _children: Node[]; @@ -5400,11 +5404,21 @@ declare namespace ts { */ getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; - getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications; + /** + * Gets semantic highlights information for a particular file. Has two formats, an older + * version used by VS and a format used by VS Code. + * + * @param fileName The path to the file + * @param position A text span to return results within + * @param format Which format to use, defaults to "original" + * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. + */ + getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications; /** * Gets completion entries at a particular position in a file. * @@ -5557,7 +5571,7 @@ declare namespace ts { } interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames; + classificationType: ClassificationTypeNames | number; } /** * Navigation bar interface designed for visual studio's dual-column layout. @@ -6219,6 +6233,11 @@ declare namespace ts { /** The classifier is used for syntactic highlighting in editors via the TSServer */ function createClassifier(): Classifier; } +declare namespace ts.classifier.vscode { + /** This is mainly used internally for testing */ + function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[]; + function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications; +} declare namespace ts { interface DocumentHighlights { fileName: string; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e85e4a8bf70b2..3d8ffc4478d00 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3733,6 +3733,10 @@ declare namespace ts { span: TextSpan; newLength: number; } + export enum SemanticClassificationFormat { + Original = "original", + TwentyTwenty = "2020" + } export interface SyntaxList extends Node { kind: SyntaxKind.SyntaxList; _children: Node[]; @@ -5400,11 +5404,21 @@ declare namespace ts { */ getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; - getEncodedSemanticClassifications(fileName: string, span: TextSpan): Classifications; + /** + * Gets semantic highlights information for a particular file. Has two formats, an older + * version used by VS and a format used by VS Code. + * + * @param fileName The path to the file + * @param position A text span to return results within + * @param format Which format to use, defaults to "original" + * @returns a number array encoded as triples of [start, length, ClassificationType, ...]. + */ + getEncodedSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): Classifications; /** * Gets completion entries at a particular position in a file. * @@ -5557,7 +5571,7 @@ declare namespace ts { } interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames; + classificationType: ClassificationTypeNames | number; } /** * Navigation bar interface designed for visual studio's dual-column layout. @@ -6219,6 +6233,11 @@ declare namespace ts { /** The classifier is used for syntactic highlighting in editors via the TSServer */ function createClassifier(): Classifier; } +declare namespace ts.classifier.vscode { + /** This is mainly used internally for testing */ + function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[]; + function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications; +} declare namespace ts { interface DocumentHighlights { fileName: string; From 78ad1d73fb67dbada9ae94a36a3fe0a0460af2a2 Mon Sep 17 00:00:00 2001 From: Orta Date: Mon, 22 Jun 2020 15:06:26 -0400 Subject: [PATCH 06/19] Update src/harness/fourslashImpl.ts Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> --- src/harness/fourslashImpl.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 3b774692cfd33..2f490205dc42c 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2487,8 +2487,7 @@ namespace FourSlash { const typeIdx = getTokenTypeFromClassification(classification) || 0; const modSet = getTokenModifierFromClassification(classification); - const tokenClassifiction = [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join("."); - return tokenClassifiction; + return [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join("."); } private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) { From c43374b321658e10ef0973fbc7bb1595df93eab8 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 22 Jun 2020 15:33:19 -0400 Subject: [PATCH 07/19] Handle feedback from #39119 --- src/compiler/types.ts | 5 -- src/harness/fourslashImpl.ts | 56 +++++++++---------- ...{classifierVscode.ts => classifier2020.ts} | 3 +- src/services/services.ts | 4 +- src/services/tsconfig.json | 2 +- src/services/types.ts | 5 ++ 6 files changed, 37 insertions(+), 38 deletions(-) rename src/services/{classifierVscode.ts => classifier2020.ts} (96%) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4473e494d4357..2472b302545cc 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7764,11 +7764,6 @@ namespace ts { newLength: number; } - export const enum SemanticClassificationFormat { - Original = "original", - TwentyTwenty = "2020" - } - /* @internal */ export interface DiagnosticCollection { // Adds a diagnostic to this diagnostic collection. diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 2f490205dc42c..26f11cab3c747 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2451,37 +2451,37 @@ namespace FourSlash { private classificationToIdentifier(classification: number){ const tokenTypes: string[] = []; - tokenTypes[ts.classifier.vscode.TokenType.class] = "class"; - tokenTypes[ts.classifier.vscode.TokenType.enum] = "enum"; - tokenTypes[ts.classifier.vscode.TokenType.interface] = "interface"; - tokenTypes[ts.classifier.vscode.TokenType.namespace] = "namespace"; - tokenTypes[ts.classifier.vscode.TokenType.typeParameter] = "typeParameter"; - tokenTypes[ts.classifier.vscode.TokenType.type] = "type"; - tokenTypes[ts.classifier.vscode.TokenType.parameter] = "parameter"; - tokenTypes[ts.classifier.vscode.TokenType.variable] = "variable"; - tokenTypes[ts.classifier.vscode.TokenType.enumMember] = "enumMember"; - tokenTypes[ts.classifier.vscode.TokenType.property] = "property"; - tokenTypes[ts.classifier.vscode.TokenType.function] = "function"; - tokenTypes[ts.classifier.vscode.TokenType.member] = "member"; + tokenTypes[ts.classifier.modern.TokenType.class] = "class"; + tokenTypes[ts.classifier.modern.TokenType.enum] = "enum"; + tokenTypes[ts.classifier.modern.TokenType.interface] = "interface"; + tokenTypes[ts.classifier.modern.TokenType.namespace] = "namespace"; + tokenTypes[ts.classifier.modern.TokenType.typeParameter] = "typeParameter"; + tokenTypes[ts.classifier.modern.TokenType.type] = "type"; + tokenTypes[ts.classifier.modern.TokenType.parameter] = "parameter"; + tokenTypes[ts.classifier.modern.TokenType.variable] = "variable"; + tokenTypes[ts.classifier.modern.TokenType.enumMember] = "enumMember"; + tokenTypes[ts.classifier.modern.TokenType.property] = "property"; + tokenTypes[ts.classifier.modern.TokenType.function] = "function"; + tokenTypes[ts.classifier.modern.TokenType.member] = "member"; const tokenModifiers: string[] = []; - tokenModifiers[ts.classifier.vscode.TokenModifier.async] = "async"; - tokenModifiers[ts.classifier.vscode.TokenModifier.declaration] = "declaration"; - tokenModifiers[ts.classifier.vscode.TokenModifier.readonly] = "readonly"; - tokenModifiers[ts.classifier.vscode.TokenModifier.static] = "static"; - tokenModifiers[ts.classifier.vscode.TokenModifier.local] = "local"; - tokenModifiers[ts.classifier.vscode.TokenModifier.defaultLibrary] = "defaultLibrary"; + tokenModifiers[ts.classifier.modern.TokenModifier.async] = "async"; + tokenModifiers[ts.classifier.modern.TokenModifier.declaration] = "declaration"; + tokenModifiers[ts.classifier.modern.TokenModifier.readonly] = "readonly"; + tokenModifiers[ts.classifier.modern.TokenModifier.static] = "static"; + tokenModifiers[ts.classifier.modern.TokenModifier.local] = "local"; + tokenModifiers[ts.classifier.modern.TokenModifier.defaultLibrary] = "defaultLibrary"; function getTokenTypeFromClassification(tsClassification: number): number | undefined { - if (tsClassification > ts.classifier.vscode.TokenEncodingConsts.modifierMask) { - return (tsClassification >> ts.classifier.vscode.TokenEncodingConsts.typeOffset) - 1; + if (tsClassification > ts.classifier.modern.TokenEncodingConsts.modifierMask) { + return (tsClassification >> ts.classifier.modern.TokenEncodingConsts.typeOffset) - 1; } return undefined; } function getTokenModifierFromClassification(tsClassification: number) { - return tsClassification & ts.classifier.vscode.TokenEncodingConsts.modifierMask; + return tsClassification & ts.classifier.modern.TokenEncodingConsts.modifierMask; } const typeIdx = getTokenTypeFromClassification(classification) || 0; @@ -2566,15 +2566,13 @@ namespace FourSlash { }); replacement.push(");"); - // throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); - - - const fs = require("fs"); - const testfilePath = this.originalInputFileName.slice(1); - const testfile = fs.readFileSync(testfilePath, "utf8"); - const newfile = testfile.replace("verify.replaceWithSemanticClassifications(\"2020\")", replacement.join("\n")); - fs.writeFileSync(testfilePath, newfile); + throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); + // const fs = require("fs"); + // const testfilePath = this.originalInputFileName.slice(1); + // const testfile = fs.readFileSync(testfilePath, "utf8"); + // const newfile = testfile.replace("verify.replaceWithSemanticClassifications(\"2020\")", replacement.join("\n")); + // fs.writeFileSync(testfilePath, newfile); } diff --git a/src/services/classifierVscode.ts b/src/services/classifier2020.ts similarity index 96% rename from src/services/classifierVscode.ts rename to src/services/classifier2020.ts index 2d3a382cc9574..f8f02c13b2bcb 100644 --- a/src/services/classifierVscode.ts +++ b/src/services/classifier2020.ts @@ -1,4 +1,5 @@ -namespace ts.classifier.vscode { +/** @internal */ +namespace ts.classifier.modern { /** @internal */ export enum TokenEncodingConsts { diff --git a/src/services/services.ts b/src/services/services.ts index 9939bdc787363..c287b06a6cd17 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1809,7 +1809,7 @@ namespace ts { return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } else { - return classifier.vscode.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier.modern.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } @@ -1825,7 +1825,7 @@ namespace ts { return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } else { - return classifier.vscode.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier.modern.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index ded83472433dc..42e153e45dd28 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -12,7 +12,7 @@ "types.ts", "utilities.ts", "classifier.ts", - "classifierVscode.ts", + "classifier2020.ts", "stringCompletions.ts", "completions.ts", "documentHighlights.ts", diff --git a/src/services/types.ts b/src/services/types.ts index 5d53fc9a666ee..581b70aef15f2 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -313,6 +313,11 @@ namespace ts { export type WithMetadata = T & { metadata?: unknown; }; + export const enum SemanticClassificationFormat { + Original = "original", + TwentyTwenty = "2020" + } + // // Public services of a language service instance associated // with a language service host instance From 40e5d223546a7a4f28b5a6388efc82610b3e15d5 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 22 Jun 2020 15:34:03 -0400 Subject: [PATCH 08/19] Consistent formatting in the 2020 classifier --- src/services/classifier2020.ts | 426 ++++++++++++++++----------------- 1 file changed, 213 insertions(+), 213 deletions(-) diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index f8f02c13b2bcb..5a482f47fe216 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -1,257 +1,257 @@ /** @internal */ namespace ts.classifier.modern { - /** @internal */ - export enum TokenEncodingConsts { - typeOffset = 8, - modifierMask = (1 << typeOffset) - 1 - } + /** @internal */ + export enum TokenEncodingConsts { + typeOffset = 8, + modifierMask = (1 << typeOffset) - 1 + } - /** @internal */ - export enum TokenType { - class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ - } + /** @internal */ + export enum TokenType { + class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ + } - /** @internal */ - export enum TokenModifier { - declaration, static, async, readonly, defaultLibrary, local, _ - } + /** @internal */ + export enum TokenModifier { + declaration, static, async, readonly, defaultLibrary, local, _ + } - /** This is mainly used internally for testing */ - export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { - const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span); + /** This is mainly used internally for testing */ + export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { + const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span); - Debug.assert(classifications.spans.length % 3 === 0); - const dense = classifications.spans; - const result: ClassifiedSpan[] = []; - for (let i = 0; i < dense.length; i += 3) { - result.push({ - textSpan: createTextSpan(dense[i], dense[i + 1]), - classificationType: dense[i + 2] - }); - } + Debug.assert(classifications.spans.length % 3 === 0); + const dense = classifications.spans; + const result: ClassifiedSpan[] = []; + for (let i = 0; i < dense.length; i += 3) { + result.push({ + textSpan: createTextSpan(dense[i], dense[i + 1]), + classificationType: dense[i + 2] + }); + } - return result; - } + return result; + } - export function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { - return { - spans: getSemanticTokens(program, sourceFile, span), - endOfLineState: EndOfLineState.None - }; - } + export function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { + return { + spans: getSemanticTokens(program, sourceFile, span), + endOfLineState: EndOfLineState.None + }; + } - function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan): number[] { - const resultTokens: number[] = []; + function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan): number[] { + const resultTokens: number[] = []; - const collector = (node: Node, typeIdx: number, modifierSet: number) => { - resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); - }; + const collector = (node: Node, typeIdx: number, modifierSet: number) => { + resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); + }; - if (program && sourceFile) { - collectTokens(program, sourceFile, span, collector); + if (program && sourceFile) { + collectTokens(program, sourceFile, span, collector); + } + return resultTokens; } - return resultTokens; - } - - function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void) { - const typeChecker = program.getTypeChecker(); - let inJSXElement = false; + function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void) { + const typeChecker = program.getTypeChecker(); - function visit(node: Node) { - if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { - return; - } - const prevInJSXElement = inJSXElement; - if (isJsxElement(node) || isJsxSelfClosingElement(node)) { - inJSXElement = true; - } - if (isJsxExpression(node)) { - inJSXElement = false; - } + let inJSXElement = false; - if (isIdentifier(node) && !inJSXElement && !inImportClause(node)) { - let symbol = typeChecker.getSymbolAtLocation(node); - if (symbol) { - if (symbol.flags & SymbolFlags.Alias) { - symbol = typeChecker.getAliasedSymbol(symbol); - } - let typeIdx = classifySymbol(symbol, getMeaningFromLocation(node)); - if (typeIdx !== undefined) { - let modifierSet = 0; - if (node.parent) { - const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); - if (parentIsDeclaration && (node.parent).name === node) { - modifierSet = 1 << TokenModifier.declaration; - } + function visit(node: Node) { + if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { + return; } - - // property declaration in constructor - if (typeIdx === TokenType.parameter && isRightSideOfQualifiedNameOrPropertyAccess(node)) { - typeIdx = TokenType.property; + const prevInJSXElement = inJSXElement; + if (isJsxElement(node) || isJsxSelfClosingElement(node)) { + inJSXElement = true; + } + if (isJsxExpression(node)) { + inJSXElement = false; } - typeIdx = reclassifyByType(typeChecker, node, typeIdx); + if (isIdentifier(node) && !inJSXElement && !inImportClause(node)) { + let symbol = typeChecker.getSymbolAtLocation(node); + if (symbol) { + if (symbol.flags & SymbolFlags.Alias) { + symbol = typeChecker.getAliasedSymbol(symbol); + } + let typeIdx = classifySymbol(symbol, getMeaningFromLocation(node)); + if (typeIdx !== undefined) { + let modifierSet = 0; + if (node.parent) { + const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); + if (parentIsDeclaration && (node.parent).name === node) { + modifierSet = 1 << TokenModifier.declaration; + } + } + + // property declaration in constructor + if (typeIdx === TokenType.parameter && isRightSideOfQualifiedNameOrPropertyAccess(node)) { + typeIdx = TokenType.property; + } + + typeIdx = reclassifyByType(typeChecker, node, typeIdx); - const decl = symbol.valueDeclaration; - if (decl) { - const modifiers = getCombinedModifierFlags(decl); - const nodeFlags = getCombinedNodeFlags(decl); - if (modifiers & ModifierFlags.Static) { - modifierSet |= 1 << TokenModifier.static; - } - if (modifiers & ModifierFlags.Async) { - modifierSet |= 1 << TokenModifier.async; - } - if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { - if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { - modifierSet |= 1 << TokenModifier.readonly; + const decl = symbol.valueDeclaration; + if (decl) { + const modifiers = getCombinedModifierFlags(decl); + const nodeFlags = getCombinedNodeFlags(decl); + if (modifiers & ModifierFlags.Static) { + modifierSet |= 1 << TokenModifier.static; + } + if (modifiers & ModifierFlags.Async) { + modifierSet |= 1 << TokenModifier.async; + } + if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { + if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (symbol.getFlags() & SymbolFlags.EnumMember)) { + modifierSet |= 1 << TokenModifier.readonly; + } + } + if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { + modifierSet |= 1 << TokenModifier.local; + } + if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + } + else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + + collector(node, typeIdx, modifierSet); + + } } - } - if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { - modifierSet |= 1 << TokenModifier.local; - } - if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { - modifierSet |= 1 << TokenModifier.defaultLibrary; - } - } - else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { - modifierSet |= 1 << TokenModifier.defaultLibrary; } + forEachChild(node, visit); - collector(node, typeIdx, modifierSet); - - } + inJSXElement = prevInJSXElement; } - } - forEachChild(node, visit); - - inJSXElement = prevInJSXElement; + visit(sourceFile); } - visit(sourceFile); - } - function classifySymbol(symbol: Symbol, meaning: SemanticMeaning): TokenType | undefined { - const flags = symbol.getFlags(); - if (flags & SymbolFlags.Class) { - return TokenType.class; - } - else if (flags & SymbolFlags.Enum) { - return TokenType.enum; - } - else if (flags & SymbolFlags.TypeAlias) { - return TokenType.type; - } - else if (flags & SymbolFlags.Interface) { - if (meaning & SemanticMeaning.Type) { - return TokenType.interface; - } - } - else if (flags & SymbolFlags.TypeParameter) { - return TokenType.typeParameter; + function classifySymbol(symbol: Symbol, meaning: SemanticMeaning): TokenType | undefined { + const flags = symbol.getFlags(); + if (flags & SymbolFlags.Class) { + return TokenType.class; + } + else if (flags & SymbolFlags.Enum) { + return TokenType.enum; + } + else if (flags & SymbolFlags.TypeAlias) { + return TokenType.type; + } + else if (flags & SymbolFlags.Interface) { + if (meaning & SemanticMeaning.Type) { + return TokenType.interface; + } + } + else if (flags & SymbolFlags.TypeParameter) { + return TokenType.typeParameter; + } + let decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; + if (decl && isBindingElement(decl)) { + decl = getDeclarationForBindingElement(decl); + } + return decl && tokenFromDeclarationMapping[decl.kind]; } - let decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; - if (decl && isBindingElement(decl)) { - decl = getDeclarationForBindingElement(decl); + + function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenType): TokenType { + // type based classifications + if (typeIdx === TokenType.variable || typeIdx === TokenType.property || typeIdx === TokenType.parameter) { + const type = typeChecker.getTypeAtLocation(node); + if (type) { + const test = (condition: (type: Type) => boolean) => { + return condition(type) || type.isUnion() && type.types.some(condition); + }; + if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { + return TokenType.class; + } + if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { + return typeIdx === TokenType.property ? TokenType.member : TokenType.function; + } + } + } + return typeIdx; } - return decl && tokenFromDeclarationMapping[decl.kind]; - } - function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenType): TokenType { - // type based classifications - if (typeIdx === TokenType.variable || typeIdx === TokenType.property || typeIdx === TokenType.parameter) { - const type = typeChecker.getTypeAtLocation(node); - if (type) { - const test = (condition: (type: Type) => boolean) => { - return condition(type) || type.isUnion() && type.types.some(condition); - }; - if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { - return TokenType.class; + function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean { + if (isBindingElement(decl)) { + decl = getDeclarationForBindingElement(decl); } - if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { - return typeIdx === TokenType.property ? TokenType.member : TokenType.function; + if (isVariableDeclaration(decl)) { + return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; } - } + else if (isFunctionDeclaration(decl)) { + return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; + } + return false; } - return typeIdx; - } - function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean { - if (isBindingElement(decl)) { - decl = getDeclarationForBindingElement(decl); - } - if (isVariableDeclaration(decl)) { - return (!isSourceFile(decl.parent.parent.parent) || isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; - } - else if (isFunctionDeclaration(decl)) { - return !isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; + function getDeclarationForBindingElement(element: BindingElement): VariableDeclaration | ParameterDeclaration { + while (true) { + if (isBindingElement(element.parent.parent)) { + element = element.parent.parent; + } + else { + return element.parent.parent; + } + } } - return false; - } - function getDeclarationForBindingElement(element: BindingElement): VariableDeclaration | ParameterDeclaration { - while (true) { - if (isBindingElement(element.parent.parent)) { - element = element.parent.parent; - } - else { - return element.parent.parent; - } + function inImportClause(node: Node): boolean { + const parent = node.parent; + return parent && (isImportClause(parent) || isImportSpecifier(parent) || isNamespaceImport(parent)); } - } - function inImportClause(node: Node): boolean { - const parent = node.parent; - return parent && (isImportClause(parent) || isImportSpecifier(parent) || isNamespaceImport(parent)); - } - - function isExpressionInCallExpression(node: Node): boolean { - while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { - node = node.parent; + function isExpressionInCallExpression(node: Node): boolean { + while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { + node = node.parent; + } + return isCallExpression(node.parent) && node.parent.expression === node; } - return isCallExpression(node.parent) && node.parent.expression === node; - } - function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { - return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); - } + function isRightSideOfQualifiedNameOrPropertyAccess(node: Node): boolean { + return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); + } - const enum SemanticMeaning { - None = 0x0, - Value = 0x1, - Type = 0x2, - Namespace = 0x4, - All = Value | Type | Namespace - } + const enum SemanticMeaning { + None = 0x0, + Value = 0x1, + Type = 0x2, + Namespace = 0x4, + All = Value | Type | Namespace + } - function getMeaningFromLocation(node: Node): SemanticMeaning { - const f = (ts).getMeaningFromLocation; - if (typeof f === "function") { - return f(node); + function getMeaningFromLocation(node: Node): SemanticMeaning { + const f = (ts).getMeaningFromLocation; + if (typeof f === "function") { + return f(node); + } + return SemanticMeaning.All; } - return SemanticMeaning.All; - } - const tokenFromDeclarationMapping: { [name: string]: TokenType } = { - [SyntaxKind.VariableDeclaration]: TokenType.variable, - [SyntaxKind.Parameter]: TokenType.parameter, - [SyntaxKind.PropertyDeclaration]: TokenType.property, - [SyntaxKind.ModuleDeclaration]: TokenType.namespace, - [SyntaxKind.EnumDeclaration]: TokenType.enum, - [SyntaxKind.EnumMember]: TokenType.enumMember, - [SyntaxKind.ClassDeclaration]: TokenType.class, - [SyntaxKind.MethodDeclaration]: TokenType.member, - [SyntaxKind.FunctionDeclaration]: TokenType.function, - [SyntaxKind.FunctionExpression]: TokenType.function, - [SyntaxKind.MethodSignature]: TokenType.member, - [SyntaxKind.GetAccessor]: TokenType.property, - [SyntaxKind.SetAccessor]: TokenType.property, - [SyntaxKind.PropertySignature]: TokenType.property, - [SyntaxKind.InterfaceDeclaration]: TokenType.interface, - [SyntaxKind.TypeAliasDeclaration]: TokenType.type, - [SyntaxKind.TypeParameter]: TokenType.typeParameter, - [SyntaxKind.PropertyAssignment]: TokenType.property, - [SyntaxKind.ShorthandPropertyAssignment]: TokenType.property - }; + const tokenFromDeclarationMapping: { [name: string]: TokenType } = { + [SyntaxKind.VariableDeclaration]: TokenType.variable, + [SyntaxKind.Parameter]: TokenType.parameter, + [SyntaxKind.PropertyDeclaration]: TokenType.property, + [SyntaxKind.ModuleDeclaration]: TokenType.namespace, + [SyntaxKind.EnumDeclaration]: TokenType.enum, + [SyntaxKind.EnumMember]: TokenType.enumMember, + [SyntaxKind.ClassDeclaration]: TokenType.class, + [SyntaxKind.MethodDeclaration]: TokenType.member, + [SyntaxKind.FunctionDeclaration]: TokenType.function, + [SyntaxKind.FunctionExpression]: TokenType.function, + [SyntaxKind.MethodSignature]: TokenType.member, + [SyntaxKind.GetAccessor]: TokenType.property, + [SyntaxKind.SetAccessor]: TokenType.property, + [SyntaxKind.PropertySignature]: TokenType.property, + [SyntaxKind.InterfaceDeclaration]: TokenType.interface, + [SyntaxKind.TypeAliasDeclaration]: TokenType.type, + [SyntaxKind.TypeParameter]: TokenType.typeParameter, + [SyntaxKind.PropertyAssignment]: TokenType.property, + [SyntaxKind.ShorthandPropertyAssignment]: TokenType.property + }; } From 524e475f5e83a553a39f8e479dfb85a5b6232e3f Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Mon, 22 Jun 2020 15:46:46 -0400 Subject: [PATCH 09/19] Update baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 13 ++++--------- tests/baselines/reference/api/typescript.d.ts | 13 ++++--------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index f9ab007e35e3c..fa01cf888ac00 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3733,10 +3733,6 @@ declare namespace ts { span: TextSpan; newLength: number; } - export enum SemanticClassificationFormat { - Original = "original", - TwentyTwenty = "2020" - } export interface SyntaxList extends Node { kind: SyntaxKind.SyntaxList; _children: Node[]; @@ -5354,6 +5350,10 @@ declare namespace ts { type WithMetadata = T & { metadata?: unknown; }; + enum SemanticClassificationFormat { + Original = "original", + TwentyTwenty = "2020" + } interface LanguageService { /** This is used as a part of restarting the language service. */ cleanupSemanticCache(): void; @@ -6233,11 +6233,6 @@ declare namespace ts { /** The classifier is used for syntactic highlighting in editors via the TSServer */ function createClassifier(): Classifier; } -declare namespace ts.classifier.vscode { - /** This is mainly used internally for testing */ - function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[]; - function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications; -} declare namespace ts { interface DocumentHighlights { fileName: string; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 3d8ffc4478d00..83207156815e1 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3733,10 +3733,6 @@ declare namespace ts { span: TextSpan; newLength: number; } - export enum SemanticClassificationFormat { - Original = "original", - TwentyTwenty = "2020" - } export interface SyntaxList extends Node { kind: SyntaxKind.SyntaxList; _children: Node[]; @@ -5354,6 +5350,10 @@ declare namespace ts { type WithMetadata = T & { metadata?: unknown; }; + enum SemanticClassificationFormat { + Original = "original", + TwentyTwenty = "2020" + } interface LanguageService { /** This is used as a part of restarting the language service. */ cleanupSemanticCache(): void; @@ -6233,11 +6233,6 @@ declare namespace ts { /** The classifier is used for syntactic highlighting in editors via the TSServer */ function createClassifier(): Classifier; } -declare namespace ts.classifier.vscode { - /** This is mainly used internally for testing */ - function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[]; - function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications; -} declare namespace ts { interface DocumentHighlights { fileName: string; From e1ce70924d777910b1ec42d070f02f9588fc13a5 Mon Sep 17 00:00:00 2001 From: Orta Date: Tue, 23 Jun 2020 10:57:19 -0400 Subject: [PATCH 10/19] Apply suggestions from code review Co-authored-by: Daniel Rosenwasser --- src/services/classifier2020.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index 5a482f47fe216..2df3cf3e0a243 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -2,18 +2,19 @@ namespace ts.classifier.modern { /** @internal */ - export enum TokenEncodingConsts { + export const enum TokenEncodingConsts { + typeOffset = 8, modifierMask = (1 << typeOffset) - 1 } /** @internal */ - export enum TokenType { + export const enum TokenType { class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ } /** @internal */ - export enum TokenModifier { + export const enum TokenModifier { declaration, static, async, readonly, defaultLibrary, local, _ } @@ -49,7 +50,7 @@ namespace ts.classifier.modern { }; if (program && sourceFile) { - collectTokens(program, sourceFile, span, collector); + collectTokens(program, sourceFile, span, collector); } return resultTokens; } From 7e35e534d822137d8e4c5c84dd2147998b972e4c Mon Sep 17 00:00:00 2001 From: Orta Date: Tue, 23 Jun 2020 11:01:25 -0400 Subject: [PATCH 11/19] Update src/harness/fourslashImpl.ts Co-authored-by: Daniel Rosenwasser --- src/harness/fourslashImpl.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 26f11cab3c747..1a61e25c33850 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2559,7 +2559,7 @@ namespace FourSlash { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); const replacement = [`const c2 = classification("2020");`,`verify.semanticClassificationsAre("2020",`]; - actual.forEach(a => { + for (const a of actual) { const identifier = this.classificationToIdentifier(a.classificationType as number); const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length); replacement.push(` c2.semanticToken("${identifier}", "${text}"), `); From 8a7596a2ee8af73232cc4a235665ff361e490382 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 23 Jun 2020 11:36:11 -0400 Subject: [PATCH 12/19] Reafactor after comments --- src/harness/fourslashImpl.ts | 2 +- src/services/classifier2020.ts | 15 +++++++-------- src/services/services.ts | 6 +++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 1a61e25c33850..f2a17d4eee58d 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2563,7 +2563,7 @@ namespace FourSlash { const identifier = this.classificationToIdentifier(a.classificationType as number); const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length); replacement.push(` c2.semanticToken("${identifier}", "${text}"), `); - }); + }; replacement.push(");"); throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications"); diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index 2df3cf3e0a243..adbac20b3e7e6 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -3,19 +3,18 @@ namespace ts.classifier.modern { /** @internal */ export const enum TokenEncodingConsts { - typeOffset = 8, modifierMask = (1 << typeOffset) - 1 } /** @internal */ export const enum TokenType { - class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ + class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member } /** @internal */ export const enum TokenModifier { - declaration, static, async, readonly, defaultLibrary, local, _ + declaration, static, async, readonly, defaultLibrary, local } /** This is mainly used internally for testing */ @@ -26,10 +25,10 @@ namespace ts.classifier.modern { const dense = classifications.spans; const result: ClassifiedSpan[] = []; for (let i = 0; i < dense.length; i += 3) { - result.push({ - textSpan: createTextSpan(dense[i], dense[i + 1]), - classificationType: dense[i + 2] - }); + result.push({ + textSpan: createTextSpan(dense[i], dense[i + 1]), + classificationType: dense[i + 2] + }); } return result; @@ -46,7 +45,7 @@ namespace ts.classifier.modern { const resultTokens: number[] = []; const collector = (node: Node, typeIdx: number, modifierSet: number) => { - resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); + resultTokens.push(node.getStart(sourceFile), node.getWidth(sourceFile), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); }; if (program && sourceFile) { diff --git a/src/services/services.ts b/src/services/services.ts index c287b06a6cd17..f29acb01100af 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1805,11 +1805,11 @@ namespace ts { synchronizeHostData(); const responseFormat = format || SemanticClassificationFormat.Original; - if (responseFormat === SemanticClassificationFormat.Original) { - return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + if (responseFormat === SemanticClassificationFormat.TwentyTwenty) { + return classifier.modern.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } else { - return classifier.modern.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } } From b8742c30f97aa497777c6db2084725b1c369aa9c Mon Sep 17 00:00:00 2001 From: Orta Date: Mon, 6 Jul 2020 13:01:34 -0400 Subject: [PATCH 13/19] Use 2020 everywhere --- src/harness/fourslashImpl.ts | 42 +++++++++++++-------------- src/harness/fourslashInterfaceImpl.ts | 14 +++++++-- src/services/classifier2020.ts | 2 +- src/services/services.ts | 4 +-- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index f2a17d4eee58d..628181c8f0f28 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2451,37 +2451,37 @@ namespace FourSlash { private classificationToIdentifier(classification: number){ const tokenTypes: string[] = []; - tokenTypes[ts.classifier.modern.TokenType.class] = "class"; - tokenTypes[ts.classifier.modern.TokenType.enum] = "enum"; - tokenTypes[ts.classifier.modern.TokenType.interface] = "interface"; - tokenTypes[ts.classifier.modern.TokenType.namespace] = "namespace"; - tokenTypes[ts.classifier.modern.TokenType.typeParameter] = "typeParameter"; - tokenTypes[ts.classifier.modern.TokenType.type] = "type"; - tokenTypes[ts.classifier.modern.TokenType.parameter] = "parameter"; - tokenTypes[ts.classifier.modern.TokenType.variable] = "variable"; - tokenTypes[ts.classifier.modern.TokenType.enumMember] = "enumMember"; - tokenTypes[ts.classifier.modern.TokenType.property] = "property"; - tokenTypes[ts.classifier.modern.TokenType.function] = "function"; - tokenTypes[ts.classifier.modern.TokenType.member] = "member"; + tokenTypes[ts.classifier.v2020.TokenType.class] = "class"; + tokenTypes[ts.classifier.v2020.TokenType.enum] = "enum"; + tokenTypes[ts.classifier.v2020.TokenType.interface] = "interface"; + tokenTypes[ts.classifier.v2020.TokenType.namespace] = "namespace"; + tokenTypes[ts.classifier.v2020.TokenType.typeParameter] = "typeParameter"; + tokenTypes[ts.classifier.v2020.TokenType.type] = "type"; + tokenTypes[ts.classifier.v2020.TokenType.parameter] = "parameter"; + tokenTypes[ts.classifier.v2020.TokenType.variable] = "variable"; + tokenTypes[ts.classifier.v2020.TokenType.enumMember] = "enumMember"; + tokenTypes[ts.classifier.v2020.TokenType.property] = "property"; + tokenTypes[ts.classifier.v2020.TokenType.function] = "function"; + tokenTypes[ts.classifier.v2020.TokenType.member] = "member"; const tokenModifiers: string[] = []; - tokenModifiers[ts.classifier.modern.TokenModifier.async] = "async"; - tokenModifiers[ts.classifier.modern.TokenModifier.declaration] = "declaration"; - tokenModifiers[ts.classifier.modern.TokenModifier.readonly] = "readonly"; - tokenModifiers[ts.classifier.modern.TokenModifier.static] = "static"; - tokenModifiers[ts.classifier.modern.TokenModifier.local] = "local"; - tokenModifiers[ts.classifier.modern.TokenModifier.defaultLibrary] = "defaultLibrary"; + tokenModifiers[ts.classifier.v2020.TokenModifier.async] = "async"; + tokenModifiers[ts.classifier.v2020.TokenModifier.declaration] = "declaration"; + tokenModifiers[ts.classifier.v2020.TokenModifier.readonly] = "readonly"; + tokenModifiers[ts.classifier.v2020.TokenModifier.static] = "static"; + tokenModifiers[ts.classifier.v2020.TokenModifier.local] = "local"; + tokenModifiers[ts.classifier.v2020.TokenModifier.defaultLibrary] = "defaultLibrary"; function getTokenTypeFromClassification(tsClassification: number): number | undefined { - if (tsClassification > ts.classifier.modern.TokenEncodingConsts.modifierMask) { - return (tsClassification >> ts.classifier.modern.TokenEncodingConsts.typeOffset) - 1; + if (tsClassification > ts.classifier.v2020.TokenEncodingConsts.modifierMask) { + return (tsClassification >> ts.classifier.v2020.TokenEncodingConsts.typeOffset) - 1; } return undefined; } function getTokenModifierFromClassification(tsClassification: number) { - return tsClassification & ts.classifier.modern.TokenEncodingConsts.modifierMask; + return tsClassification & ts.classifier.v2020.TokenEncodingConsts.modifierMask; } const typeIdx = getTokenTypeFromClassification(classification) || 0; diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 6a7c3ae838939..e6417566b3084 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -752,12 +752,20 @@ namespace FourSlashInterface { } } - interface Classification { - classificationType: ts.ClassificationTypeNames | string; + interface OlderClassification { + classificationType: ts.ClassificationTypeNames; + text: string; + textSpan?: FourSlash.TextSpan; + } + + // The VS Code LSP + interface ModernClassification { + classificationType: string; text?: string; textSpan?: FourSlash.TextSpan; } + type Classification = OlderClassification | ModernClassification; export function classification(format: ts.SemanticClassificationFormat) { @@ -774,6 +782,8 @@ namespace FourSlashInterface { }; } + // Defaults to the previous semantic classifier factory functions + function comment(text: string, position?: number): Classification { return getClassification(ts.ClassificationTypeNames.comment, text, position); } diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index adbac20b3e7e6..a689bdadeb7f0 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -1,5 +1,5 @@ /** @internal */ -namespace ts.classifier.modern { +namespace ts.classifier.v2020 { /** @internal */ export const enum TokenEncodingConsts { diff --git a/src/services/services.ts b/src/services/services.ts index f29acb01100af..d7f0dc581af84 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1806,7 +1806,7 @@ namespace ts { const responseFormat = format || SemanticClassificationFormat.Original; if (responseFormat === SemanticClassificationFormat.TwentyTwenty) { - return classifier.modern.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier.v2020.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } else { return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); @@ -1825,7 +1825,7 @@ namespace ts { return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); } else { - return classifier.modern.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + return classifier.v2020.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); } } From 473f65156c926816a6d69a2f301805d0cd96813c Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 8 Jul 2020 08:14:53 -0400 Subject: [PATCH 14/19] Handle feedback --- src/services/classifier2020.ts | 41 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index a689bdadeb7f0..2d8031e2fe655 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -18,8 +18,8 @@ namespace ts.classifier.v2020 { } /** This is mainly used internally for testing */ - export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { - const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span); + export function getSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { + const classifications = getEncodedSemanticClassifications(program, cancellationToken, sourceFile, span); Debug.assert(classifications.spans.length % 3 === 0); const dense = classifications.spans; @@ -34,14 +34,14 @@ namespace ts.classifier.v2020 { return result; } - export function getEncodedSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { + export function getEncodedSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): Classifications { return { - spans: getSemanticTokens(program, sourceFile, span), + spans: getSemanticTokens(program, sourceFile, span, cancellationToken), endOfLineState: EndOfLineState.None }; } - function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan): number[] { + function getSemanticTokens(program: Program, sourceFile: SourceFile, span: TextSpan, cancellationToken: CancellationToken): number[] { const resultTokens: number[] = []; const collector = (node: Node, typeIdx: number, modifierSet: number) => { @@ -49,17 +49,28 @@ namespace ts.classifier.v2020 { }; if (program && sourceFile) { - collectTokens(program, sourceFile, span, collector); + collectTokens(program, sourceFile, span, collector, cancellationToken); } return resultTokens; } - function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void) { + function collectTokens(program: Program, sourceFile: SourceFile, span: TextSpan, collector: (node: Node, tokenType: number, tokenModifier: number) => void, cancellationToken: CancellationToken) { const typeChecker = program.getTypeChecker(); let inJSXElement = false; function visit(node: Node) { + switch(node.kind) { + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + if (cancellationToken.isCancellationRequested()) return; + } + if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { return; } @@ -217,22 +228,6 @@ namespace ts.classifier.v2020 { return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); } - const enum SemanticMeaning { - None = 0x0, - Value = 0x1, - Type = 0x2, - Namespace = 0x4, - All = Value | Type | Namespace - } - - function getMeaningFromLocation(node: Node): SemanticMeaning { - const f = (ts).getMeaningFromLocation; - if (typeof f === "function") { - return f(node); - } - return SemanticMeaning.All; - } - const tokenFromDeclarationMapping: { [name: string]: TokenType } = { [SyntaxKind.VariableDeclaration]: TokenType.variable, [SyntaxKind.Parameter]: TokenType.parameter, From 2b663a8c365eec5aec48ceb85be7ccdda37697a0 Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 8 Jul 2020 11:14:25 -0400 Subject: [PATCH 15/19] WIP - don't provide a breaking change --- src/services/classifier2020.ts | 4 ++-- src/services/services.ts | 4 ++-- src/services/types.ts | 16 +++++++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index 2d8031e2fe655..694c20acdc7de 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -18,12 +18,12 @@ namespace ts.classifier.v2020 { } /** This is mainly used internally for testing */ - export function getSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] { + export function getSemanticClassifications(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan2020[] { const classifications = getEncodedSemanticClassifications(program, cancellationToken, sourceFile, span); Debug.assert(classifications.spans.length % 3 === 0); const dense = classifications.spans; - const result: ClassifiedSpan[] = []; + const result: ClassifiedSpan2020[] = []; for (let i = 0; i < dense.length; i += 3) { result.push({ textSpan: createTextSpan(dense[i], dense[i + 1]), diff --git a/src/services/services.ts b/src/services/services.ts index d7f0dc581af84..026bd68f308a5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1797,7 +1797,7 @@ namespace ts { return kind === ScriptKind.TS || kind === ScriptKind.TSX; } - function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] { + function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): (ClassifiedSpan| ClassifiedSpan2020)[] { if (!isTsOrTsxFile(fileName)) { // do not run semantic classification on non-ts-or-tsx files return []; @@ -1829,7 +1829,7 @@ namespace ts { } } - function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { + function getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[] { // doesn't use compiler - no need to synchronize with host return ts.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); } diff --git a/src/services/types.ts b/src/services/types.ts index 581b70aef15f2..82dd6faf0afac 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -380,10 +380,15 @@ namespace ts { getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.TwentyTwenty): ClassifiedSpan2020[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.Original): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.TwentyTwenty): ClassifiedSpan2020[]; + getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.Original): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; @@ -603,7 +608,12 @@ namespace ts { export interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames | number; + classificationType: ClassificationTypeNames; + } + + export interface ClassifiedSpan2020 { + textSpan: TextSpan; + classificationType: number; } /** From 219c64a5db4c22b56288d2caff2bf1ae19916051 Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 9 Sep 2020 08:59:48 -0400 Subject: [PATCH 16/19] Fix all build errors --- src/harness/fourslashImpl.ts | 3 +-- src/services/services.ts | 5 +++-- src/services/types.ts | 10 ++++------ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 628181c8f0f28..3bdfa29203e9d 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2490,7 +2490,7 @@ namespace FourSlash { return [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join("."); } - private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) { + private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: (ts.ClassifiedSpan | ts.ClassifiedSpan2020)[] , sourceFileText: string) { if (actual.length !== expected.length) { this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length + ", but was " + actual.length + @@ -2579,7 +2579,6 @@ namespace FourSlash { public verifySemanticClassifications(format: ts.SemanticClassificationFormat, expected: { classificationType: string | number; text?: string }[]) { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length), format); - this.verifyClassifications(expected, actual, this.activeFile.content); } diff --git a/src/services/services.ts b/src/services/services.ts index 026bd68f308a5..05a41528037a9 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1797,7 +1797,8 @@ namespace ts { return kind === ScriptKind.TS || kind === ScriptKind.TSX; } - function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): (ClassifiedSpan| ClassifiedSpan2020)[] { + function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + function getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[] { if (!isTsOrTsxFile(fileName)) { // do not run semantic classification on non-ts-or-tsx files return []; @@ -1829,7 +1830,7 @@ namespace ts { } } - function getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[] { + function getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] { // doesn't use compiler - no need to synchronize with host return ts.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span); } diff --git a/src/services/types.ts b/src/services/types.ts index 82dd6faf0afac..94151fd0a2c4d 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -380,14 +380,12 @@ namespace ts { getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.TwentyTwenty): ClassifiedSpan2020[]; - getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.Original): ClassifiedSpan[]; - getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.TwentyTwenty): ClassifiedSpan2020[]; - getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat.Original): ClassifiedSpan[]; - getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; + getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; From a9035d6fea42e8b2d7340a6789d4a6c6101750f3 Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 9 Sep 2020 09:44:32 -0400 Subject: [PATCH 17/19] Update baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 12 +++++++++--- tests/baselines/reference/api/typescript.d.ts | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 051207c249d7d..ea937a6e998f6 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5409,9 +5409,11 @@ declare namespace ts { */ getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; /** @@ -5580,7 +5582,11 @@ declare namespace ts { } interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames | number; + classificationType: ClassificationTypeNames; + } + interface ClassifiedSpan2020 { + textSpan: TextSpan; + classificationType: number; } /** * Navigation bar interface designed for visual studio's dual-column layout. diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 3124762b9743c..971786b778223 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5409,9 +5409,11 @@ declare namespace ts { */ getCompilerOptionsDiagnostics(): Diagnostic[]; /** @deprecated Use getEncodedSyntacticClassifications instead. */ - getSyntacticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSyntacticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** @deprecated Use getEncodedSemanticClassifications instead. */ - getSemanticClassifications(fileName: string, span: TextSpan, format?: SemanticClassificationFormat): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[]; + getSemanticClassifications(fileName: string, span: TextSpan, format: SemanticClassificationFormat): ClassifiedSpan[] | ClassifiedSpan2020[]; /** Encoded as triples of [start, length, ClassificationType]. */ getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications; /** @@ -5580,7 +5582,11 @@ declare namespace ts { } interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames | number; + classificationType: ClassificationTypeNames; + } + interface ClassifiedSpan2020 { + textSpan: TextSpan; + classificationType: number; } /** * Navigation bar interface designed for visual studio's dual-column layout. From 8739cbf1f06fa2d9a2e038a65453c0e2810d6321 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Wed, 9 Sep 2020 10:46:34 -0400 Subject: [PATCH 18/19] Update src/services/classifier2020.ts Co-authored-by: Sheetal Nandi --- src/services/classifier2020.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index 694c20acdc7de..5c97bcf33c85c 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -68,7 +68,7 @@ namespace ts.classifier.v2020 { case SyntaxKind.ClassExpression: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - if (cancellationToken.isCancellationRequested()) return; + cancellationToken.throwIfCancellationRequested(); } if (!node || !textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { From ff748a556da5ec930dec2426e46543f78d297dfa Mon Sep 17 00:00:00 2001 From: Orta Date: Fri, 11 Sep 2020 08:22:13 -0400 Subject: [PATCH 19/19] Addresses Ron's feedback --- src/services/classifier2020.ts | 49 ++++++++++++++++------------------ 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts index 5c97bcf33c85c..263d1ca89d2c1 100644 --- a/src/services/classifier2020.ts +++ b/src/services/classifier2020.ts @@ -1,18 +1,15 @@ /** @internal */ namespace ts.classifier.v2020 { - /** @internal */ export const enum TokenEncodingConsts { typeOffset = 8, modifierMask = (1 << typeOffset) - 1 } - /** @internal */ export const enum TokenType { class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member } - /** @internal */ export const enum TokenModifier { declaration, static, async, readonly, defaultLibrary, local } @@ -92,7 +89,7 @@ namespace ts.classifier.v2020 { if (typeIdx !== undefined) { let modifierSet = 0; if (node.parent) { - const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); + const parentIsDeclaration = (isBindingElement(node.parent) || tokenFromDeclarationMapping.get(node.parent.kind) === typeIdx); if (parentIsDeclaration && (node.parent).name === node) { modifierSet = 1 << TokenModifier.declaration; } @@ -166,7 +163,7 @@ namespace ts.classifier.v2020 { if (decl && isBindingElement(decl)) { decl = getDeclarationForBindingElement(decl); } - return decl && tokenFromDeclarationMapping[decl.kind]; + return decl && tokenFromDeclarationMapping.get(decl.kind); } function reclassifyByType(typeChecker: TypeChecker, node: Node, typeIdx: TokenType): TokenType { @@ -228,25 +225,25 @@ namespace ts.classifier.v2020 { return (isQualifiedName(node.parent) && node.parent.right === node) || (isPropertyAccessExpression(node.parent) && node.parent.name === node); } - const tokenFromDeclarationMapping: { [name: string]: TokenType } = { - [SyntaxKind.VariableDeclaration]: TokenType.variable, - [SyntaxKind.Parameter]: TokenType.parameter, - [SyntaxKind.PropertyDeclaration]: TokenType.property, - [SyntaxKind.ModuleDeclaration]: TokenType.namespace, - [SyntaxKind.EnumDeclaration]: TokenType.enum, - [SyntaxKind.EnumMember]: TokenType.enumMember, - [SyntaxKind.ClassDeclaration]: TokenType.class, - [SyntaxKind.MethodDeclaration]: TokenType.member, - [SyntaxKind.FunctionDeclaration]: TokenType.function, - [SyntaxKind.FunctionExpression]: TokenType.function, - [SyntaxKind.MethodSignature]: TokenType.member, - [SyntaxKind.GetAccessor]: TokenType.property, - [SyntaxKind.SetAccessor]: TokenType.property, - [SyntaxKind.PropertySignature]: TokenType.property, - [SyntaxKind.InterfaceDeclaration]: TokenType.interface, - [SyntaxKind.TypeAliasDeclaration]: TokenType.type, - [SyntaxKind.TypeParameter]: TokenType.typeParameter, - [SyntaxKind.PropertyAssignment]: TokenType.property, - [SyntaxKind.ShorthandPropertyAssignment]: TokenType.property - }; + const tokenFromDeclarationMapping = new Map([ + [SyntaxKind.VariableDeclaration, TokenType.variable], + [SyntaxKind.Parameter, TokenType.parameter], + [SyntaxKind.PropertyDeclaration, TokenType.property], + [SyntaxKind.ModuleDeclaration, TokenType.namespace], + [SyntaxKind.EnumDeclaration, TokenType.enum], + [SyntaxKind.EnumMember, TokenType.enumMember], + [SyntaxKind.ClassDeclaration, TokenType.class], + [SyntaxKind.MethodDeclaration, TokenType.member], + [SyntaxKind.FunctionDeclaration, TokenType.function], + [SyntaxKind.FunctionExpression, TokenType.function], + [SyntaxKind.MethodSignature, TokenType.member], + [SyntaxKind.GetAccessor, TokenType.property], + [SyntaxKind.SetAccessor, TokenType.property], + [SyntaxKind.PropertySignature, TokenType.property], + [SyntaxKind.InterfaceDeclaration, TokenType.interface], + [SyntaxKind.TypeAliasDeclaration, TokenType.type], + [SyntaxKind.TypeParameter, TokenType.typeParameter], + [SyntaxKind.PropertyAssignment, TokenType.property], + [SyntaxKind.ShorthandPropertyAssignment, TokenType.property] + ]); }