diff --git a/src/harness/client.ts b/src/harness/client.ts index 32b9b7f4e16e3..b8d7d7ee48294 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?: SemanticClassificationFormat): Classifications { return notImplemented(); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 08ed8709fb0e9..511a03c69a0a5 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2448,20 +2448,64 @@ 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 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"; + + 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"; + + + function getTokenTypeFromClassification(tsClassification: number): number | undefined { + 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.modern.TokenEncodingConsts.modifierMask; + } + + const typeIdx = getTokenTypeFromClassification(classification) || 0; + const modSet = getTokenModifierFromClassification(classification); + + 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) { if (actual.length !== expected.length) { this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length + ", but was " + actual.length + jsonMismatchString()); } - ts.zipWith(expected, actual, (expectedClassification, actualClassification) => { + ts.zipWith(expected, actual, (expectedClassification, actualClassification, index) => { const expectedType = expectedClassification.classificationType; - if (expectedType !== actualClassification.classificationType) { - this.raiseError("verifyClassifications failed - expected classifications type to be " + + const actualType = typeof actualClassification.classificationType === "number" ? this.classificationToIdentifier(actualClassification.classificationType) : actualClassification.classificationType; + + if (expectedType !== actualType) { + this.raiseError(`verifyClassifications failed - expected classifications at index ${index} type to be ` + expectedType + ", but was " + - actualClassification.classificationType + - jsonMismatchString()); + actualType + + displayExpectedAndActualString(JSON.stringify(expectedType, undefined, 4), JSON.stringify(actualType, undefined, 5))); } const expectedSpan = expectedClassification.textSpan; @@ -2511,9 +2555,30 @@ namespace FourSlash { } } - public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) { + public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, - ts.createTextSpan(0, this.activeFile.content.length)); + ts.createTextSpan(0, this.activeFile.content.length), format); + const replacement = [`const c2 = classification("2020");`,`verify.semanticClassificationsAre("2020",`]; + 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}"), `); + }; + 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); this.verifyClassifications(expected, actual, this.activeFile.content); } @@ -3766,7 +3831,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 876a5bc37b02b..f3fc93cfc65bc 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -504,8 +504,12 @@ 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: ts.SemanticClassificationFormat, ...classifications: Classification[]) { + 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) { @@ -749,100 +753,116 @@ namespace FourSlashInterface { } interface Classification { - classificationType: ts.ClassificationTypeNames; - text: string; + classificationType: ts.ClassificationTypeNames | string; + text?: string; textSpan?: FourSlash.TextSpan; } - export namespace Classification { - export function comment(text: string, position?: number): Classification { + + + export function classification(format: ts.SemanticClassificationFormat) { + + function semanticToken(identifier: string, text: string, _position: number): Classification { + return { + classificationType: identifier, + text + }; + } + + if (format === ts.SemanticClassificationFormat.TwentyTwenty) { + return { + semanticToken + }; + } + + 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 +870,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 78acc177b8cc4..3f4cd6233ed34 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?: 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): ts.Classifications { - return unwrapJSONCallResult(this.shim.getEncodedSemanticClassifications(fileName, span.start, span.length)); + 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 { return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position, preferences)); diff --git a/src/server/project.ts b/src/server/project.ts index 9bdbb194472f1..f0d89ebcc7ec3 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1819,7 +1819,7 @@ namespace ts.server { packageJson.dependencies?.forEach((_, dependenyName) => addDependency(dependenyName)); packageJson.peerDependencies?.forEach((_, dependencyName) => addDependency(dependencyName)); if (dependencySelection === PackageJsonAutoImportPreference.All) { - packageJson.devDependencies?.forEach((_, dependencyName) => addDependency(dependencyName)); + packageJson.devDependencies?.forEach((_gulp, dependencyName) => addDependency(dependencyName)); } } diff --git a/src/services/classifier2020.ts b/src/services/classifier2020.ts new file mode 100644 index 0000000000000..005c985416a75 --- /dev/null +++ b/src/services/classifier2020.ts @@ -0,0 +1,2165 @@ +/** @internal */ +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 + } + + /** @internal */ + export const 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); + + Debug.assert(classifications.length % 3 === 0); + const dense = classifications; + 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) { + const context = new Context(program, sourceFile); + visitSourceFile(context, sourceFile); + return context.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(sourceFile), node.getWidth(sourceFile), ((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); + // } + + // function getMeaningFromLocation(node: Node): SemanticMeaning { + // const f = (ts).getMeaningFromLocation; + // if (typeof f === "function") { + // return f(node); + // } + // return SemanticMeaning.All; + // } + + /// CUT + + const enum SemanticMeaning { + None = 0x0, + Value = 0x1, + Type = 0x2, + Namespace = 0x4, + All = Value | Type | Namespace + } + + const enum CanUseLocals { + False = 0, + True = 1, + } + + const enum IsCallExpression { + False = 0, + True = 1 + } + + const enum IsRightSideOfExpression { + False = 0, + True = 1 + } + + const valueSymbolFlags = ( + SymbolFlags.FunctionScopedVariable + | SymbolFlags.BlockScopedVariable + | SymbolFlags.Property + | SymbolFlags.Function + ); + + const emptyLocals: SymbolTable = new Map<__String, Symbol>(); + + // Using internal TS API: + interface NodeWithLocals { + locals: SymbolTable | undefined; + } + interface NodeWithSymbol { + symbol: Symbol | undefined; + } + interface ProgramWithDiagnosticsProducingTypeChecker { + getDiagnosticsProducingTypeChecker(): TypeChecker; + } + interface SymbolWithExportSymbol { + exportSymbol: Symbol | undefined; + } + + class Context { + + private readonly program: Program; + private readonly typeChecker: TypeChecker; + public readonly sourceFile: SourceFile; + + private readonly locals: SymbolTable[]; + + private readonly scopeSymbolCacheStack: Map[]; + private scopeSymbolCache: Map; + + private readonly thisSymbolStack: (Symbol | undefined)[]; + private thisSymbol: Symbol | undefined; + + private readonly symbolToEncodedTokenType: Map; + + public readonly result: number[]; + public resultLen: number; + + constructor(program: Program, sourceFile: SourceFile) { + this.program = program; + this.typeChecker = (this.program).getDiagnosticsProducingTypeChecker(); + this.sourceFile = sourceFile; + this.locals = []; + this.scopeSymbolCacheStack = [new Map()]; + this.scopeSymbolCache = this.scopeSymbolCacheStack[this.scopeSymbolCacheStack.length - 1]; + this.thisSymbolStack = [undefined]; + this.thisSymbol = this.thisSymbolStack[this.thisSymbolStack.length - 1]; + this.symbolToEncodedTokenType = new Map(); + this.result = []; + this.resultLen = 0; + } + + public findSymbolInLocals(escapedText: __String, meaning: SemanticMeaning): Symbol | undefined { + const locals = this.locals; + for (let i = locals.length - 1; i >= 0; i--) { + const symbolTable = locals[i]; + const symbol = symbolTable.get(escapedText); + if (symbol) { + if (((meaning & SemanticMeaning.Value) === 0) && (symbol.getFlags() & valueSymbolFlags)) { + // we are not looking for Value + continue; + } + const symbolWithExportSymbol = (symbol); + if (symbolWithExportSymbol.exportSymbol) { + return symbolWithExportSymbol.exportSymbol; + } + return symbol; + } + } + return undefined; + } + + public pushResult(node: Identifier | PrivateIdentifier, tokenType: TokenType, modifiers: number): void { + const nodeWidth = node.getWidth(); + if (nodeWidth === 0) { + return; + } + const result = this.result; + let resultLen = this.resultLen; + result[resultLen++] = node.getStart(); + result[resultLen++] = nodeWidth; + result[resultLen++] = ((tokenType + 1) << TokenEncodingConsts.typeOffset) + modifiers; + this.resultLen = resultLen; + } + + public pushEncodedResult(node: Identifier | PrivateIdentifier, encodedToken: number): void { + const nodeWidth = node.getWidth(); + if (nodeWidth === 0) { + return; + } + const result = this.result; + let resultLen = this.resultLen; + result[resultLen++] = node.getStart(); + result[resultLen++] = nodeWidth; + result[resultLen++] = encodedToken; + this.resultLen = resultLen; + } + + public pushResultFromSymbolCache(symbol: Symbol, node: Identifier | PrivateIdentifier, extraTokenModifiers: number, isCallExpression: IsCallExpression, isRightSideOfExpression: IsRightSideOfExpression): boolean { + const cachedEncodedTokenType = this.symbolToEncodedTokenType.get(symbol); + if (typeof cachedEncodedTokenType !== "undefined") { + let tokenType = (cachedEncodedTokenType >>> TokenEncodingConsts.typeOffset) - 1; + let tokenModifiers = (cachedEncodedTokenType & TokenEncodingConsts.modifierMask); + if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter && symbol.valueDeclaration.parent.kind === SyntaxKind.Constructor) { + // handle the case of a property declaration in constructor + if (isRightSideOfExpression === IsRightSideOfExpression.True) { + if (tokenType === TokenType.parameter) { + tokenType = TokenType.property; + } + else if (tokenType === TokenType.function) { + tokenType = TokenType.member; + } + } + else { + if (tokenType === TokenType.property) { + tokenType = TokenType.parameter; + } + else if (tokenType === TokenType.member) { + tokenType = TokenType.function; + } + } + } + if (isCallExpression === IsCallExpression.True && (tokenType === TokenType.variable || tokenType === TokenType.property || tokenType === TokenType.parameter)) { + tokenType = tokenType === TokenType.property ? TokenType.member : TokenType.function; + } + tokenModifiers = tokenModifiers | extraTokenModifiers; + this.pushResult(node, tokenType, tokenModifiers); + return true; + } + return false; + } + + public saveResultInSymbolCache(symbol: Symbol, encodedTokenType: number): void { + this.symbolToEncodedTokenType.set(symbol, encodedTokenType); + } + + public pushThisSymbol(nodeScopeThis: Symbol | undefined): void { + this.thisSymbolStack.push(nodeScopeThis); + this.thisSymbol = this.thisSymbolStack[this.thisSymbolStack.length - 1]; + } + + public popThisSymbol(): void { + this.thisSymbolStack.pop(); + this.thisSymbol = this.thisSymbolStack[this.thisSymbolStack.length - 1]; + } + + public getThisSymbol(): Symbol | undefined { + return this.thisSymbol; + } + + public pushLocals(nodeLocals: SymbolTable | undefined): void { + if (!nodeLocals) { + this.locals.push(emptyLocals); + return; + } + // if any aliases are present, make a new symbol table + let hasAlias = false; + nodeLocals.forEach((symbol) => { + if (hasAlias) { + return; + } + hasAlias = (symbol.flags & SymbolFlags.Alias) ? true : false; + }); + + if (hasAlias) { + // must recreate symbol table with resolved aliases + const newSymbolTable = new Map<__String, Symbol>(); + nodeLocals.forEach((symbol, key) => { + if (symbol.flags & SymbolFlags.Alias) { + newSymbolTable.set(key, this.typeChecker.getAliasedSymbol(symbol)); + } + else { + newSymbolTable.set(key, symbol); + } + }); + this.locals.push(newSymbolTable); + } + else { + this.locals.push(nodeLocals); + } + } + + public popLocals(): void { + this.locals.pop(); + } + + public pushScope(nodeLocals: SymbolTable | undefined): void { + this.scopeSymbolCacheStack.push(new Map()); + this.scopeSymbolCache = this.scopeSymbolCacheStack[this.scopeSymbolCacheStack.length - 1]; + this.pushLocals(nodeLocals); + } + + public popScope(): void { + this.scopeSymbolCacheStack.pop(); + this.scopeSymbolCache = this.scopeSymbolCacheStack[this.scopeSymbolCacheStack.length - 1]; + this.popLocals(); + } + + public getCachedScopeSymbol(cacheKey: string): Symbol | undefined { + return this.scopeSymbolCache.get(cacheKey); + } + + public setCachedScopeSymbol(cacheKey: string, symbol: Symbol | undefined): void { + this.scopeSymbolCache.set(cacheKey, symbol); + } + + public getTypeCheckerSymbolAtLocation(node: Node): Symbol | undefined { + const symbol = this.typeChecker.getSymbolAtLocation(node); + if (symbol && symbol.flags & SymbolFlags.Alias) { + return this.typeChecker.getAliasedSymbol(symbol); + } + return symbol; + } + + public reclassifyWithType(node: Node, tokenType: TokenType.variable | TokenType.property | TokenType.parameter): TokenType { + // type based classifications + const type = this.typeChecker.getTypeAtLocation(node); + if (type) { + if (tokenType !== TokenType.parameter && typeHasConstructSignatures(type)) { + return TokenType.class; + } + if (typeHasCallSignatures(type) && !typeHasProperties(type)) { + return tokenType === TokenType.property ? TokenType.member : TokenType.function; + } + } + return tokenType; + } + + public isSourceFileDefaultLibrary(sourceFile: SourceFile): boolean { + return this.program.isSourceFileDefaultLibrary(sourceFile); + } + } + + function getSymbolFast(ctx: Context, node: Identifier, meaning: SemanticMeaning, canUseLocals: CanUseLocals): Symbol | undefined { + const escapedText = node.escapedText; + if (canUseLocals === CanUseLocals.True) { + const symbolInLocals = ctx.findSymbolInLocals(escapedText, meaning); + if (symbolInLocals) { + return symbolInLocals; + } + } + const cacheKey = `${meaning}${escapedText}`; + const symbolInCache = ctx.getCachedScopeSymbol(cacheKey); + if (typeof symbolInCache !== "undefined") { + return symbolInCache; + } + const symbol = ctx.getTypeCheckerSymbolAtLocation(node) || undefined; + ctx.setCachedScopeSymbol(cacheKey, symbol); + return symbol; + } + + function nodeModifiersToTokenModifiers(modifiers: ModifiersArray | undefined): number { + if (!modifiers) { + return 0; + } + let result = 0; + for (const modifier of modifiers) { + if (modifier.kind === SyntaxKind.StaticKeyword) { + result |= 1 << TokenModifier.static; + } + else if (modifier.kind === SyntaxKind.AsyncKeyword) { + result |= 1 << TokenModifier.async; + } + else if (modifier.kind === SyntaxKind.ReadonlyKeyword) { + result |= 1 << TokenModifier.readonly; + } + } + return result; + } + + function canCacheSymbol(symbol: Symbol | undefined): boolean { + // can only cache symbols that have 1 declaration or that have multiple declarations of the same kind + if (!symbol || !symbol.declarations || symbol.declarations.length <= 1) { + return true; + } + const kind = symbol.declarations[0].kind; + for (let i = 1, len = symbol.declarations.length; i < len; i++) { + if (symbol.declarations[i].kind !== kind) { + return false; + } + } + return true; + } + + function visitIdentifierInDeclaration(ctx: Context, node: Identifier, symbol: Symbol | undefined, _meaning: SemanticMeaning, tokenType: TokenType, tokenModifiers: number): void { + const canCache = canCacheSymbol(symbol); + if (canCache && symbol && ctx.pushResultFromSymbolCache(symbol, node, (1 << TokenModifier.declaration), IsCallExpression.False, IsRightSideOfExpression.False)) { + return; + } + + if (tokenType === TokenType.variable || tokenType === TokenType.property || tokenType === TokenType.parameter) { + tokenType = ctx.reclassifyWithType(node, tokenType); + if (tokenType !== TokenType.variable && tokenType !== TokenType.function) { + // the token has changed its type, be sure to remove local + tokenModifiers &= ~(1 << TokenModifier.local); + } + } + + const encodedTokenType = ((tokenType + 1) << TokenEncodingConsts.typeOffset) | tokenModifiers; + if (canCache && symbol) { + ctx.saveResultInSymbolCache(symbol, encodedTokenType); + } + ctx.pushEncodedResult(node, encodedTokenType | (1 << TokenModifier.declaration)); + } + + function visitIdentifierWithSymbol(ctx: Context, node: Identifier | PrivateIdentifier, symbol: Symbol, meaning: SemanticMeaning, isCallExpression: IsCallExpression, isRightSideOfExpression: IsRightSideOfExpression): void { + let canCache = canCacheSymbol(symbol); + if (canCache && ctx.pushResultFromSymbolCache(symbol, node, 0, isCallExpression, isRightSideOfExpression)) { + return; + } + + const flags = symbol.getFlags(); + let decl = symbol.valueDeclaration || (symbol.declarations && symbol.declarations[0]); + let tokenType: TokenType; + if (flags & SymbolFlags.Class) { + tokenType = TokenType.class; + } + else if (flags & SymbolFlags.Enum) { + tokenType = TokenType.enum; + } + else if (flags & SymbolFlags.TypeAlias) { + tokenType = TokenType.type; + } + else if ((flags & SymbolFlags.Interface) && (meaning & SemanticMeaning.Type)) { + tokenType = TokenType.interface; + } + else if (flags & SymbolFlags.TypeParameter) { + tokenType = TokenType.typeParameter; + } + else if (decl) { + if (decl.kind === SyntaxKind.BindingElement) { + decl = findBindingElementParentDeclaration(decl); + } + switch (decl.kind) { + case SyntaxKind.VariableDeclaration: tokenType = TokenType.variable; break; + case SyntaxKind.Parameter: + // handle the case of a property declaration in constructor + if (isRightSideOfExpression === IsRightSideOfExpression.True) { + tokenType = TokenType.property; + } + else { + tokenType = TokenType.parameter; + } + break; + case SyntaxKind.PropertyDeclaration: tokenType = TokenType.property; break; + case SyntaxKind.ModuleDeclaration: tokenType = TokenType.namespace; break; + case SyntaxKind.EnumDeclaration: tokenType = TokenType.enum; break; + case SyntaxKind.EnumMember: tokenType = TokenType.enumMember; break; + case SyntaxKind.ClassDeclaration: tokenType = TokenType.class; break; + case SyntaxKind.MethodDeclaration: tokenType = TokenType.member; break; + case SyntaxKind.FunctionDeclaration: tokenType = TokenType.function; break; + case SyntaxKind.FunctionExpression: tokenType = TokenType.function; break; + case SyntaxKind.MethodSignature: tokenType = TokenType.member; break; + case SyntaxKind.GetAccessor: tokenType = TokenType.property; break; + case SyntaxKind.PropertySignature: tokenType = TokenType.property; break; + case SyntaxKind.InterfaceDeclaration: tokenType = TokenType.interface; break; + case SyntaxKind.TypeAliasDeclaration: tokenType = TokenType.type; break; + case SyntaxKind.TypeParameter: tokenType = TokenType.typeParameter; break; + case SyntaxKind.PropertyAssignment: tokenType = TokenType.property; break; + case SyntaxKind.ShorthandPropertyAssignment: tokenType = TokenType.property; break; + default: + return; + } + } + else { + return; + } + + const isDefaultLibrary = ctx.isSourceFileDefaultLibrary(decl.getSourceFile()); + + if (tokenType === TokenType.variable || tokenType === TokenType.property || tokenType === TokenType.parameter) { + if (isCallExpression === IsCallExpression.True && !isDefaultLibrary) { + // normally, classes cannot be called, but there are default library symbols like String which can appear in a call expression + tokenType = tokenType === TokenType.property ? TokenType.member : TokenType.function; + canCache = false; + } + else { + tokenType = ctx.reclassifyWithType(node, tokenType); + } + } + + let modifierSet = 0; + const valueDecl = symbol.valueDeclaration; + if (valueDecl) { + const modifiers = getCombinedModifierFlags(valueDecl); + const nodeFlags = getCombinedNodeFlags(valueDecl); + if (modifiers & ModifierFlags.Static) { + modifierSet |= 1 << TokenModifier.static; + } + if (modifiers & ModifierFlags.Async) { + modifierSet |= 1 << TokenModifier.async; + } + if (tokenType !== TokenType.interface) { + if ((modifiers & ModifierFlags.Readonly) || (nodeFlags & NodeFlags.Const) || (flags & SymbolFlags.EnumMember)) { + modifierSet |= 1 << TokenModifier.readonly; + } + } + if ((tokenType === TokenType.variable || tokenType === TokenType.function) && isLocalDeclaration(valueDecl, ctx.sourceFile)) { + modifierSet |= 1 << TokenModifier.local; + } + } + + if (isDefaultLibrary) { + modifierSet |= 1 << TokenModifier.defaultLibrary; + } + + const encodedTokenType = ((tokenType + 1) << TokenEncodingConsts.typeOffset) | modifierSet; + if (canCache) { + ctx.saveResultInSymbolCache(symbol, encodedTokenType); + } + ctx.pushEncodedResult(node, encodedTokenType); + } + function visitIdentifier(ctx: Context, node: Identifier, meaning: SemanticMeaning, canUseLocals: CanUseLocals, isCallExpression: IsCallExpression): Symbol | undefined { + const symbol = getSymbolFast(ctx, node, meaning, canUseLocals); + if (!symbol) { + return undefined; + } + visitIdentifierWithSymbol(ctx, node, symbol, meaning, isCallExpression, IsRightSideOfExpression.False); + return symbol; + } + function visitPropertyName(ctx: Context, node: StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier): void { + if (node.kind === SyntaxKind.ComputedPropertyName) { + visitExpression(ctx, node.expression); + } + } + function visitQualifiedName(ctx: Context, node: QualifiedName, meaning: SemanticMeaning): Symbol | undefined { + return visitQualifiedNameWithSplitMeaning(ctx, node, meaning, meaning); + } + function visitQualifiedNameWithSplitMeaning(ctx: Context, node: QualifiedName, meaningLeft: SemanticMeaning, meaningRight: SemanticMeaning): Symbol | undefined { + const leftSymbol = visitEntityName(ctx, node.left, meaningLeft); + if (!leftSymbol || !leftSymbol.exports) { + return undefined; + } + const symbol = leftSymbol.exports.get(node.right.escapedText); + if (!symbol) { + return undefined; + } + visitIdentifierWithSymbol(ctx, node.right, symbol, meaningRight, IsCallExpression.False, IsRightSideOfExpression.False); + return symbol; + } + function visitEntityName(ctx: Context, node: EntityName, meaning: SemanticMeaning): Symbol | undefined { + switch (node.kind) { + case SyntaxKind.Identifier: + return visitIdentifier(ctx, node, meaning, CanUseLocals.True, IsCallExpression.False); + case SyntaxKind.QualifiedName: + return visitQualifiedName(ctx, node, meaning); + } + } + function visitParameterDeclaration(ctx: Context, node: ParameterDeclaration): Symbol | null | void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + visitBindingName(ctx, node.name, (node).symbol, TokenType.parameter, tokenModifiers); + let typeSymbol: Symbol | null | void; + if (node.type) { + typeSymbol = visitTypeNode(ctx, node.type); + } + if (node.initializer) { + visitExpression(ctx, node.initializer); + } + return typeSymbol; + } + function visitParameters(ctx: Context, nodes: NodeArray): void { + for (const parameter of nodes) { + visitParameterDeclaration(ctx, parameter); + } + } + function visitFunctionTypeNode(ctx: Context, node: FunctionTypeNode): Symbol | undefined | void { + visitDecorators(ctx, node.decorators); + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + visitTypeNode(ctx, node.type); + return (node).symbol; + } + function visitConstructorTypeNode(ctx: Context, node: ConstructorTypeNode): Symbol | undefined | void { + visitDecorators(ctx, node.decorators); + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + visitTypeNode(ctx, node.type); + return (node).symbol; + } + function visitImportTypeNode(ctx: Context, node: ImportTypeNode): void { + visitTypeNode(ctx, node.argument); + if (node.qualifier) { + visitEntityName(ctx, node.qualifier, (node.isTypeOf ? SemanticMeaning.Value : SemanticMeaning.Type)); + } + visitTypeArguments(ctx, node.typeArguments); + } + function visitTypeReference(ctx: Context, node: TypeReferenceNode): Symbol | undefined { + let symbol: Symbol | undefined; + if (node.typeName.kind === SyntaxKind.Identifier) { + symbol = visitIdentifier(ctx, node.typeName, SemanticMeaning.Type, CanUseLocals.True, IsCallExpression.False); + } + else { + symbol = visitQualifiedNameWithSplitMeaning(ctx, node.typeName, SemanticMeaning.Namespace, SemanticMeaning.Type); + } + visitTypeArguments(ctx, node.typeArguments); + return symbol; + } + function visitExpressionWithTypeArguments(ctx: Context, node: ExpressionWithTypeArguments): void { + if (node.parent.kind === SyntaxKind.HeritageClause && (node.parent.token === SyntaxKind.ExtendsKeyword || node.parent.token === SyntaxKind.ImplementsKeyword)) { + if (node.expression.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.expression, SemanticMeaning.Type, CanUseLocals.True, IsCallExpression.False); + } + else { + visitExpression(ctx, node.expression); + } + } + else { + visitExpression(ctx, node.expression); + } + visitTypeArguments(ctx, node.typeArguments); + } + function visitTypePredicateNode(ctx: Context, node: TypePredicateNode): void { + if (node.parameterName.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.parameterName, SemanticMeaning.Value, CanUseLocals.True, IsCallExpression.False); + } + if (node.type) { + visitTypeNode(ctx, node.type); + } + } + function visitTypeQueryNode(ctx: Context, node: TypeQueryNode): void { + visitEntityName(ctx, node.exprName, SemanticMeaning.Value); + } + function visitTypeLiteralNode(ctx: Context, node: TypeLiteralNode): void { + for (const member of node.members) { + switch (member.kind) { + case SyntaxKind.CallSignature: + visitCallSignatureDeclaration(ctx, member); + break; + case SyntaxKind.ConstructSignature: + visitConstructSignatureDeclaration(ctx, member); + break; + case SyntaxKind.PropertySignature: + visitPropertySignature(ctx, member); + break; + case SyntaxKind.MethodSignature: + visitMethodSignature(ctx, member); + break; + case SyntaxKind.IndexSignature: + visitIndexSignatureDeclaration(ctx, member); + break; + } + } + } + function visitArrayTypeNode(ctx: Context, node: ArrayTypeNode): void { + visitTypeNode(ctx, node.elementType); + } + function visitTupleTypeNode(ctx: Context, node: TupleTypeNode): void { + for (const elementType of node.elements) { + visitTypeNode(ctx, elementType); + } + } + function visitOptionalTypeNode(ctx: Context, node: OptionalTypeNode): void { + visitTypeNode(ctx, node.type); + } + function visitRestTypeNode(ctx: Context, node: RestTypeNode): void { + visitTypeNode(ctx, node.type); + } + function visitUnionTypeNode(ctx: Context, node: UnionTypeNode): void { + for (const type of node.types) { + visitTypeNode(ctx, type); + } + } + function visitIntersectionTypeNode(ctx: Context, node: IntersectionTypeNode): void { + for (const type of node.types) { + visitTypeNode(ctx, type); + } + } + function visitConditionalTypeNode(ctx: Context, node: ConditionalTypeNode): void { + visitTypeNode(ctx, node.checkType); + visitTypeNode(ctx, node.extendsType); + visitTypeNode(ctx, node.trueType); + visitTypeNode(ctx, node.falseType); + } + function visitInferTypeNode(ctx: Context, node: InferTypeNode): void { + visitTypeParameterDeclaration(ctx, node.typeParameter); + } + function visitParenthesizedTypeNode(ctx: Context, node: ParenthesizedTypeNode): Symbol | undefined | void { + return visitTypeNode(ctx, node.type); + } + function visitTypeOperatorNode(ctx: Context, node: TypeOperatorNode): void { + visitTypeNode(ctx, node.type); + } + function visitIndexedAccessTypeNode(ctx: Context, node: IndexedAccessTypeNode): void { + visitTypeNode(ctx, node.objectType); + visitTypeNode(ctx, node.indexType); + } + function visitMappedTypeNode(ctx: Context, node: MappedTypeNode): void { + visitTypeParameterDeclaration(ctx, node.typeParameter); + if (node.type) { + visitTypeNode(ctx, node.type); + } + } + function visitTypeNode(ctx: Context, node: TypeNode): Symbol | undefined | void { + switch (node.kind) { + case SyntaxKind.FunctionType: + return visitFunctionTypeNode(ctx, node); + case SyntaxKind.ConstructorType: + return visitConstructorTypeNode(ctx, node); + case SyntaxKind.ImportType: + return visitImportTypeNode(ctx, node); + case SyntaxKind.TypeReference: + return visitTypeReference(ctx, node); + case SyntaxKind.ExpressionWithTypeArguments: + return visitExpressionWithTypeArguments(ctx, node); + case SyntaxKind.TypePredicate: + return visitTypePredicateNode(ctx, node); + case SyntaxKind.TypeQuery: + return visitTypeQueryNode(ctx, node); + case SyntaxKind.TypeLiteral: + return visitTypeLiteralNode(ctx, node); + case SyntaxKind.ArrayType: + return visitArrayTypeNode(ctx, node); + case SyntaxKind.TupleType: + return visitTupleTypeNode(ctx, node); + case SyntaxKind.OptionalType: + return visitOptionalTypeNode(ctx, node); + case SyntaxKind.RestType: + return visitRestTypeNode(ctx, node); + case SyntaxKind.UnionType: + return visitUnionTypeNode(ctx, node); + case SyntaxKind.IntersectionType: + return visitIntersectionTypeNode(ctx, node); + case SyntaxKind.ConditionalType: + return visitConditionalTypeNode(ctx, node); + case SyntaxKind.InferType: + return visitInferTypeNode(ctx, node); + case SyntaxKind.ParenthesizedType: + return visitParenthesizedTypeNode(ctx, node); + case SyntaxKind.TypeOperator: + return visitTypeOperatorNode(ctx, node); + case SyntaxKind.IndexedAccessType: + return visitIndexedAccessTypeNode(ctx, node); + case SyntaxKind.MappedType: + return visitMappedTypeNode(ctx, node); + // ignoring: + + // TODO: This was commented in importing + // case SyntaxKind.ThisKeyword: + // return ctx.getThisSymbol(); + + + // case SyntaxKind.JSDocTypeExpression: + // case SyntaxKind.JSDocAllType: + // case SyntaxKind.JSDocUnknownType: + // case SyntaxKind.JSDocNonNullableType: + // case SyntaxKind.JSDocNullableType: + // case SyntaxKind.JSDocOptionalType: + // case SyntaxKind.JSDocFunctionType: + // case SyntaxKind.JSDocVariadicType: + // case SyntaxKind.JSDocNamepathType: + // case SyntaxKind.JSDocSignature: + // case SyntaxKind.JSDocTypeLiteral: + // case SyntaxKind.LiteralType: + // case SyntaxKind.ThisType: + // case SyntaxKind.NullKeyword: + // case SyntaxKind.TrueKeyword + // case SyntaxKind.FalseKeyword: + // case SyntaxKind.AnyKeyword: + // case SyntaxKind.UnknownKeyword: + // case SyntaxKind.NumberKeyword: + // case SyntaxKind.BigIntKeyword: + // case SyntaxKind.ObjectKeyword: + // case SyntaxKind.BooleanKeyword: + // case SyntaxKind.StringKeyword: + // case SyntaxKind.SymbolKeyword: + // case SyntaxKind.ThisKeyword: + // case SyntaxKind.VoidKeyword: + // case SyntaxKind.UndefinedKeyword: + // case SyntaxKind.NullKeyword: + // case SyntaxKind.NeverKeyword: + } + } + function visitTypeArguments(ctx: Context, nodes: NodeArray | undefined): void { + if (nodes) { + for (const node of nodes) { + visitTypeNode(ctx, node); + } + } + } + function visitPrefixUnaryExpression(ctx: Context, node: PrefixUnaryExpression): void { + visitExpression(ctx, node.operand); + } + function visitPostfixUnaryExpression(ctx: Context, node: PostfixUnaryExpression): void { + visitExpression(ctx, node.operand); + } + function visitPartiallyEmittedExpression(ctx: Context, node: PartiallyEmittedExpression): void { + visitExpression(ctx, node.expression); + } + function visitFunctionExpression(ctx: Context, node: FunctionExpression): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name) { + ctx.pushResult(node.name, TokenType.function, tokenModifiers | (1 << TokenModifier.declaration)); + } + visitTypeParameters(ctx, node.typeParameters); + const newScopeThis = visitParametersAndGetThisSymbol(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.body) { + ctx.pushThisSymbol(newScopeThis); + ctx.pushScope((node).locals); + visitBlock(ctx, node.body); + ctx.popScope(); + ctx.popThisSymbol(); + } + } + function visitTemplateSpan(ctx: Context, node: TemplateSpan): void { + visitExpression(ctx, node.expression); + } + function visitTemplateExpression(ctx: Context, node: TemplateExpression): void { + // ignoring node.head + for (const templateSpan of node.templateSpans) { + visitTemplateSpan(ctx, templateSpan); + } + } + function visitParenthesizedExpression(ctx: Context, node: ParenthesizedExpression): Symbol | null | void { + return visitExpression(ctx, node.expression); + } + function visitArrayLiteralExpression(ctx: Context, node: ArrayLiteralExpression): void { + for (const element of node.elements) { + visitExpression(ctx, element); + } + } + function visitMethodDeclaration(ctx: Context, node: MethodDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + ctx.pushResult(node.name, TokenType.member, tokenModifiers | (1 << TokenModifier.declaration)); + } + else { + visitPropertyName(ctx, node.name); + } + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.body) { + ctx.pushScope((node).locals); + visitBlock(ctx, node.body); + ctx.popScope(); + } + } + function visitGetAccessorDeclaration(ctx: Context, node: GetAccessorDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.property, tokenModifiers); + } + else { + visitPropertyName(ctx, node.name); + } + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.body) { + ctx.pushScope((node).locals); + visitBlock(ctx, node.body); + ctx.popScope(); + } + } + function visitSetAccessorDeclaration(ctx: Context, node: SetAccessorDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.property, tokenModifiers); + } + else { + visitPropertyName(ctx, node.name); + } + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.body) { + ctx.pushScope((node).locals); + visitBlock(ctx, node.body); + ctx.popScope(); + } + } + function visitPropertyAssignment(ctx: Context, node: PropertyAssignment): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.property, tokenModifiers); + } + else { + visitPropertyName(ctx, node.name); + } + visitExpression(ctx, node.initializer); + } + function visitShorthandPropertyAssignment(ctx: Context, node: ShorthandPropertyAssignment): void { + visitDecorators(ctx, node.decorators); + const tokenType = ctx.reclassifyWithType(node.name, TokenType.property); + ctx.pushResult(node.name, tokenType, (1 << TokenModifier.declaration)); + if (node.objectAssignmentInitializer) { + visitExpression(ctx, node.objectAssignmentInitializer); + } + } + function visitSpreadAssignment(ctx: Context, node: SpreadAssignment): void { + visitExpression(ctx, node.expression); + } + function visitObjectLiteralExpression(ctx: Context, node: ObjectLiteralExpression): Symbol | null | void { + for (const property of node.properties) { + switch (property.kind) { + case SyntaxKind.MethodDeclaration: + visitMethodDeclaration(ctx, property); + break; + case SyntaxKind.GetAccessor: + visitGetAccessorDeclaration(ctx, property); + break; + case SyntaxKind.SetAccessor: + visitSetAccessorDeclaration(ctx, property); + break; + case SyntaxKind.PropertyAssignment: + visitPropertyAssignment(ctx, property); + break; + case SyntaxKind.ShorthandPropertyAssignment: + visitShorthandPropertyAssignment(ctx, property); + break; + case SyntaxKind.SpreadAssignment: + visitSpreadAssignment(ctx, property); + break; + } + } + return (node).symbol; + } + function visitNewExpression(ctx: Context, node: NewExpression): void { + visitExpression(ctx, node.expression); + visitTypeArguments(ctx, node.typeArguments); + if (node.arguments) { + for (const argument of node.arguments) { + visitExpression(ctx, argument); + } + } + } + function visitMetaProperty(ctx: Context, node: MetaProperty): void { + visitIdentifier(ctx, node.name, SemanticMeaning.Value, CanUseLocals.False, IsCallExpression.False); + } + function visitPropertyDeclaration(ctx: Context, node: PropertyDeclaration): void { + visitDecorators(ctx, node.decorators); + const modifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.property, modifiers); + } + else { + visitPropertyName(ctx, node.name); + } + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.initializer) { + visitExpression(ctx, node.initializer); + } + } + function visitConstructorDeclaration(ctx: Context, node: ConstructorDeclaration): void { + visitDecorators(ctx, node.decorators); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.body) { + ctx.pushScope((node).locals); + visitBlock(ctx, node.body); + ctx.popScope(); + } + } + function visitClassElement(ctx: Context, node: ClassElement): void { + switch (node.kind) { + case SyntaxKind.PropertyDeclaration: + return visitPropertyDeclaration(ctx, node); + case SyntaxKind.MethodDeclaration: + return visitMethodDeclaration(ctx, node); + case SyntaxKind.Constructor: + return visitConstructorDeclaration(ctx, node); + case SyntaxKind.GetAccessor: + return visitGetAccessorDeclaration(ctx, node); + case SyntaxKind.SetAccessor: + return visitSetAccessorDeclaration(ctx, node); + case SyntaxKind.IndexSignature: + return visitIndexSignatureDeclaration(ctx, node); + // ignoring: + // case SyntaxKind.SemicolonClassElement: + } + } + function visitClassExpression(ctx: Context, node: ClassExpression): void { + visitDecorators(ctx, node.decorators); + if (node.name) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.class, 0); + } + visitTypeParameters(ctx, node.typeParameters); + if (node.heritageClauses) { + for (const heritageClause of node.heritageClauses) { + visitHeritageClause(ctx, heritageClause); + } + } + ctx.pushThisSymbol((node).symbol); + for (const member of node.members) { + visitClassElement(ctx, member); + } + ctx.popThisSymbol(); + } + function visitPropertyAccessExpression(ctx: Context, node: PropertyAccessExpression, isCallExpression: IsCallExpression): Symbol | null | void { + const leftSymbol = visitExpression(ctx, node.expression); + if (leftSymbol && (leftSymbol.getFlags() & valueSymbolFlags) === 0 && (leftSymbol.exports || leftSymbol.members)) { + let symbol: Symbol | undefined; + if (leftSymbol.exports) { + symbol = leftSymbol.exports.get(node.name.escapedText); + } + if (!symbol && leftSymbol.members) { + symbol = leftSymbol.members.get(node.name.escapedText); + } + if (symbol) { + // found it! + visitIdentifierWithSymbol(ctx, node.name, symbol, SemanticMeaning.Value, isCallExpression, IsRightSideOfExpression.True); + return symbol; + } + } + const symbol = ctx.getTypeCheckerSymbolAtLocation(node.name); + if (symbol) { + visitIdentifierWithSymbol(ctx, node.name, symbol, SemanticMeaning.Value, isCallExpression, IsRightSideOfExpression.True); + } + return symbol; + } + function visitElementAccessExpression(ctx: Context, node: ElementAccessExpression): void { + visitExpression(ctx, node.expression); + visitExpression(ctx, node.argumentExpression); + } + function visitTaggedTemplateExpression(ctx: Context, node: TaggedTemplateExpression): void { + visitExpression(ctx, node.tag); + visitTypeArguments(ctx, node.typeArguments); + visitExpression(ctx, node.template); + } + function visitCallExpression(ctx: Context, node: CallExpression): void { + if (node.expression.kind === SyntaxKind.PropertyAccessExpression) { + visitPropertyAccessExpression(ctx, (node.expression), IsCallExpression.True); + } + else if (node.expression.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.expression, SemanticMeaning.Value, CanUseLocals.True, IsCallExpression.True); + } + else { + visitExpression(ctx, node.expression); + } + visitTypeArguments(ctx, node.typeArguments); + for (const argument of node.arguments) { + visitExpression(ctx, argument); + } + } + function visitNonNullExpression(ctx: Context, node: NonNullExpression): void { + visitExpression(ctx, node.expression); + } + function visitDeleteExpression(ctx: Context, node: DeleteExpression): void { + visitExpression(ctx, node.expression); + } + function visitTypeOfExpression(ctx: Context, node: TypeOfExpression): void { + visitExpression(ctx, node.expression); + } + function visitVoidExpression(ctx: Context, node: VoidExpression): void { + visitExpression(ctx, node.expression); + } + function visitAwaitExpression(ctx: Context, node: AwaitExpression): void { + visitExpression(ctx, node.expression); + } + function visitTypeAssertion(ctx: Context, node: TypeAssertion): Symbol | null | void { + const symbol = visitTypeNode(ctx, node.type); + visitExpression(ctx, node.expression); + return symbol; + } + function visitYieldExpression(ctx: Context, node: YieldExpression): void { + if (node.expression) { + visitExpression(ctx, node.expression); + } + } + function visitBinaryExpression(ctx: Context, node: BinaryExpression): void { + visitExpression(ctx, node.left); + visitExpression(ctx, node.right); + } + function visitConditionalExpression(ctx: Context, node: ConditionalExpression): void { + visitExpression(ctx, node.condition); + visitExpression(ctx, node.whenTrue); + visitExpression(ctx, node.whenFalse); + } + function visitArrowFunction(ctx: Context, node: ArrowFunction): void { + visitDecorators(ctx, node.decorators); + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + + ctx.pushScope((node).locals); + if (node.body.kind === SyntaxKind.Block) { + visitBlock(ctx, node.body); + } + else { + // must be expression + visitExpression(ctx, node.body); + } + ctx.popScope(); + } + function visitSpreadElement(ctx: Context, node: SpreadElement): void { + visitExpression(ctx, node.expression); + } + function visitAsExpression(ctx: Context, node: AsExpression): Symbol | null | void { + visitExpression(ctx, node.expression); + return visitTypeNode(ctx, node.type); + } + function visitCommaListExpression(ctx: Context, node: CommaListExpression): void { + for (const element of node.elements) { + visitExpression(ctx, element); + } + } + function visitJsxAttributes(ctx: Context, node: JsxAttributes): void { + for (const property of node.properties) { + if (property.kind === SyntaxKind.JsxAttribute) { + // ignoring property.name + if (property.initializer && property.initializer.kind === SyntaxKind.JsxExpression) { + visitJsxExpression(ctx, property.initializer); + } + } + // ignoring JsxSpreadAttribute + } + } + function visitJsxChild(ctx: Context, node: JsxChild): void { + switch (node.kind) { + case SyntaxKind.JsxElement: + return visitJsxElement(ctx, node); + case SyntaxKind.JsxSelfClosingElement: + return visitJsxSelfClosingElement(ctx, node); + case SyntaxKind.JsxFragment: + return visitJsxFragment(ctx, node); + case SyntaxKind.JsxExpression: + return visitJsxExpression(ctx, node); + // ignoring: + // case SyntaxKind.JsxText: + } + } + function visitJsxElement(ctx: Context, node: JsxElement): void { + visitJsxOpeningElement(ctx, node.openingElement); + for (const child of node.children) { + visitJsxChild(ctx, child); + } + // ignoring node.closingElement + } + function visitJsxSelfClosingElement(ctx: Context, node: JsxSelfClosingElement): void { + // ignoring node.tagName; + // ignoring node.typeArguments; + visitJsxAttributes(ctx, node.attributes); + } + function visitJsxFragment(ctx: Context, node: JsxFragment): void { + for (const child of node.children) { + visitJsxChild(ctx, child); + } + } + function visitJsxOpeningElement(ctx: Context, node: JsxOpeningElement): void { + // ignoring node.tagName; + // ignoring node.typeArguments; + visitJsxAttributes(ctx, node.attributes); + } + function visitJsxExpression(ctx: Context, node: JsxExpression): void { + if (node.expression) { + visitExpression(ctx, node.expression); + } + } + function visitExpression(ctx: Context, node: Expression): Symbol | null | void { + switch (node.kind) { + case SyntaxKind.PrefixUnaryExpression: + return visitPrefixUnaryExpression(ctx, node); + case SyntaxKind.PostfixUnaryExpression: + return visitPostfixUnaryExpression(ctx, node); + case SyntaxKind.PartiallyEmittedExpression: + return visitPartiallyEmittedExpression(ctx, node); + case SyntaxKind.Identifier: + return visitIdentifier(ctx, node, SemanticMeaning.Value, CanUseLocals.True, IsCallExpression.False); + case SyntaxKind.FunctionExpression: + return visitFunctionExpression(ctx, node); + case SyntaxKind.TemplateExpression: + return visitTemplateExpression(ctx, node); + case SyntaxKind.ParenthesizedExpression: + return visitParenthesizedExpression(ctx, node); + case SyntaxKind.ArrayLiteralExpression: + return visitArrayLiteralExpression(ctx, node); + case SyntaxKind.ObjectLiteralExpression: + return visitObjectLiteralExpression(ctx, node); + case SyntaxKind.NewExpression: + return visitNewExpression(ctx, node); + case SyntaxKind.MetaProperty: + return visitMetaProperty(ctx, node); + case SyntaxKind.ClassExpression: + return visitClassExpression(ctx, node); + case SyntaxKind.PropertyAccessExpression: + return visitPropertyAccessExpression(ctx, node, IsCallExpression.False); + case SyntaxKind.ElementAccessExpression: + return visitElementAccessExpression(ctx, node); + case SyntaxKind.TaggedTemplateExpression: + return visitTaggedTemplateExpression(ctx, node); + case SyntaxKind.CallExpression: + return visitCallExpression(ctx, node); + case SyntaxKind.NonNullExpression: + return visitNonNullExpression(ctx, node); + case SyntaxKind.DeleteExpression: + return visitDeleteExpression(ctx, node); + case SyntaxKind.TypeOfExpression: + return visitTypeOfExpression(ctx, node); + case SyntaxKind.VoidExpression: + return visitVoidExpression(ctx, node); + case SyntaxKind.AwaitExpression: + return visitAwaitExpression(ctx, node); + case SyntaxKind.TypeAssertionExpression: + return visitTypeAssertion(ctx, node); + case SyntaxKind.YieldExpression: + return visitYieldExpression(ctx, node); + case SyntaxKind.BinaryExpression: + return visitBinaryExpression(ctx, node); + case SyntaxKind.ConditionalExpression: + return visitConditionalExpression(ctx, node); + case SyntaxKind.ArrowFunction: + return visitArrowFunction(ctx, node); + case SyntaxKind.SpreadElement: + return visitSpreadElement(ctx, node); + case SyntaxKind.AsExpression: + return visitAsExpression(ctx, node); + case SyntaxKind.CommaListExpression: + return visitCommaListExpression(ctx, node); + case SyntaxKind.JsxAttributes: + return visitJsxAttributes(ctx, node); + case SyntaxKind.JsxElement: + return visitJsxElement(ctx, node); + case SyntaxKind.JsxSelfClosingElement: + return visitJsxSelfClosingElement(ctx, node); + case SyntaxKind.JsxFragment: + return visitJsxFragment(ctx, node); + case SyntaxKind.JsxOpeningElement: + return visitJsxOpeningElement(ctx, node); + case SyntaxKind.JsxExpression: + return visitJsxExpression(ctx, node); + // ignoring: + case SyntaxKind.ThisKeyword: + return ctx.getThisSymbol(); + // case SyntaxKind.JsxOpeningFragment: + // case SyntaxKind.JsxClosingFragment: + // case SyntaxKind.OmittedExpression: + // case SyntaxKind.SyntheticExpression: + // case SyntaxKind.NullKeyword: + // case SyntaxKind.TrueKeyword: + // case SyntaxKind.FalseKeyword: + // case SyntaxKind.SuperKeyword: + // case SyntaxKind.ImportKeyword: + // case SyntaxKind.StringLiteral: + // case SyntaxKind.RegularExpressionLiteral: + // case SyntaxKind.NoSubstitutionTemplateLiteral: + // case SyntaxKind.NumericLiteral: + // case SyntaxKind.BigIntLiteral: + } + } + function visitDecorator(ctx: Context, node: Decorator): void { + visitExpression(ctx, node.expression); + } + function visitDecorators(ctx: Context, decorators: NodeArray | undefined): void { + if (decorators) { + for (const decorator of decorators) { + visitDecorator(ctx, decorator); + } + } + } + function visitParametersAndGetThisSymbol(ctx: Context, parameters: NodeArray): Symbol | undefined { + let isFirst = true; + let result: Symbol | undefined; + for (const parameter of parameters) { + if (isFirst) { + isFirst = false; + if (parameter.name.kind === SyntaxKind.Identifier && parameter.name.getText() === "this") { + result = visitParameterDeclaration(ctx, parameter) || undefined; + } + else { + visitParameterDeclaration(ctx, parameter); + } + } + else { + visitParameterDeclaration(ctx, parameter); + } + } + return result; + } + function visitFunctionDeclaration(ctx: Context, node: FunctionDeclaration, parentKind: SyntaxKind): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name) { + ctx.pushResult(node.name, TokenType.function, tokenModifiers | (1 << TokenModifier.declaration) | (parentKind !== SyntaxKind.SourceFile ? (1 << TokenModifier.local) : 0)); + } + visitTypeParameters(ctx, node.typeParameters); + const newScopeThis = visitParametersAndGetThisSymbol(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.body) { + ctx.pushThisSymbol(newScopeThis); + ctx.pushScope((node).locals); + visitBlock(ctx, node.body); + ctx.popScope(); + ctx.popThisSymbol(); + } + } + function visitClassDeclaration(ctx: Context, node: ClassDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value | SemanticMeaning.Type, TokenType.class, tokenModifiers); + } + visitTypeParameters(ctx, node.typeParameters); + if (node.heritageClauses) { + for (const heritageClause of node.heritageClauses) { + visitHeritageClause(ctx, heritageClause); + } + } + ctx.pushThisSymbol((node).symbol); + for (const member of node.members) { + visitClassElement(ctx, member); + } + ctx.popThisSymbol(); + } + function visitMissingDeclaration(ctx: Context, node: MissingDeclaration): void { + visitDecorators(ctx, node.decorators); + } + function visitTypeParameterDeclaration(ctx: Context, node: TypeParameterDeclaration): void { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Type, TokenType.typeParameter, 0); + if (node.constraint) { + visitTypeNode(ctx, node.constraint); + } + if (node.default) { + visitTypeNode(ctx, node.default); + } + if (node.expression) { + visitExpression(ctx, node.expression); + } + } + function visitTypeParameters(ctx: Context, nodes: NodeArray | undefined): void { + if (nodes) { + for (const typeParameter of nodes) { + visitTypeParameterDeclaration(ctx, typeParameter); + } + } + } + function visitHeritageClause(ctx: Context, node: HeritageClause): void { + for (const type of node.types) { + visitExpressionWithTypeArguments(ctx, type); + } + } + function visitCallSignatureDeclaration(ctx: Context, node: CallSignatureDeclaration): void { + visitDecorators(ctx, node.decorators); + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + } + function visitConstructSignatureDeclaration(ctx: Context, node: ConstructSignatureDeclaration): void { + visitDecorators(ctx, node.decorators); + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + } + function visitPropertySignature(ctx: Context, node: PropertySignature): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.property, tokenModifiers); + } + else { + visitPropertyName(ctx, node.name); + } + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.initializer) { + visitExpression(ctx, node.initializer); + } + } + function visitMethodSignature(ctx: Context, node: MethodSignature): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + visitIdentifierInDeclaration(ctx, node.name, (node).symbol, SemanticMeaning.Value, TokenType.member, tokenModifiers); + } + else { + visitPropertyName(ctx, node.name); + } + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + } + function visitIndexSignatureDeclaration(ctx: Context, node: IndexSignatureDeclaration): void { + visitDecorators(ctx, node.decorators); + visitTypeParameters(ctx, node.typeParameters); + visitParameters(ctx, node.parameters); + if (node.type) { + visitTypeNode(ctx, node.type); + } + } + function visitInterfaceDeclaration(ctx: Context, node: InterfaceDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + ctx.pushResult(node.name, TokenType.interface, tokenModifiers | (1 << TokenModifier.declaration)); + visitTypeParameters(ctx, node.typeParameters); + if (node.heritageClauses) { + for (const heritageClause of node.heritageClauses) { + visitHeritageClause(ctx, heritageClause); + } + } + for (const member of node.members) { + switch (member.kind) { + case SyntaxKind.CallSignature: + visitCallSignatureDeclaration(ctx, member); + break; + case SyntaxKind.ConstructSignature: + visitConstructSignatureDeclaration(ctx, member); + break; + case SyntaxKind.PropertySignature: + visitPropertySignature(ctx, member); + break; + case SyntaxKind.MethodSignature: + visitMethodSignature(ctx, member); + break; + case SyntaxKind.IndexSignature: + visitIndexSignatureDeclaration(ctx, member); + break; + } + } + } + function visitTypeAliasDeclaration(ctx: Context, node: TypeAliasDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + ctx.pushResult(node.name, TokenType.type, tokenModifiers | (1 << TokenModifier.declaration)); + visitTypeParameters(ctx, node.typeParameters); + visitTypeNode(ctx, node.type); + } + function visitEnumDeclaration(ctx: Context, node: EnumDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + ctx.pushResult(node.name, TokenType.enum, tokenModifiers | (1 << TokenModifier.declaration)); + + const symbol = (node).symbol; + ctx.pushLocals(symbol ? symbol.exports : undefined); + for (const enumMember of node.members) { + if (enumMember.name.kind === SyntaxKind.Identifier) { + ctx.pushResult(enumMember.name, TokenType.enumMember, (1 << TokenModifier.declaration) | (1 << TokenModifier.readonly)); + } + else { + visitPropertyName(ctx, enumMember.name); + } + if (enumMember.initializer) { + visitExpression(ctx, enumMember.initializer); + } + } + ctx.popLocals(); + } + function visitModuleBlock(ctx: Context, node: ModuleBlock): void { + for (const statement of node.statements) { + visitStatement(ctx, statement, SyntaxKind.ModuleBlock); + } + } + function visitModuleDeclaration(ctx: Context, node: ModuleDeclaration): void { + visitDecorators(ctx, node.decorators); + const tokenModifiers = nodeModifiersToTokenModifiers(node.modifiers); + if (node.name.kind === SyntaxKind.Identifier) { + ctx.pushResult(node.name, TokenType.namespace, tokenModifiers | (1 << TokenModifier.declaration)); + } + if (node.body) { + ctx.pushScope((node).locals); + switch (node.body.kind) { + case SyntaxKind.ModuleBlock: + visitModuleBlock(ctx, node.body); + break; + case SyntaxKind.ModuleDeclaration: + visitModuleDeclaration(ctx, node.body); + break; + // ignoring: + // case SyntaxKind.Identifier: + } + ctx.popScope(); + } + } + function visitExternalModuleReference(ctx: Context, node: ExternalModuleReference): void { + if (node.expression.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.expression, SemanticMeaning.All, CanUseLocals.True, IsCallExpression.False); + } + else { + visitExpression(ctx, node.expression); + } + } + function visitImportEqualsDeclaration(ctx: Context, node: ImportEqualsDeclaration): void { + visitDecorators(ctx, node.decorators); + ctx.pushResult(node.name, TokenType.namespace, 0); + if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) { + visitExternalModuleReference(ctx, node.moduleReference); + } + else { + // isInternalModuleImportEqualsDeclaration + // import a = |b|; // Namespace + // import a = |b.c|; // Value, type, namespace + // import a = |b.c|.d; // Namespace + if (node.moduleReference.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.moduleReference, SemanticMeaning.Namespace, CanUseLocals.True, IsCallExpression.False); + } + else { + visitQualifiedNameWithSplitMeaning(ctx, node.moduleReference, SemanticMeaning.Namespace, SemanticMeaning.All); + } + } + } + function visitNamespaceExportDeclaration(ctx: Context, node: NamespaceExportDeclaration): void { + if (node.name) { + visitIdentifier(ctx, node.name, SemanticMeaning.Namespace | SemanticMeaning.Value, CanUseLocals.True, IsCallExpression.False); + } + } + function visitExportSpecifier(ctx: Context, node: ExportSpecifier): void { + if (node.propertyName) { + visitIdentifier(ctx, node.propertyName, SemanticMeaning.Value, CanUseLocals.True, IsCallExpression.False); + } + visitIdentifier(ctx, node.name, SemanticMeaning.Value, CanUseLocals.True, IsCallExpression.False); + } + function visitNamedExports(ctx: Context, node: NamedExportBindings): void { + if (isNamedExports(node)) { + for (const element of node.elements) { + visitExportSpecifier(ctx, element); + } + } + else if(isNamespaceExport(node)) { + // TODO: Noop probably seems right here, double check + } + } + function visitExportDeclaration(ctx: Context, node: ExportDeclaration): void { + visitDecorators(ctx, node.decorators); + if (node.exportClause) { + visitNamedExports(ctx, node.exportClause); + } + if (node.moduleSpecifier) { + visitExpression(ctx, node.moduleSpecifier); + } + } + function visitExportAssignment(ctx: Context, node: ExportAssignment): void { + visitDecorators(ctx, node.decorators); + if (node.expression.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.expression, SemanticMeaning.All, CanUseLocals.True, IsCallExpression.False); + } + else { + visitExpression(ctx, node.expression); + } + } + function visitBlock(ctx: Context, node: Block): void { + ctx.pushScope((node).locals); + for (const statement of node.statements) { + visitStatement(ctx, statement, SyntaxKind.Block); + } + ctx.popScope(); + } + function visitBindingName(ctx: Context, node: BindingName, symbol: Symbol | undefined, tokenType: TokenType.variable | TokenType.parameter, tokenModifiers: number): void { + switch (node.kind) { + case SyntaxKind.Identifier: + visitIdentifierInDeclaration(ctx, node, symbol, SemanticMeaning.Value, tokenType, tokenModifiers); + break; + case SyntaxKind.ObjectBindingPattern: + visitObjectBindingPattern(ctx, node, tokenType, tokenModifiers); + break; + case SyntaxKind.ArrayBindingPattern: + visitArrayBindingPattern(ctx, node, tokenType, tokenModifiers); + break; + } + + } + function visitBindingElement(ctx: Context, node: BindingElement, tokenType: TokenType.variable | TokenType.parameter, tokenModifiers: number): void { + visitDecorators(ctx, node.decorators); + if (node.propertyName) { + if (node.propertyName.kind === SyntaxKind.Identifier) { + visitIdentifier(ctx, node.propertyName, SemanticMeaning.Value, CanUseLocals.False, IsCallExpression.False); + } + else { + visitPropertyName(ctx, node.propertyName); + } + } + if (node.name) { + visitBindingName(ctx, node.name, (node).symbol, tokenType, tokenModifiers); + } + if (node.initializer) { + visitExpression(ctx, node.initializer); + } + } + function visitObjectBindingPattern(ctx: Context, node: ObjectBindingPattern, tokenType: TokenType.variable | TokenType.parameter, tokenModifiers: number): void { + for (const element of node.elements) { + visitBindingElement(ctx, element, tokenType, tokenModifiers); + } + } + function visitArrayBindingPattern(ctx: Context, node: ArrayBindingPattern, tokenType: TokenType.variable | TokenType.parameter, tokenModifiers: number): void { + for (const element of node.elements) { + if (element.kind === SyntaxKind.BindingElement) { + visitBindingElement(ctx, element, tokenType, tokenModifiers); + } + } + } + function visitVariableDeclaration(ctx: Context, node: VariableDeclaration, tokenModifiers: number): void { + visitDecorators(ctx, node.decorators); + visitBindingName(ctx, node.name, (node).symbol, TokenType.variable, tokenModifiers); + if (node.type) { + visitTypeNode(ctx, node.type); + } + if (node.initializer) { + visitExpression(ctx, node.initializer); + } + } + function visitVariableDeclarationList(ctx: Context, node: VariableDeclarationList, tokenModifiers: number): void { + if (node.flags & NodeFlags.Const) { + tokenModifiers |= (1 << TokenModifier.readonly); + } + for (const decl of node.declarations) { + visitVariableDeclaration(ctx, decl, tokenModifiers); + } + } + function visitVariableStatement(ctx: Context, node: VariableStatement, parentKind: SyntaxKind): void { + visitDecorators(ctx, node.decorators); + let tokenModifiers = 0; + if (parentKind !== SyntaxKind.SourceFile) { + tokenModifiers |= (1 << TokenModifier.local); + } + visitVariableDeclarationList(ctx, node.declarationList, tokenModifiers); + } + function visitExpressionStatement(ctx: Context, node: ExpressionStatement): void { + visitExpression(ctx, node.expression); + } + function visitIfStatement(ctx: Context, node: IfStatement): void { + visitExpression(ctx, node.expression); + visitStatement(ctx, node.thenStatement, SyntaxKind.IfStatement); + if (node.elseStatement) { + visitStatement(ctx, node.elseStatement, SyntaxKind.IfStatement); + } + } + function visitDoStatement(ctx: Context, node: DoStatement): void { + visitStatement(ctx, node.statement, SyntaxKind.DoStatement); + visitExpression(ctx, node.expression); + } + function visitWhileStatement(ctx: Context, node: WhileStatement): void { + visitExpression(ctx, node.expression); + visitStatement(ctx, node.statement, SyntaxKind.WhileStatement); + } + function visitForInitializer(ctx: Context, node: ForInitializer): void { + if (node.kind === SyntaxKind.VariableDeclarationList) { + visitVariableDeclarationList(ctx, node, 1 << TokenModifier.local); + } + else { + visitExpression(ctx, node); + } + } + function visitForStatement(ctx: Context, node: ForStatement): void { + ctx.pushScope((node).locals); + if (node.initializer) { + visitForInitializer(ctx, node.initializer); + } + if (node.condition) { + visitExpression(ctx, node.condition); + } + if (node.incrementor) { + visitExpression(ctx, node.incrementor); + } + visitStatement(ctx, node.statement, SyntaxKind.ForOfStatement); + ctx.popScope(); + } + function visitForInStatement(ctx: Context, node: ForInStatement): void { + ctx.pushScope((node).locals); + visitForInitializer(ctx, node.initializer); + visitExpression(ctx, node.expression); + visitStatement(ctx, node.statement, SyntaxKind.ForOfStatement); + ctx.popScope(); + } + function visitForOfStatement(ctx: Context, node: ForOfStatement): void { + ctx.pushScope((node).locals); + visitForInitializer(ctx, node.initializer); + visitExpression(ctx, node.expression); + visitStatement(ctx, node.statement, SyntaxKind.ForOfStatement); + ctx.popScope(); + } + function visitCaseClause(ctx: Context, node: CaseClause): void { + visitExpression(ctx, node.expression); + for (const statement of node.statements) { + visitStatement(ctx, statement, SyntaxKind.CaseClause); + } + } + function visitDefaultClause(ctx: Context, node: DefaultClause): void { + for (const statement of node.statements) { + visitStatement(ctx, statement, SyntaxKind.CaseClause); + } + } + function visitCaseBlock(ctx: Context, node: CaseBlock): void { + ctx.pushScope((node).locals); + for (const clause of node.clauses) { + if (clause.kind === SyntaxKind.CaseClause) { + visitCaseClause(ctx, clause); + } + else { + visitDefaultClause(ctx, clause); + } + } + ctx.popScope(); + } + function visitSwitchStatement(ctx: Context, node: SwitchStatement): void { + visitExpression(ctx, node.expression); + visitCaseBlock(ctx, node.caseBlock); + } + function visitLabeledStatement(ctx: Context, node: LabeledStatement): void { + // ignoring node.label + visitStatement(ctx, node.statement, SyntaxKind.LabeledStatement); + } + function visitThrowStatement(ctx: Context, node: ThrowStatement): void { + if (node.expression) { + visitExpression(ctx, node.expression); + } + } + function visitCatchClause(ctx: Context, node: CatchClause): void { + if (node.variableDeclaration) { + visitVariableDeclaration(ctx, node.variableDeclaration, (1 << TokenModifier.local)); + } + visitBlock(ctx, node.block); + } + function visitTryStatement(ctx: Context, node: TryStatement): void { + visitBlock(ctx, node.tryBlock); + if (node.catchClause) { + ctx.pushScope((node).locals); + visitCatchClause(ctx, node.catchClause); + ctx.popScope(); + } + if (node.finallyBlock) { + visitBlock(ctx, node.finallyBlock); + } + } + function visitReturnStatement(ctx: Context, node: ReturnStatement): void { + if (node.expression) { + visitExpression(ctx, node.expression); + } + } + function visitStatement(ctx: Context, node: Statement, parentKind: SyntaxKind): void { + switch (node.kind) { + case SyntaxKind.FunctionDeclaration: + return visitFunctionDeclaration(ctx, node, parentKind); + case SyntaxKind.ClassDeclaration: + return visitClassDeclaration(ctx, node); + case SyntaxKind.MissingDeclaration: + return visitMissingDeclaration(ctx, node); + case SyntaxKind.InterfaceDeclaration: + return visitInterfaceDeclaration(ctx, node); + case SyntaxKind.TypeAliasDeclaration: + return visitTypeAliasDeclaration(ctx, node); + case SyntaxKind.EnumDeclaration: + return visitEnumDeclaration(ctx, node); + case SyntaxKind.ModuleDeclaration: + return visitModuleDeclaration(ctx, node); + case SyntaxKind.ImportEqualsDeclaration: + return visitImportEqualsDeclaration(ctx, node); + case SyntaxKind.NamespaceExportDeclaration: + return visitNamespaceExportDeclaration(ctx, node); + case SyntaxKind.ExportDeclaration: + return visitExportDeclaration(ctx, node); + case SyntaxKind.ExportAssignment: + return visitExportAssignment(ctx, node); + case SyntaxKind.Block: + return visitBlock(ctx, node); + case SyntaxKind.VariableStatement: + return visitVariableStatement(ctx, node, parentKind); + case SyntaxKind.ExpressionStatement: + return visitExpressionStatement(ctx, node); + case SyntaxKind.IfStatement: + return visitIfStatement(ctx, node); + case SyntaxKind.DoStatement: + return visitDoStatement(ctx, node); + case SyntaxKind.WhileStatement: + return visitWhileStatement(ctx, node); + case SyntaxKind.ForStatement: + return visitForStatement(ctx, node); + case SyntaxKind.ForInStatement: + return visitForInStatement(ctx, node); + case SyntaxKind.ForOfStatement: + return visitForOfStatement(ctx, node); + case SyntaxKind.SwitchStatement: + return visitSwitchStatement(ctx, node); + case SyntaxKind.LabeledStatement: + return visitLabeledStatement(ctx, node); + case SyntaxKind.ThrowStatement: + return visitThrowStatement(ctx, node); + case SyntaxKind.TryStatement: + return visitTryStatement(ctx, node); + case SyntaxKind.ReturnStatement: + return visitReturnStatement(ctx, node); + + // ignoring + // case SyntaxKind.ImportDeclaration: + // case SyntaxKind.BreakStatement: + // case SyntaxKind.ContinueStatement: + // case SyntaxKind.WithStatement: + // case SyntaxKind.NotEmittedStatement: + // case SyntaxKind.EmptyStatement: + // case SyntaxKind.DebuggerStatement: + } + } + function visitSourceFile(ctx: Context, node: SourceFile): void { + ctx.pushScope((node).locals); + for (const statement of node.statements) { + visitStatement(ctx, statement, SyntaxKind.SourceFile); + } + ctx.popScope(); + } + + function findBindingElementParentDeclaration(element: BindingElement): VariableDeclaration | ParameterDeclaration { + while (true) { + if (element.parent.parent.kind === SyntaxKind.BindingElement) { + element = element.parent.parent; + } + else { + return element.parent.parent; + } + } + } + + function isLocalDeclaration(decl: Declaration, sourceFile: SourceFile): boolean { + if (isBindingElement(decl)) { + decl = findBindingElementParentDeclaration(decl); + } + if (isVariableDeclaration(decl) || isBindingElement(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 typeHasConstructSignatures(type: Type): boolean { + if (type.isUnion()) { + for (const t of type.types) { + if (t.getConstructSignatures().length > 0) { + return true; + } + } + return false; + } + return (type.getConstructSignatures().length > 0); + } + + function typeHasCallSignatures(type: Type): boolean { + if (type.isUnion()) { + for (const t of type.types) { + if (t.getCallSignatures().length > 0) { + return true; + } + } + return false; + } + return (type.getCallSignatures().length > 0); + } + + function typeHasProperties(type: Type): boolean { + if (type.isUnion()) { + for (const t of type.types) { + if (t.getProperties().length > 0) { + return true; + } + } + return false; + } + return (type.getProperties().length > 0); + } + + + + export function compareTokens(sourceFile: SourceFile, actualTokens: number[], oracleTokens: number[]): string[] { + const result: string[] = []; + for (let i = 0, len = Math.max(oracleTokens.length / 3, actualTokens.length / 3); i < len; i++) { + const offset = 3 * i; + const oracleOffset = (offset < oracleTokens.length ? oracleTokens[offset] : -1); + const oracleLength = (offset < oracleTokens.length ? oracleTokens[offset + 1] : -1); + const oracleType = (offset < oracleTokens.length ? oracleTokens[offset + 2] : -1); + const actualOffset = (offset < actualTokens.length ? actualTokens[offset] : -1); + const actualLength = (offset < actualTokens.length ? actualTokens[offset + 1] : -1); + const actualType = (offset < actualTokens.length ? actualTokens[offset + 2] : -1); + if (oracleOffset !== actualOffset || oracleLength !== actualLength || oracleType !== actualType) { + let debugStr = ``; + debugStr += `THEIRS: ${printSemanticToken(sourceFile, oracleOffset, oracleLength, oracleType)}\n`; + debugStr += `OURS: ${printSemanticToken(sourceFile, actualOffset, actualLength, actualType)}\n`; + // const oracleNode = findNodeEncompassingRange(sourceFile, oracleOffset, oracleLength); + // const actualNode = findNodeEncompassingRange(sourceFile, actualOffset, actualLength); + result.push(debugStr); + if (oracleOffset !== actualOffset) { + break; + } + } + } + return result; + + function printSemanticToken(sourceFile: SourceFile, offset: number, length: number, type: number): string { + if (offset === -1) { + return ``; + } + const node = findNodeEncompassingRange(sourceFile, offset, length); + const chain: string[] = []; + let tmp: Node | undefined = node; + while (tmp) { + chain.push((tmp).__debugKind); + tmp = tmp.parent; + } + chain.reverse(); + const tokenType = (type >>> TokenEncodingConsts.typeOffset) - 1; + const tokenModifiers = (type & TokenEncodingConsts.modifierMask); + const lineChar = sourceFile.getLineAndCharacterOfPosition(node.pos + node.getLeadingTriviaWidth()); + + return `<<<${node.getText()}>>> @ ${lineChar.line + 1}:${lineChar.character} --- ${chain.join(">")} :::: ${tokenTypeToString(tokenType)} - [${tokenModifiersToString(tokenModifiers)}]`; + } + function findNodeEncompassingRange(sourceFile: SourceFile, offset: number, length: number): Node { + const searchStart = offset; + const searchEnd = offset + length; + let current: Node = sourceFile; + outer: while (true) { + // find the child that contains 'position' + for (const child of current.getChildren(sourceFile)) { + const childStart = child.getStart(sourceFile, /* includeJsDocComment */ true); + const childEnd = child.getEnd(); + if (childStart <= searchStart && searchEnd <= childEnd) { + // Good child + current = child; + continue outer; + } + } + return current; + } + } + function tokenTypeToString(tokenType: TokenType): string { + switch (tokenType) { + case TokenType.class: return "class"; + case TokenType.enum: return "enum"; + case TokenType.interface: return "interface"; + case TokenType.namespace: return "namespace"; + case TokenType.typeParameter: return "typeParameter"; + case TokenType.type: return "type"; + case TokenType.parameter: return "parameter"; + case TokenType.variable: return "variable"; + case TokenType.enumMember: return "enumMember"; + case TokenType.property: return "property"; + case TokenType.function: return "function"; + case TokenType.member: return "member"; + } + return ""; + } + function tokenModifierToString(tokenModifier: TokenModifier): string { + switch (tokenModifier) { + case TokenModifier.declaration: return "declaration"; + case TokenModifier.static: return "static"; + case TokenModifier.async: return "async"; + case TokenModifier.readonly: return "readonly"; + case TokenModifier.defaultLibrary: return "defaultLibrary"; + case TokenModifier.local: return "local"; + } + return ""; + } + function tokenModifiersToString(tokenModifiers: number): string[] { + const result: string[] = []; + for (let i = 0; i < TokenModifier._; i++) { + const mask = ((1 << i) >>> 0); + if (tokenModifiers & mask) { + result.push(tokenModifierToString(i)); + } + } + return result; + } + } + + + /// CUT + + // 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 75c9bfdba71df..eba1dc21efb2c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1797,22 +1797,39 @@ namespace ts { return kind === ScriptKind.TS || kind === ScriptKind.TSX; } - function getSemanticClassifications(fileName: string, span: TextSpan): 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(); - return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + + const responseFormat = format || SemanticClassificationFormat.Original; + if (responseFormat === SemanticClassificationFormat.TwentyTwenty) { + return classifier.modern.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span); + } + else { + return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + } } - function getEncodedSemanticClassifications(fileName: string, span: TextSpan): 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(); - return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + + const responseFormat = format || SemanticClassificationFormat.Original; + if (responseFormat === SemanticClassificationFormat.Original) { + return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span); + } + else { + return { + endOfLineState: EndOfLineState.None, + spans: classifier.modern.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 4c60639bdab88..4d79258ba2065 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?: SemanticClassificationFormat): 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?: 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/tsconfig.json b/src/services/tsconfig.json index 9567185c7a9ac..8e660d9f2854e 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -12,6 +12,7 @@ "types.ts", "utilities.ts", "classifier.ts", + "classifier2020.ts", "stringCompletions.ts", "completions.ts", "documentHighlights.ts", diff --git a/src/services/types.ts b/src/services/types.ts index bc1223272faf8..401b0ac202830 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 @@ -375,14 +380,23 @@ 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[]; - - // Encoded as triples of [start, length, ClassificationType]. + 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. @@ -589,7 +603,7 @@ namespace ts { export interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames; + classificationType: ClassificationTypeNames | number; } /** diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 72100cfc28940..8d40708e09930 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -5339,6 +5339,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; @@ -5389,11 +5393,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. * @@ -5546,7 +5560,7 @@ declare namespace ts { } interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames; + classificationType: ClassificationTypeNames | 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 8ed116b6b1d38..35b2e1f98dbf1 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5339,6 +5339,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; @@ -5389,11 +5393,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. * @@ -5546,7 +5560,7 @@ declare namespace ts { } interface ClassifiedSpan { textSpan: TextSpan; - classificationType: ClassificationTypeNames; + classificationType: ClassificationTypeNames | number; } /** * Navigation bar interface designed for visual studio's dual-column layout. 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 a1f91482309c6..8f2e85021d93d 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -348,16 +348,18 @@ 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; + /** 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; @@ -454,118 +456,123 @@ declare namespace FourSlashInterface { resetCancelled(): void; setCancelled(numberOfCalls?: number): void; } - module classification { - function comment(text: string, position?: number): { + + interface ModernClassificationFactory { + semanticToken(identifier: string, name: string) + } + + 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 +756,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/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 4eb7f2a32edab..25f5557542a07 100644 --- a/tests/cases/fourslash/semanticClassification1.ts +++ b/tests/cases/fourslash/semanticClassification1.ts @@ -6,10 +6,20 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification; -verify.semanticClassificationsAre( +const 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)); + +var c2 = classification("2020") +verify.semanticClassificationsAre("2020", + 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 f7f6340e5bd6c..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; -verify.semanticClassificationsAre(c.interfaceName("Thing", test.marker("0").position)); \ No newline at end of file +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 799674a211dae..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; -verify.semanticClassificationsAre( +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 f067265df2994..6616f61beb0b0 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; -verify.semanticClassificationsAre( +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) -); \ No newline at end of file +); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("class.declaration", "x"), + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("class.declaration", "C"), + c2.semanticToken("class.declaration", "D"), + c2.semanticToken("class.declaration", "B"), +); diff --git a/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts b/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts index 7ac8bec28207f..5866529de3da8 100644 --- a/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts +++ b/tests/cases/fourslash/semanticClassificationInTemplateExpressions.ts @@ -10,8 +10,8 @@ ////} ////`abcd${ /*3*/M./*4*/C.x + /*5*/M./*6*/E.E1}efg` -var c = classification; -verify.semanticClassificationsAre( +const c = classification("original"); +verify.semanticClassificationsAre("original", c.moduleName("M", test.marker("0").position), c.className("C", test.marker("1").position), c.enumName("E", test.marker("2").position), @@ -19,3 +19,18 @@ verify.semanticClassificationsAre( 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 2061c218eac7a..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; -verify.semanticClassificationsAre( +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 f1f4fa8e67014..5f9de7227d9b3 100644 --- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts @@ -18,11 +18,27 @@ //// ////var x = /*6*/M; -var c = classification; -verify.semanticClassificationsAre( +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("2").position), 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 8105202a23fed..69683d6669511 100644 --- a/tests/cases/fourslash/semanticClassificationJs.ts +++ b/tests/cases/fourslash/semanticClassificationJs.ts @@ -6,4 +6,6 @@ //// 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..5a57251b3a599 100644 --- a/tests/cases/fourslash/semanticClassificationModules.ts +++ b/tests/cases/fourslash/semanticClassificationModules.ts @@ -9,11 +9,25 @@ ////var x: /*2*/M./*3*/I = /*4*/M.v; ////var y = /*5*/M; -var c = classification; -verify.semanticClassificationsAre( +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("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)); + +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 6c98c8340c38f..6a495a279bf5f 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts @@ -8,7 +8,16 @@ //// ////var M = { I: 10 }; -var c = classification; -verify.semanticClassificationsAre( +const c = classification("original"); +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)); + + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "M"), + c2.semanticToken("interface.declaration", "I"), + c2.semanticToken("variable.declaration", "M"), + c2.semanticToken("property.declaration", "I"), +); diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts index 419692b98ce7d..9d45176096a4f 100644 --- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts +++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts @@ -14,9 +14,23 @@ //// ////var x = /*5*/M; -var c = classification; -verify.semanticClassificationsAre( +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("namespace.declaration", "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"), +); diff --git a/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts b/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts index bc55c5d8253cc..a56a0ce888431 100644 --- a/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts +++ b/tests/cases/fourslash/semanticClassificationWithUnionTypes.ts @@ -11,8 +11,8 @@ ////var M: /*4*/M./*5*/I | /*6*/I | /*7*/C; ////var I: typeof M | typeof /*8*/C; -var c = classification; -verify.semanticClassificationsAre( +const c = classification("original"); +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,20 @@ 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)); + +const c2 = classification("2020"); +verify.semanticClassificationsAre("2020", + c2.semanticToken("namespace.declaration", "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 9381bef5e86ce..84a0dafe17681 100644 --- a/tests/cases/fourslash/semanticClassificationsCancellation1.ts +++ b/tests/cases/fourslash/semanticClassificationsCancellation1.ts @@ -5,11 +5,20 @@ ////module N { ////} -var c = classification; +const c = classification("original"); cancellation.setCancelled(1); -verifyOperationIsCancelled(() => verify.semanticClassificationsAre()); +verifyOperationIsCancelled(() => verify.semanticClassificationsAre("original", )); cancellation.resetCancelled(); -verify.semanticClassificationsAre( +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 188a09afcbc76..01e390b33a85d 100644 --- a/tests/cases/fourslash/semanticClassificatonTypeAlias.ts +++ b/tests/cases/fourslash/semanticClassificatonTypeAlias.ts @@ -5,11 +5,24 @@ ////var y = {}; ////function f(x: /*3*/Alias): /*4*/Alias { return undefined; } -var c = classification; -verify.semanticClassificationsAre( +const c = classification("original"); +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 + ); + +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/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 diff --git a/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts b/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts index 4eb7f2a32edab..1bbc4eec21a3e 100644 --- a/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts +++ b/tests/cases/fourslash/shims-pp/getSemanticClassifications.ts @@ -6,8 +6,8 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification; -verify.semanticClassificationsAre( +const 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), 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 4eb7f2a32edab..1bbc4eec21a3e 100644 --- a/tests/cases/fourslash/shims/getSemanticClassifications.ts +++ b/tests/cases/fourslash/shims/getSemanticClassifications.ts @@ -6,8 +6,8 @@ //// } //// interface /*2*/X extends /*3*/M./*4*/I { } -var c = classification; -verify.semanticClassificationsAre( +const 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), 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..6220f77c6fce6 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.local", "of"), + c2.semanticToken("variable.local", "of"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword2.ts index 190663caa995e..db49945e1a73f 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.local", "of"), + c2.semanticToken("variable.local", "of"), +); diff --git a/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts b/tests/cases/fourslash/syntacticClassificationsForOfKeyword3.ts index ef96c99fed45b..3393a4737f3b0 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.local", "of"), + c2.semanticToken("variable.local", "of"), + c2.semanticToken("variable.local", "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 @@ //// ///