Skip to content

Commit dd671ed

Browse files
Merge pull request microsoft#3530 from Microsoft/lessScanningDuringClassification
Scan less during classification.
2 parents 3a9bc99 + 151306f commit dd671ed

File tree

5 files changed

+74
-35
lines changed

5 files changed

+74
-35
lines changed

src/compiler/scanner.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,31 @@ namespace ts {
376376
return ch >= CharacterCodes._0 && ch <= CharacterCodes._7;
377377
}
378378

379+
export function couldStartTrivia(text: string, pos: number): boolean {
380+
// Keep in sync with skipTrivia
381+
let ch = text.charCodeAt(pos);
382+
switch (ch) {
383+
case CharacterCodes.carriageReturn:
384+
case CharacterCodes.lineFeed:
385+
case CharacterCodes.tab:
386+
case CharacterCodes.verticalTab:
387+
case CharacterCodes.formFeed:
388+
case CharacterCodes.space:
389+
case CharacterCodes.slash:
390+
// starts of normal trivia
391+
case CharacterCodes.lessThan:
392+
case CharacterCodes.equals:
393+
case CharacterCodes.greaterThan:
394+
// Starts of conflict marker trivia
395+
return true;
396+
default:
397+
return ch > CharacterCodes.maxAsciiCharacter;
398+
}
399+
}
400+
379401
/* @internal */
380402
export function skipTrivia(text: string, pos: number, stopAfterLineBreak?: boolean): number {
403+
// Keep in sync with couldStartTrivia
381404
while (true) {
382405
let ch = text.charCodeAt(pos);
383406
switch (ch) {

src/compiler/utilities.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,12 @@ namespace ts {
20902090
return start <= textSpanEnd(span) && end >= span.start;
20912091
}
20922092

2093+
export function decodedTextSpanIntersectsWith(start1: number, length1: number, start2: number, length2: number) {
2094+
let end1 = start1 + length1;
2095+
let end2 = start2 + length2;
2096+
return start2 <= end1 && end2 >= start1;
2097+
}
2098+
20932099
export function textSpanIntersectsWithPosition(span: TextSpan, position: number) {
20942100
return position <= textSpanEnd(span) && position >= span.start;
20952101
}

src/harness/runner.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ if (testConfigFile !== '') {
4949
if (!option) {
5050
continue;
5151
}
52-
ts.sys.write("Option: " + option + "\r\n");
5352
switch (option) {
5453
case 'compiler':
5554
runners.push(new CompilerBaselineRunner(CompilerTestType.Conformance));

src/services/services.ts

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ namespace ts {
167167
}
168168

169169
public getFullWidth(): number {
170-
return this.end - this.getFullStart();
170+
return this.end - this.pos;
171171
}
172172

173173
public getLeadingTriviaWidth(sourceFile?: SourceFile): number {
@@ -6115,6 +6115,8 @@ namespace ts {
61156115
function getEncodedSyntacticClassifications(fileName: string, span: TextSpan): Classifications {
61166116
// doesn't use compiler - no need to synchronize with host
61176117
let sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
6118+
let spanStart = span.start;
6119+
let spanLength = span.length;
61186120

61196121
// Make a scanner we can get trivia from.
61206122
let triviaScanner = createScanner(ScriptTarget.Latest, /*skipTrivia:*/ false, sourceFile.text);
@@ -6131,48 +6133,55 @@ namespace ts {
61316133
result.push(type);
61326134
}
61336135

6134-
function classifyLeadingTrivia(token: Node): void {
6135-
let tokenStart = skipTrivia(sourceFile.text, token.pos, /*stopAfterLineBreak:*/ false);
6136-
if (tokenStart === token.pos) {
6137-
return;
6138-
}
6139-
6140-
// token has trivia. Classify them appropriately.
6136+
function classifyLeadingTriviaAndGetTokenStart(token: Node): number {
61416137
triviaScanner.setTextPos(token.pos);
61426138
while (true) {
61436139
let start = triviaScanner.getTextPos();
6140+
// only bother scanning if we have something that could be trivia.
6141+
if (!couldStartTrivia(sourceFile.text, start)) {
6142+
return start;
6143+
}
6144+
61446145
let kind = triviaScanner.scan();
61456146
let end = triviaScanner.getTextPos();
61466147
let width = end - start;
61476148

61486149
// The moment we get something that isn't trivia, then stop processing.
61496150
if (!isTrivia(kind)) {
6150-
return;
6151+
return start;
61516152
}
61526153

6153-
// Only bother with the trivia if it at least intersects the span of interest.
6154-
if (textSpanIntersectsWith(span, start, width)) {
6155-
if (isComment(kind)) {
6156-
classifyComment(token, kind, start, width);
6157-
continue;
6158-
}
6154+
// Don't bother with newlines/whitespace.
6155+
if (kind === SyntaxKind.NewLineTrivia || kind === SyntaxKind.WhitespaceTrivia) {
6156+
continue;
6157+
}
61596158

6160-
if (kind === SyntaxKind.ConflictMarkerTrivia) {
6161-
let text = sourceFile.text;
6162-
let ch = text.charCodeAt(start);
6159+
// Only bother with the trivia if it at least intersects the span of interest.
6160+
if (isComment(kind)) {
6161+
classifyComment(token, kind, start, width);
6162+
6163+
// Classifying a comment might cause us to reuse the trivia scanner
6164+
// (because of jsdoc comments). So after we classify the comment make
6165+
// sure we set the scanner position back to where it needs to be.
6166+
triviaScanner.setTextPos(end);
6167+
continue;
6168+
}
61636169

6164-
// for the <<<<<<< and >>>>>>> markers, we just add them in as comments
6165-
// in the classification stream.
6166-
if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) {
6167-
pushClassification(start, width, ClassificationType.comment);
6168-
continue;
6169-
}
6170+
if (kind === SyntaxKind.ConflictMarkerTrivia) {
6171+
let text = sourceFile.text;
6172+
let ch = text.charCodeAt(start);
61706173

6171-
// for the ======== add a comment for the first line, and then lex all
6172-
// subsequent lines up until the end of the conflict marker.
6173-
Debug.assert(ch === CharacterCodes.equals);
6174-
classifyDisabledMergeCode(text, start, end);
6174+
// for the <<<<<<< and >>>>>>> markers, we just add them in as comments
6175+
// in the classification stream.
6176+
if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) {
6177+
pushClassification(start, width, ClassificationType.comment);
6178+
continue;
61756179
}
6180+
6181+
// for the ======== add a comment for the first line, and then lex all
6182+
// subsequent lines up until the end of the conflict marker.
6183+
Debug.assert(ch === CharacterCodes.equals);
6184+
classifyDisabledMergeCode(text, start, end);
61766185
}
61776186
}
61786187
}
@@ -6291,12 +6300,14 @@ namespace ts {
62916300
}
62926301

62936302
function classifyToken(token: Node): void {
6294-
classifyLeadingTrivia(token);
6303+
let tokenStart = classifyLeadingTriviaAndGetTokenStart(token);
62956304

6296-
if (token.getWidth() > 0) {
6305+
let tokenWidth = token.end - tokenStart;
6306+
Debug.assert(tokenWidth >= 0);
6307+
if (tokenWidth > 0) {
62976308
let type = classifyTokenType(token.kind, token);
62986309
if (type) {
6299-
pushClassification(token.getStart(), token.getWidth(), type);
6310+
pushClassification(tokenStart, tokenWidth, type);
63006311
}
63016312
}
63026313
}
@@ -6401,9 +6412,10 @@ namespace ts {
64016412
}
64026413

64036414
// Ignore nodes that don't intersect the original span to classify.
6404-
if (textSpanIntersectsWith(span, element.getFullStart(), element.getFullWidth())) {
6415+
if (decodedTextSpanIntersectsWith(spanStart, spanLength, element.pos, element.getFullWidth())) {
64056416
let children = element.getChildren(sourceFile);
6406-
for (let child of children) {
6417+
for (let i = 0, n = children.length; i < n; i++) {
6418+
let child = children[i];
64076419
if (isToken(child)) {
64086420
classifyToken(child);
64096421
}

tests/cases/fourslash/syntacticClassificationsDocComment3.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ verify.syntacticClassificationsAre(
1414
c.punctuation("{"),
1515
c.keyword("number"),
1616
c.comment(" /* } */"),
17-
c.comment("/* } */"),
1817
c.keyword("var"),
1918
c.text("v"),
2019
c.punctuation(";"));

0 commit comments

Comments
 (0)