Skip to content

Commit 2822e49

Browse files
committed
JS: Switch to absolute offsets
1 parent d6ba1ff commit 2822e49

File tree

1 file changed

+57
-28
lines changed

1 file changed

+57
-28
lines changed

javascript/extractor/src/com/semmle/js/parser/JSDocParser.java

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,20 @@
3636
/** A Java port of <a href="https://github.com/Constellation/doctrine">doctrine</a>. */
3737
public class JSDocParser {
3838
private String source;
39+
private int absoluteOffset;
3940

4041
/** Parse the given string as a JSDoc comment. */
4142
public JSDocComment parse(Comment comment) {
4243
source = comment.getText();
4344
JSDocTagParser p = new JSDocTagParser();
44-
Pair<String, List<JSDocTagParser.Tag>> r = p.new TagParser(null).parseComment();
45+
Position startPos = comment.getLoc().getStart();
46+
// Get the start of the first line relative to the 'source' string.
47+
// This occurs before the start of 'source', so the lineStart is negative.
48+
int firstLineStart = -(startPos.getColumn() + "/**".length() - 1);
49+
this.absoluteOffset = startPos.getOffset();
50+
Pair<String, List<JSDocTagParser.Tag>> r = p.new TagParser(null).parseComment(
51+
startPos.getLine() - 1,
52+
firstLineStart);
4553
List<JSDocTag> tags = new ArrayList<>();
4654
for (JSDocTagParser.Tag tag : r.snd()) {
4755
String title = tag.title;
@@ -52,14 +60,12 @@ public JSDocComment parse(Comment comment) {
5260

5361
JSDocTypeExpression jsdocType = tag.type;
5462

55-
int realStartLine = comment.getLoc().getStart().getLine() + startLine;
56-
int realStartColumn =
57-
(startLine == 0 ? comment.getLoc().getStart().getColumn() + 3 : 0) + startColumn;
63+
int lineNumber = startLine + 1; // convert to 1-based
5864
SourceLocation loc =
5965
new SourceLocation(
6066
source,
61-
new Position(realStartLine, realStartColumn, -1),
62-
new Position(realStartLine, realStartColumn + 1 + title.length(), -1));
67+
new Position(lineNumber, startColumn, -1),
68+
new Position(lineNumber, startColumn + 1 + title.length(), -1));
6369
tags.add(new JSDocTag(loc, title, description, name, jsdocType, tag.errors));
6470
}
6571
return new JSDocComment(comment, r.fst(), tags);
@@ -223,48 +229,65 @@ private enum Token {
223229
private class TypeExpressionParser {
224230
int startIndex;
225231
int endIndex;
226-
int previous, index;
232+
int startOfCurToken, endOfPrevToken, index;
227233
Token token;
228234
Object value;
235+
int lineStart;
236+
int lineNumber;
229237

230238
private class Context {
231-
int _previous, _index;
239+
int _startOfCurToken, _endOfPrevToken, _index;
232240
Token _token;
233241
Object _value;
234242

235-
Context(int previous, int index, Token token, Object value) {
236-
this._previous = previous;
243+
Context(int startOfCurToken, int endOfPrevToken, int index, Token token, Object value) {
244+
this._startOfCurToken = startOfCurToken;
245+
this._endOfPrevToken = endOfPrevToken;
237246
this._index = index;
238247
this._token = token;
239248
this._value = value;
240249
}
241250

242251
void restore() {
243-
previous = this._previous;
252+
startOfCurToken = this._startOfCurToken;
253+
endOfPrevToken = this._endOfPrevToken;
244254
index = this._index;
245255
token = this._token;
246256
value = this._value;
247257
}
248258
}
249259

250260
Context save() {
251-
return new Context(previous, index, token, value);
261+
return new Context(startOfCurToken, endOfPrevToken, index, token, value);
252262
}
253263

254264
private SourceLocation loc() {
255265
return new SourceLocation(pos());
256266
}
257267

268+
/**
269+
* Returns the absolute position of the start of the current token.
270+
*/
258271
private Position pos() {
259-
// TEMPORARY: Produce relative positions as the parser originally did
260-
return new Position(1, index + 1 - startIndex, index - startIndex);
272+
return new Position(this.lineNumber + 1, startOfCurToken - lineStart, startOfCurToken + absoluteOffset);
273+
}
274+
275+
/**
276+
* Returns the absolute position of the end of the previous token.
277+
*
278+
* This can differ from the start of the current token case the two tokens
279+
* are separated by whitespace.
280+
*/
281+
private Position endPos() {
282+
return new Position(this.lineNumber + 1, endOfPrevToken - lineStart, endOfPrevToken + absoluteOffset);
261283
}
262284

263285
private <T extends JSDocTypeExpression> T finishNode(T node) {
264286
SourceLocation loc = node.getLoc();
265-
Position end = pos();
266-
// TEMPORARY: Assume relative positions as the parser originally did
267-
loc.setSource(inputSubstring(loc.getStart().getOffset() + startIndex, end.getOffset() + startIndex));
287+
Position end = endPos();
288+
int relativeStartOffset = loc.getStart().getOffset() - absoluteOffset;
289+
int relativeEndOffset = end.getOffset() - absoluteOffset;
290+
loc.setSource(inputSubstring(relativeStartOffset, relativeEndOffset));
268291
loc.setEnd(end);
269292
return node;
270293
}
@@ -546,7 +569,7 @@ private Token scanTypeName() {
546569
private Token next() throws ParseError {
547570
char ch;
548571

549-
previous = index;
572+
endOfPrevToken = index;
550573

551574
while (index < endIndex && isWhiteSpace(source.charAt(index))) {
552575
advance();
@@ -556,6 +579,8 @@ private Token next() throws ParseError {
556579
return token;
557580
}
558581

582+
startOfCurToken = index;
583+
559584
ch = source.charAt(index);
560585
switch (ch) {
561586
case '"':
@@ -918,7 +943,7 @@ private List<JSDocTypeExpression> parseParametersType() throws ParseError {
918943
}
919944
if (token == Token.EQUAL) {
920945
consume(Token.EQUAL);
921-
expr = finishNode(new OptionalType(loc, expr));
946+
expr = finishNode(new OptionalType(new SourceLocation(loc), expr));
922947
normal = false;
923948
} else {
924949
if (!normal) {
@@ -1147,13 +1172,14 @@ private JSDocTypeExpression parseTopParamType() throws ParseError {
11471172
return expr;
11481173
}
11491174

1150-
private JSDocTypeExpression parseType(int startIndex, int endIndex) throws ParseError {
1175+
private JSDocTypeExpression parseType(int startIndex, int endIndex, int lineStart, int lineNumber) throws ParseError {
11511176
JSDocTypeExpression expr;
11521177

1178+
this.lineNumber = lineNumber;
1179+
this.lineStart = lineStart;
11531180
this.startIndex = startIndex;
11541181
this.endIndex = endIndex;
11551182
index = startIndex;
1156-
previous = startIndex;
11571183

11581184
next();
11591185
expr = parseTop();
@@ -1165,13 +1191,14 @@ private JSDocTypeExpression parseType(int startIndex, int endIndex) throws Parse
11651191
return expr;
11661192
}
11671193

1168-
private JSDocTypeExpression parseParamType(int startIndex, int endIndex) throws ParseError {
1194+
private JSDocTypeExpression parseParamType(int startIndex, int endIndex, int lineStart, int lineNumber) throws ParseError {
11691195
JSDocTypeExpression expr;
11701196

1197+
this.lineNumber = lineNumber;
1198+
this.lineStart = lineStart;
11711199
this.startIndex = startIndex;
11721200
this.endIndex = endIndex;
11731201
index = startIndex;
1174-
previous = startIndex;
11751202

11761203
next();
11771204
expr = parseTopParamType();
@@ -1283,6 +1310,8 @@ private JSDocTypeExpression parseType(String title, int last) throws ParseError
12831310
if (!direct) {
12841311
// type expression { is found
12851312
brace = 1;
1313+
int firstLineStart = this.lineStart;
1314+
int firstLineNumber = this.lineNumber;
12861315
int startIndex = index;
12871316
while (index < last) {
12881317
ch = source.charAt(index);
@@ -1305,9 +1334,9 @@ private JSDocTypeExpression parseType(String title, int last) throws ParseError
13051334

13061335
try {
13071336
if (isParamTitle(title)) {
1308-
return typed.parseParamType(startIndex, index - 1);
1337+
return typed.parseParamType(startIndex, index - 1, firstLineStart, firstLineNumber);
13091338
}
1310-
return typed.parseType(startIndex, index - 1);
1339+
return typed.parseType(startIndex, index - 1, firstLineStart, firstLineNumber);
13111340
} catch (ParseError e) {
13121341
// parse failed
13131342
return null;
@@ -1859,15 +1888,15 @@ String scanJSDocDescription() {
18591888
return description.toString().trim();
18601889
}
18611890

1862-
public Pair<String, List<Tag>> parseComment() {
1891+
public Pair<String, List<Tag>> parseComment(int lineNumber_, int lineStart_) {
18631892
List<Tag> tags = new ArrayList<>();
18641893
Tag tag;
18651894
String description;
18661895

18671896
length = source.length();
18681897
index = 1; // Skip initial "*"
1869-
lineNumber = 0;
1870-
lineStart = 1; // Skip initial "*"
1898+
lineNumber = lineNumber_;
1899+
lineStart = lineStart_;
18711900
recoverable = true;
18721901
sloppy = true;
18731902

0 commit comments

Comments
 (0)