Skip to content

Commit

Permalink
Adds existing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
orta committed Jun 16, 2020
1 parent 4825db1 commit 2d86a6e
Show file tree
Hide file tree
Showing 66 changed files with 513 additions and 173 deletions.
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6499,7 +6499,7 @@ namespace ts {
}

export const enum SemanticClassificationFormat {
Original = "orginal",
Original = "original",
TwentyTwenty = "2020"
}

Expand Down
74 changes: 70 additions & 4 deletions src/harness/fourslashImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2449,9 +2449,50 @@ namespace FourSlash {
Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos)!, "**"));
}

private classificationToIdentifier(classification: number){

const tokenTypes: string[] = [];
tokenTypes[ts.classifier.vscode.TokenType.class] = 'class';
tokenTypes[ts.classifier.vscode.TokenType.enum] = 'enum';
tokenTypes[ts.classifier.vscode.TokenType.interface] = 'interface';
tokenTypes[ts.classifier.vscode.TokenType.namespace] = 'namespace';
tokenTypes[ts.classifier.vscode.TokenType.typeParameter] = 'typeParameter';
tokenTypes[ts.classifier.vscode.TokenType.type] = 'type';
tokenTypes[ts.classifier.vscode.TokenType.parameter] = 'parameter';
tokenTypes[ts.classifier.vscode.TokenType.variable] = 'variable';
tokenTypes[ts.classifier.vscode.TokenType.enumMember] = 'enumMember';
tokenTypes[ts.classifier.vscode.TokenType.property] = 'property';
tokenTypes[ts.classifier.vscode.TokenType.function] = 'function';
tokenTypes[ts.classifier.vscode.TokenType.member] = 'member';

const tokenModifiers: string[] = [];
tokenModifiers[ts.classifier.vscode.TokenModifier.async] = 'async';
tokenModifiers[ts.classifier.vscode.TokenModifier.declaration] = 'declaration';
tokenModifiers[ts.classifier.vscode.TokenModifier.readonly] = 'readonly';
tokenModifiers[ts.classifier.vscode.TokenModifier.static] = 'static';
tokenModifiers[ts.classifier.vscode.TokenModifier.local] = 'local';
tokenModifiers[ts.classifier.vscode.TokenModifier.defaultLibrary] = 'defaultLibrary';


function getTokenTypeFromClassification(tsClassification: number): number | undefined {
if (tsClassification > ts.classifier.vscode.TokenEncodingConsts.modifierMask) {
return (tsClassification >> ts.classifier.vscode.TokenEncodingConsts.typeOffset) - 1;
}
return undefined;
}

function getTokenModifierFromClassification(tsClassification: number) {
return tsClassification & ts.classifier.vscode.TokenEncodingConsts.modifierMask;
}

const typeIdx = getTokenTypeFromClassification(classification) || 0;
const modSet = getTokenModifierFromClassification(classification);

const tokenClassifiction = [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join(".");
return tokenClassifiction;
}

private verifyClassifications(expected: { classificationType: string | number, text?: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) {
console.log("expected:", expected);
console.log("actual:", actual);
if (actual.length !== expected.length) {
this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length +
", but was " + actual.length +
Expand All @@ -2460,10 +2501,12 @@ namespace FourSlash {

ts.zipWith(expected, actual, (expectedClassification, actualClassification) => {
const expectedType = expectedClassification.classificationType;
if (expectedType !== actualClassification.classificationType) {
const actualType = typeof actualClassification.classificationType === "number" ? this.classificationToIdentifier(actualClassification.classificationType) : actualClassification.classificationType;

if (expectedType !== actualType) {
this.raiseError("verifyClassifications failed - expected classifications type to be " +
expectedType + ", but was " +
actualClassification.classificationType +
actualType +
jsonMismatchString());
}

Expand Down Expand Up @@ -2514,6 +2557,29 @@ namespace FourSlash {
}
}

public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) {
const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
ts.createTextSpan(0, this.activeFile.content.length), format);
const replacement = [`const c2 = classification("2020");`,`verify.semanticClassificationsAre("2020",`];
actual.forEach(a => {
const identifier = this.classificationToIdentifier(a.classificationType as number);
const text = this.activeFile.content.slice(a.textSpan.start, a.textSpan.start + a.textSpan.length);
replacement.push(` c2.semanticToken("${identifier}", "${text}"), `);
});
replacement.push(");");

throw new Error("You need to change the source code of fourslash test to use replaceWithSemanticClassifications");

/**
const fs = require("fs");
const testfilePath = this.originalInputFileName.slice(1);
const testfile = fs.readFileSync(testfilePath, "utf8");
const newfile = testfile.replace("verify.replaceWithSemanticClassifications(\"2020\")", replacement.join("\n"));
fs.writeFileSync(testfilePath, newfile);
*/
}


public verifySemanticClassifications(format: ts.SemanticClassificationFormat, expected: { classificationType: string | number; text?: string }[]) {
const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
ts.createTextSpan(0, this.activeFile.content.length), format);
Expand Down
61 changes: 6 additions & 55 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,10 @@ namespace FourSlashInterface {
this.state.verifySemanticClassifications(format, classifications);
}

public replaceWithSemanticClassifications(format: ts.SemanticClassificationFormat.TwentyTwenty) {
this.state.replaceWithSemanticClassifications(format);
}

public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range, options?: ts.RenameInfoOptions) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange, options);
}
Expand Down Expand Up @@ -745,7 +749,7 @@ namespace FourSlashInterface {
}

interface Classification {
classificationType: ts.ClassificationTypeNames | number;
classificationType: ts.ClassificationTypeNames | string;
text?: string;
textSpan?: FourSlash.TextSpan;
}
Expand All @@ -754,61 +758,8 @@ namespace FourSlashInterface {
export function classification(format: ts.SemanticClassificationFormat) {

function semanticToken(identifier: string, text: string, _position: number): Classification {

const tokenTypes = {
class: ts.classifier.vscode.TokenType.class,
enum: ts.classifier.vscode.TokenType.enum,
interface: ts.classifier.vscode.TokenType.interface,
namespace: ts.classifier.vscode.TokenType.namespace,
typeParameter: ts.classifier.vscode.TokenType.typeParameter,
type: ts.classifier.vscode.TokenType.type,
parameter: ts.classifier.vscode.TokenType.parameter,
variable: ts.classifier.vscode.TokenType.variable,
enumMember: ts.classifier.vscode.TokenType.enumMember,
property: ts.classifier.vscode.TokenType.property,
function: ts.classifier.vscode.TokenType.function,
member: ts.classifier.vscode.TokenType.member
};

const tokenModifiers = {
async: ts.classifier.vscode.TokenModifier.async,
declaration: ts.classifier.vscode.TokenModifier.declaration,
readonly: ts.classifier.vscode.TokenModifier.readonly,
static: ts.classifier.vscode.TokenModifier.static,
local: ts.classifier.vscode.TokenModifier.local,
defaultLibrary: ts.classifier.vscode.TokenModifier.defaultLibrary,
};

function identifierToClassificationID(identifier: string): number {
const [tokenType, ...modifiers] = identifier.split(".");
// @ts-expect-error
const tokenValue = tokenTypes[tokenType];
if (tokenValue === undefined) {
throw new Error(`Did not find ${tokenType} in tokenTypes for classifiers.`);
}

let classification = (tokenValue + 1) << 8;
ts.forEach(modifiers, (modifier) => {
// @ts-expect-error
const modifierValue = tokenModifiers[modifiers];
if (tokenValue === undefined) {
throw new Error(`Did not find ${modifier} in tokenModifiers for classifiers.`);
}
classification += modifierValue + 1;
console.log("adding: ", modifierValue);
});

// debugger;

return classification;
}

return {
classificationType: identifierToClassificationID(identifier),
// textSpan: {
// start: position,
// end: -1
// },
classificationType: identifier,
text
};
}
Expand Down
12 changes: 6 additions & 6 deletions src/services/classifierVscode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
namespace ts.classifier.vscode {

/** @internal */
export enum TokenEncodingConsts {
typeOffset = 8,
modifierMask = (1 << typeOffset) - 1
}

/** @internal */
export enum TokenType {
class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _
Expand All @@ -10,12 +16,6 @@ namespace ts.classifier.vscode {
declaration, static, async, readonly, defaultLibrary, local, _
}

/** @internal */
export enum TokenEncodingConsts {
typeOffset = 8,
modifierMask = (1 << typeOffset) - 1
}

/** This is mainly used internally for testing */
export function getSemanticClassifications(program: Program, _cancellationToken: CancellationToken, sourceFile: SourceFile, span: TextSpan): ClassifiedSpan[] {
const classifications = getEncodedSemanticClassifications(program, _cancellationToken, sourceFile, span);
Expand Down
12 changes: 6 additions & 6 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1787,11 +1787,11 @@ namespace ts {
}
synchronizeHostData();

const responseFormat = format || "original";
if (responseFormat === "original") {
const responseFormat = format || SemanticClassificationFormat.Original;
if (responseFormat === SemanticClassificationFormat.Original) {
return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span);
}
else {
else {
return classifier.vscode.getSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span);
}
}
Expand All @@ -1803,11 +1803,11 @@ namespace ts {
}
synchronizeHostData();

const responseFormat = format || "original";
if (responseFormat === "original") {
const responseFormat = format || SemanticClassificationFormat.Original;
if (responseFormat === SemanticClassificationFormat.Original) {
return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span);
}
else {
else {
return classifier.vscode.getEncodedSemanticClassifications(program, cancellationToken, getValidSourceFile(fileName), span);
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/classifyThisParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

////function f(this){}

var c = classification;
const c = classification("original");
verify.syntacticClassificationsAre(
c.keyword("function"),
c.identifier("f"),
Expand Down
4 changes: 3 additions & 1 deletion tests/cases/fourslash/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,8 @@ declare namespace FourSlashInterface {
text?: string;
textSpan?: TextSpan;
}[]): void;
/** Edits the current testfile and replaces with the semantic classifications */
replaceWithSemanticClassifications(format: "2020")
renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, range?: Range, allowRenameOfImportPath?: boolean): void;
renameInfoFailed(message?: string, allowRenameOfImportPath?: boolean): void;
renameLocations(startRanges: ArrayOrSingle<Range>, options: RenameLocationsOptions): void;
Expand Down Expand Up @@ -455,7 +457,7 @@ declare namespace FourSlashInterface {
}

interface ModernClassificationFactory {
semanticToken(identifier: string, name: string, position: number)
semanticToken(identifier: string, name: string)
}

interface ClassificationFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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("@"),
Expand Down
12 changes: 6 additions & 6 deletions tests/cases/fourslash/semanticClassification1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//// }
//// interface /*2*/X extends /*3*/M./*4*/I { }

var c = classification("original");
const c = classification("original");
verify.semanticClassificationsAre("original",
c.moduleName("M", test.marker("0").position),
c.interfaceName("I", test.marker("1").position),
Expand All @@ -16,10 +16,10 @@ verify.semanticClassificationsAre("original",

var c2 = classification("2020")
verify.semanticClassificationsAre("2020",
c2.semanticToken("namespace.declaration", "M", test.marker("0").position),
c2.semanticToken("interface.declaration", "I", test.marker("1").position),
c2.semanticToken("interface.declaration", "X", test.marker("2").position),
c2.semanticToken("namespace", "M", test.marker("3").position),
c2.semanticToken("interface", "I", test.marker("4").position),
c2.semanticToken("namespace.declaration", "M"),
c2.semanticToken("interface.declaration", "I"),
c2.semanticToken("interface.declaration", "X"),
c2.semanticToken("namespace", "M"),
c2.semanticToken("interface", "I"),
)

11 changes: 10 additions & 1 deletion tests/cases/fourslash/semanticClassification2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,14 @@
//// var Thing = 0;
//// Thing.toExponential();

var c = classification;
const c = classification("original");
verify.semanticClassificationsAre("original", c.interfaceName("Thing", test.marker("0").position));

const c2 = classification("2020");
verify.semanticClassificationsAre("2020",
c2.semanticToken("interface.declaration", "Thing"),
c2.semanticToken("member.declaration", "toExponential"),
c2.semanticToken("variable.declaration", "Thing"),
c2.semanticToken("variable", "Thing"),
c2.semanticToken("member.defaultLibrary", "toExponential")
);
10 changes: 9 additions & 1 deletion tests/cases/fourslash/semanticClassificationAlias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@
goTo.file("/b.ts");

const [m0, m1, m2, m3] = test.markers();
const c = classification;
const c = classification("original");
verify.semanticClassificationsAre("original",
c.typeAliasName("x", m0.position),
c.className("y", m1.position),
c.typeAliasName("x", m2.position),
c.className("y", m3.position),
);

const c2 = classification("2020");
verify.semanticClassificationsAre("2020",

c2.semanticToken("variable.declaration.readonly", "v"),
c2.semanticToken("type", "x"),
c2.semanticToken("class", "y"),
);
11 changes: 10 additions & 1 deletion tests/cases/fourslash/semanticClassificationClassExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@
//// var x = class /*0*/C {}
//// class /*1*/C {}
//// class /*2*/D extends class /*3*/B{} { }
var c = classification;
const c = classification("original");
verify.semanticClassificationsAre("original",
c.className("C", test.marker("0").position),
c.className("C", test.marker("1").position),
c.className("D", test.marker("2").position),
c.className("B", test.marker("3").position)
);

const c2 = classification("2020");
verify.semanticClassificationsAre("2020",
c2.semanticToken("class.declaration", "x"),
c2.semanticToken("class", "C"),
c2.semanticToken("class.declaration", "C"),
c2.semanticToken("class.declaration", "D"),
c2.semanticToken("class", "B"),
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
////}
////`abcd${ /*3*/M./*4*/C.x + /*5*/M./*6*/E.E1}efg`

var c = classification;
const c = classification("original");
verify.semanticClassificationsAre("original",
c.moduleName("M", test.marker("0").position),
c.className("C", test.marker("1").position),
Expand All @@ -19,3 +19,18 @@ verify.semanticClassificationsAre("original",
c.className("C", test.marker("4").position),
c.moduleName("M", test.marker("5").position),
c.enumName("E", test.marker("6").position));

const c2 = classification("2020");
verify.semanticClassificationsAre("2020",
c2.semanticToken("namespace.declaration", "M"),
c2.semanticToken("class.declaration", "C"),
c2.semanticToken("property.declaration.static", "x"),
c2.semanticToken("enum.declaration", "E"),
c2.semanticToken("enumMember.declaration.readonly", "E1"),
c2.semanticToken("namespace", "M"),
c2.semanticToken("class", "C"),
c2.semanticToken("property.static", "x"),
c2.semanticToken("namespace", "M"),
c2.semanticToken("enum", "E"),
c2.semanticToken("enumMember.readonly", "E1"),
);
Loading

0 comments on commit 2d86a6e

Please sign in to comment.