Skip to content

Commit 2ada30a

Browse files
committed
Fixes microsoft#134973: Cast to uint32 before validating that semantic tokens do not overlap
1 parent af1c6c0 commit 2ada30a

File tree

3 files changed

+85
-8
lines changed

3 files changed

+85
-8
lines changed

src/vs/editor/common/services/semanticTokensProviderStyling.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ export class SemanticTokensProviderStyling {
2020

2121
constructor(
2222
private readonly _legend: SemanticTokensLegend,
23-
private readonly _themeService: IThemeService,
24-
private readonly _modeService: IModeService,
25-
private readonly _logService: ILogService
23+
@IThemeService private readonly _themeService: IThemeService,
24+
@IModeService private readonly _modeService: IModeService,
25+
@ILogService private readonly _logService: ILogService
2626
) {
2727
this._hashTable = new HashTable();
2828
this._hasWarnedOverlappingTokens = false;
@@ -162,8 +162,10 @@ export function toMultilineTokens2(tokens: SemanticTokens, styling: SemanticToke
162162
const srcOffset = 5 * tokenIndex;
163163
const deltaLine = srcData[srcOffset];
164164
const deltaCharacter = srcData[srcOffset + 1];
165-
const lineNumber = lastLineNumber + deltaLine;
166-
const startCharacter = (deltaLine === 0 ? lastStartCharacter + deltaCharacter : deltaCharacter);
165+
// Casting both `lineNumber` and `startCharacter` here to uint32 using `|0`
166+
// to do checks below with the actual value that will be inserted in the Uint32Array result
167+
const lineNumber = (lastLineNumber + deltaLine) | 0;
168+
const startCharacter = (deltaLine === 0 ? (lastStartCharacter + deltaCharacter) | 0 : deltaCharacter);
167169
const length = srcData[srcOffset + 2];
168170
const tokenTypeIndex = srcData[srcOffset + 3];
169171
const tokenModifierSet = srcData[srcOffset + 4];

src/vs/editor/test/common/editorTestUtils.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
1818
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
1919
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
2020
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
21-
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
2221
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
2322
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
2423
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -30,6 +29,7 @@ import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
3029
import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/testTextResourcePropertiesService';
3130
import { IModelService } from 'vs/editor/common/services/modelService';
3231
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
32+
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
3333

3434
class TestTextModel extends TextModel {
3535
public registerDisposable(disposable: IDisposable): void {
@@ -81,7 +81,7 @@ export function createTextModel2(instantiationService: IInstantiationService, te
8181
return instantiationService.createInstance(TestTextModel, text, options, languageId, uri);
8282
}
8383

84-
export function createModelServices(services: ServiceCollection = new ServiceCollection()): [IInstantiationService, DisposableStore] {
84+
export function createModelServices(services: ServiceCollection = new ServiceCollection()): [TestInstantiationService, DisposableStore] {
8585
const serviceIdentifiers: ServiceIdentifier<any>[] = [];
8686
const define = <T>(id: ServiceIdentifier<T>, ctor: new (...args: any[]) => T) => {
8787
if (!services.has(id)) {
@@ -101,7 +101,7 @@ export function createModelServices(services: ServiceCollection = new ServiceCol
101101
define(ILogService, NullLogService);
102102
define(IModelService, ModelServiceImpl);
103103

104-
const instantiationService: IInstantiationService = new InstantiationService(services);
104+
const instantiationService = new TestInstantiationService(services);
105105
const disposables = new DisposableStore();
106106
disposables.add(toDisposable(() => {
107107
for (const id of serviceIdentifiers) {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as assert from 'assert';
7+
import { DisposableStore } from 'vs/base/common/lifecycle';
8+
import { MultilineTokens2, SparseEncodedTokens } from 'vs/editor/common/model/tokensStore';
9+
import { MetadataConsts } from 'vs/editor/common/modes';
10+
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
11+
import { SemanticTokensProviderStyling, toMultilineTokens2 } from 'vs/editor/common/services/semanticTokensProviderStyling';
12+
import { createModelServices } from 'vs/editor/test/common/editorTestUtils';
13+
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
14+
import { IThemeService, ITokenStyle } from 'vs/platform/theme/common/themeService';
15+
16+
suite('ModelService', () => {
17+
let disposables: DisposableStore;
18+
let instantiationService: TestInstantiationService;
19+
20+
setup(() => {
21+
[instantiationService, disposables] = createModelServices();
22+
});
23+
24+
teardown(() => {
25+
disposables.dispose();
26+
});
27+
28+
test('issue #134973: invalid semantic tokens should be handled better', () => {
29+
const languageId = 'java';
30+
disposables.add(ModesRegistry.registerLanguage({ id: languageId }));
31+
const legend = {
32+
tokenTypes: ['st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6', 'st7', 'st8', 'st9', 'st10'],
33+
tokenModifiers: []
34+
};
35+
instantiationService.stub(IThemeService, <Partial<IThemeService>>{
36+
getColorTheme() {
37+
return {
38+
getTokenStyleMetadata: (tokenType, tokenModifiers, languageId): ITokenStyle => {
39+
return {
40+
foreground: parseInt(tokenType.substr(2), 10)
41+
};
42+
}
43+
};
44+
}
45+
});
46+
const styling = instantiationService.createInstance(SemanticTokensProviderStyling, legend);
47+
const badTokens = {
48+
data: new Uint32Array([
49+
0, 13, 16, 1, 0,
50+
1, 2, 6, 2, 0,
51+
0, 7, 6, 3, 0,
52+
0, 15, 8, 4, 0,
53+
0, 17, 1, 5, 0,
54+
0, 7, 5, 6, 0,
55+
1, 12, 8, 7, 0,
56+
0, 19, 5, 8, 0,
57+
0, 7, 1, 9, 0,
58+
0, 4294967294, 5, 10, 0
59+
])
60+
};
61+
const result = toMultilineTokens2(badTokens, styling, languageId);
62+
const expected = new MultilineTokens2(1, new SparseEncodedTokens(new Uint32Array([
63+
0, 13, 29, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (1 << MetadataConsts.FOREGROUND_OFFSET)),
64+
1, 2, 8, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (2 << MetadataConsts.FOREGROUND_OFFSET)),
65+
1, 9, 15, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (3 << MetadataConsts.FOREGROUND_OFFSET)),
66+
1, 24, 32, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (4 << MetadataConsts.FOREGROUND_OFFSET)),
67+
1, 41, 42, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (5 << MetadataConsts.FOREGROUND_OFFSET)),
68+
1, 48, 53, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (6 << MetadataConsts.FOREGROUND_OFFSET)),
69+
2, 12, 20, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (7 << MetadataConsts.FOREGROUND_OFFSET)),
70+
2, 31, 36, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (8 << MetadataConsts.FOREGROUND_OFFSET)),
71+
2, 36, 41, (MetadataConsts.SEMANTIC_USE_FOREGROUND | (9 << MetadataConsts.FOREGROUND_OFFSET)),
72+
])));
73+
assert.deepStrictEqual(result.toString(), expected.toString());
74+
});
75+
});

0 commit comments

Comments
 (0)