@@ -103,7 +103,7 @@ impl Visitor<'_> {
103
103
}
104
104
if node. is_missing ( ) {
105
105
error ! (
106
- "{}:{}: parse expecting '{}'" ,
106
+ "{}:{}: parse error: expecting '{}'" ,
107
107
& self . path,
108
108
node. start_position( ) . row,
109
109
node. kind( )
@@ -134,7 +134,8 @@ impl Visitor<'_> {
134
134
let loc = Label :: Location ( self . counter ) ;
135
135
self . trap_output . push ( TrapEntry :: New ( id) ) ;
136
136
self . trap_output . push ( TrapEntry :: New ( loc) ) ;
137
- self . trap_output . push ( location_for ( & self . path , loc, node) ) ;
137
+ self . trap_output
138
+ . push ( location_for ( & self . source , & self . path , loc, node) ) ;
138
139
let table_name = node_type_name ( node. kind ( ) , node. is_named ( ) ) ;
139
140
let args: Option < Vec < Arg > > ;
140
141
if fields. is_empty ( ) {
@@ -272,11 +273,50 @@ fn sliced_source_arg(source: &Vec<u8>, n: Node) -> Arg {
272
273
}
273
274
274
275
// Emit a 'Located' TrapEntry for the provided node, appropriately calibrated.
275
- fn location_for < ' a > ( fp : & String , label : Label , n : Node ) -> TrapEntry {
276
- let start_line = n. start_position ( ) . row ;
277
- let start_col = n. start_position ( ) . column ;
278
- let end_line = n. end_position ( ) . row ;
279
- let end_col = n. end_position ( ) . column ;
276
+ fn location_for < ' a > ( source : & Vec < u8 > , fp : & String , label : Label , n : Node ) -> TrapEntry {
277
+ // Tree-sitter row, column values are 0-based while CodeQL starts
278
+ // counting at 1. In addition Tree-sitter's row and column for the
279
+ // end position are exclusive while CodeQL's end positions are inclusive.
280
+ // This means that all values should be incremented by 1 and in addition the
281
+ // end position needs to be shift 1 to the left. In most cases this means
282
+ // simply incrementing all values except the end column except in cases where
283
+ // the end column is 0 (start of a line). In such cases the end position must be
284
+ // set to the end of the previous line.
285
+ let start_line = n. start_position ( ) . row + 1 ;
286
+ let start_col = n. start_position ( ) . column + 1 ;
287
+ let mut end_line = n. end_position ( ) . row + 1 ;
288
+ let mut end_col = n. end_position ( ) . column ;
289
+ if end_col == 0 {
290
+ if start_line >= end_line {
291
+ // the range is empty, clip it to sensible values
292
+ end_line = start_line;
293
+ end_col = start_col - 1 ;
294
+ } else {
295
+ let mut index = n. end_byte ( ) ;
296
+ // end_col = 0 means that we are the start of a line
297
+ // unfortunately 0 is invalid as column number, therefore
298
+ // we should update the end location to be the end of the
299
+ // previous line
300
+ if index > 0 && index <= source. len ( ) {
301
+ index -= 1 ;
302
+ if source[ index] != b'\n' {
303
+ error ! ( "expecting a line break symbol, but none found while correcting end column value" ) ;
304
+ }
305
+ end_line -= 1 ;
306
+ end_col = 1 ;
307
+ while index > 0 && source[ index - 1 ] != b'\n' {
308
+ index -= 1 ;
309
+ end_col += 1 ;
310
+ }
311
+ } else {
312
+ error ! (
313
+ "cannot correct end column value: end_byte index {} is not in range [0,{}]" ,
314
+ index,
315
+ source. len( )
316
+ ) ;
317
+ }
318
+ }
319
+ }
280
320
TrapEntry :: Located ( vec ! [
281
321
Arg :: Label ( label) ,
282
322
Arg :: String ( fp. to_owned( ) ) ,
0 commit comments