Browse Source

Take care of start column in multiline diags for detailed diag popups

Previously, we have always used the diagnostics start column of the
*starting* line of a multiline diagnostic. This is wrong, as the
starting column for a line in the middle of a multiline diagnostic is
always 1.

Previous patch just happens to work if the start column of the first
line of the diagnostic is also 1.
Boris Staletic 1 year ago
parent
commit
06aa1077fb
2 changed files with 77 additions and 54 deletions
  1. 5 1
      python/ycm/vimsupport.py
  2. 72 53
      test/diagnostics.test.vim

+ 5 - 1
python/ycm/vimsupport.py

@@ -288,18 +288,22 @@ def GetTextPropertyForDiag( buffer_number, line_number, diag ):
   end_line = end[ 'line_num' ]
   if start_line == end_line:
     length = end[ 'column_num' ] - start[ 'column_num' ]
+    column = start[ 'column_num' ]
   elif start_line == line_number:
     # -1 switches to 0-based indexing.
     current_line_len = len( vim.buffers[ buffer_number ][ line_number - 1 ] )
     # +2 includes the start columnand accounts for properties at the end of line
     # covering \n as well.
     length = current_line_len - start[ 'column_num' ] + 2
+    column = start[ 'column_num' ]
   elif end_line == line_number:
     length = end[ 'column_num' ] - 1
+    column = 1
   else:
     # -1 switches to 0-based indexing.
     # +1 accounts for properties at the end of line covering \n as well.
     length = len( vim.buffers[ buffer_number ][ line_number - 1 ] ) + 1
+    column = 1
   if diag[ 'kind' ] == 'ERROR':
     property_name = 'YcmErrorProperty'
   else:
@@ -309,7 +313,7 @@ def GetTextPropertyForDiag( buffer_number, line_number, diag ):
                           f'{{ "bufnr": { buffer_number }, '
                              f'"types": [ "{ property_name }" ] }} )' )
     return next( filter(
-        lambda p: start[ 'column_num' ] == int( p[ 'col' ] ) and
+        lambda p: column == int( p[ 'col' ] ) and
                   length == int( p[ 'length' ] ),
         vim_props ) )
   else:

+ 72 - 53
test/diagnostics.test.vim

@@ -6,6 +6,7 @@ function! SetUp()
   let g:ycm_log_level = 'DEBUG'
   let g:ycm_always_populate_location_list = 1
   let g:ycm_enable_semantic_highlighting = 1
+  let g:ycm_auto_hover = ''
 
   " diagnostics take ages
   let g:ycm_test_min_delay = 7
@@ -348,15 +349,15 @@ function! Test_ShowDetailedDiagnostic_Popup_WithCharacters()
   %bwipe!
 endfunction
 
-function! Test_ShowDetailedDiagnostic_Popup_MultilineDiag()
+function! Test_ShowDetailedDiagnostic_Popup_MultilineDiagNotFromStartOfLine()
   let f = tempname() . '.cc'
   execut 'edit' f
   call setline( 1, [
         \   'int main () {',
-        \   'const int &&',
-        \   '        /* */',
-        \   '    rd = 1;',
-        \   'rd = 4;',
+        \   '  int a \',
+        \   '=\',
+        \   '=',
+        \   '3;',
         \   '}',
         \ ] )
   call youcompleteme#test#setup#WaitForInitialParse( {} )
@@ -367,62 +368,80 @@ function! Test_ShowDetailedDiagnostic_Popup_MultilineDiag()
          \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
     \ ) ) } )
 
-  " Start of multiline diagnostic.
-  call cursor( [ 2, 1 ] )
-  YcmShowDetailedDiagnostic popup
+  call test_override( 'char_avail', 1 )
 
-  let popup_location = screenpos( bufwinid( '%' ), 3, 13 )
-  let id = popup_locate( popup_location[ 'row' ], popup_location[ 'col' ] )
-  call assert_notequal( 0, id, "Couldn't find popup!" )
+  for cursor_pos in [ [ 2, 9 ], [ 3, 1], [ 4, 1 ] ]
+    call cursor( cursor_pos )
+    YcmShowDetailedDiagnostic popup
+
+    call assert_equal( len( popup_list() ), 1 )
+    let id = popup_list()[ 0 ]
+    call assert_notequal( 0, id, "Couldn't find popup!" )
+    call assert_equal( [ 3, 10 ], win_screenpos( id ) )
+
+    call youcompleteme#test#popup#CheckPopupPosition( id, {
+          \ 'visible': 1,
+          \ 'col': 10,
+          \ 'line': 3,
+          \ } )
+    call assert_match(
+          \ "^Invalid '==' at end of declaration; did you mean '='?.*",
+          \ getbufline( winbufnr(id), 1, '$' )[ 0 ] )
+    " From vim's test_popupwin.vim
+    " trigger the check for last_cursormoved by going into insert mode
+    call feedkeys( "ji\<Esc>", 'xt' )
+    call assert_equal( {}, popup_getpos( id ) )
+  endfor
 
-  call youcompleteme#test#popup#CheckPopupPosition( id, {
-        \ 'visible': 1,
-        \ 'col': 13,
-        \ 'line': 3,
-        \ } )
-  call assert_match(
-        \ "^Variable 'rd' declared const here.*",
-        \ getbufline( winbufnr(id), 1, '$' )[ 0 ] )
-
-  " Middle of multiline diagnostic.
-  call cursor( [ 3, 9 ] )
-  YcmShowDetailedDiagnostic popup
+  call test_override( 'ALL', 0 )
 
-  let popup_location = screenpos( bufwinid( '%' ), 3, 13 )
-  let id = popup_locate( popup_location[ 'row' ], popup_location[ 'col' ] )
-  call assert_notequal( 0, id, "Couldn't find popup!" )
+  %bwipe!
+endfunction
 
-  " End of multiline diagnostic.
-  call youcompleteme#test#popup#CheckPopupPosition( id, {
-        \ 'visible': 1,
-        \ 'col': 13,
-        \ 'line': 3,
-        \ } )
-  call assert_match(
-        \ "^Variable 'rd' declared const here.*",
-        \ getbufline( winbufnr(id), 1, '$' )[ 0 ] )
+function! Test_ShowDetailedDiagnostic_Popup_MultilineDiagFromStartOfLine()
+  let f = tempname() . '.cc'
+  execut 'edit' f
+  call setline( 1, [
+        \   'int main () {',
+        \   'const int &&',
+        \   '        /* */',
+        \   '    rd = 1;',
+        \   'rd = 4;',
+        \   '}',
+        \ ] )
+  call youcompleteme#test#setup#WaitForInitialParse( {} )
 
-  call cursor( [ 4, 5 ] )
-  YcmShowDetailedDiagnostic popup
+  call WaitForAssert( {->
+    \ assert_true(
+      \ py3eval(
+         \ 'len( ycm_state.CurrentBuffer()._diag_interface._diagnostics )'
+    \ ) ) } )
 
-  let popup_location = screenpos( bufwinid( '%' ), 3, 13 )
-  let id = popup_locate( popup_location[ 'row' ], popup_location[ 'col' ] )
-  call assert_notequal( 0, id, "Couldn't find popup!" )
+  call test_override( 'char_avail', 1 )
 
-  call youcompleteme#test#popup#CheckPopupPosition( id, {
-        \ 'visible': 1,
-        \ 'col': 13,
-        \ 'line': 3,
-        \ } )
-  call assert_match(
-        \ "^Variable 'rd' declared const here.*",
-        \ getbufline( winbufnr(id), 1, '$' )[ 0 ] )
+  for cursor_pos in [ [ 2, 1 ], [ 3, 9 ], [ 4, 5 ] ]
+    call cursor( cursor_pos )
+    YcmShowDetailedDiagnostic popup
+
+    call assert_equal( 1, len( popup_list() ) )
+    let id = popup_list()[ 0 ]
+    call assert_notequal( 0, id, "Couldn't find popup!" )
+    call assert_equal( [ 3, 13 ], win_screenpos( id ) )
+
+    call youcompleteme#test#popup#CheckPopupPosition( id, {
+          \ 'visible': 1,
+          \ 'col': 13,
+          \ 'line': 3,
+          \ } )
+    call assert_match(
+          \ "^Variable 'rd' declared const here.*",
+          \ getbufline( winbufnr(id), 1, '$' )[ 0 ] )
+    " From vim's test_popupwin.vim
+    " trigger the check for last_cursormoved by going into insert mode
+    call feedkeys( "ji\<Esc>ki\<Esc>", 'xt' )
+    call assert_equal( {}, popup_getpos( id ) )
+  endfor
 
-  " From vim's test_popupwin.vim
-  " trigger the check for last_cursormoved by going into insert mode
-  call test_override( 'char_avail', 1 )
-  call feedkeys( "ji\<Esc>", 'xt' )
-  call assert_equal( {}, popup_getpos( id ) )
   call test_override( 'ALL', 0 )
 
   %bwipe!