Skip to content

Commit b63d2e8

Browse files
authored
Merge pull request #1728 from bstaletic/detailed-diag-priority
Sort diagnostics according to severity for detailed diag responses
2 parents 0ce532e + 5fb0927 commit b63d2e8

File tree

7 files changed

+62
-5
lines changed

7 files changed

+62
-5
lines changed

ycmd/completers/cs/cs_completer.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,9 @@ def GetDetailedDiagnostic( self, request_data ):
316316
if not diagnostics:
317317
raise ValueError( NO_DIAGNOSTIC_MESSAGE )
318318

319+
# Prefer errors to warnings and warnings to infos.
320+
diagnostics.sort( key = _CsDiagnosticToLspSeverity )
321+
319322
closest_diagnostic = None
320323
distance_to_closest_diagnostic = 999
321324

@@ -968,3 +971,11 @@ def _ModifiedFilesToFixIt( changes, request_data ):
968971
request_data[ 'line_num' ],
969972
request_data[ 'column_codepoint' ] ),
970973
chunks )
974+
975+
976+
def _CsDiagnosticToLspSeverity( diagnostic ):
977+
if diagnostic.kind_ == 'ERROR':
978+
return 1
979+
if diagnostic.kind_ == 'WARNING':
980+
return 2
981+
return 3

ycmd/completers/language_server/language_server_completer.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,9 +1663,14 @@ def GetDetailedDiagnostic( self, request_data ):
16631663
return responses.BuildDisplayMessageResponse(
16641664
'No diagnostics for current file.' )
16651665

1666+
# Prefer errors to warnings and warnings to infos.
1667+
diagnostics.sort( key = lambda d: d[ 'severity' ] )
1668+
1669+
# request_data uses 1-based offsets, but LSP diagnostics use 0-based.
1670+
# It's easier to shift this one offset by -1 than to shift all diag ranges.
16661671
current_column = lsp.CodepointsToUTF16CodeUnits(
16671672
GetFileLines( request_data, current_file )[ current_line_lsp ],
1668-
request_data[ 'column_codepoint' ] )
1673+
request_data[ 'column_codepoint' ] ) - 1
16691674
minimum_distance = None
16701675

16711676
message = 'No diagnostics for current line.'
@@ -2981,13 +2986,15 @@ def _DistanceOfPointToRange( point, range ):
29812986
# Single-line range.
29822987
if start[ 'line' ] == end[ 'line' ]:
29832988
# 0 if point is within range, otherwise distance from start/end.
2984-
return max( 0, point[ 'character' ] - end[ 'character' ],
2989+
# +1 takes into account that, visually, end is one character farther.
2990+
return max( 0, point[ 'character' ] - end[ 'character' ] + 1,
29852991
start[ 'character' ] - point[ 'character' ] )
29862992

29872993
if start[ 'line' ] == point[ 'line' ]:
29882994
return max( 0, start[ 'character' ] - point[ 'character' ] )
29892995
if end[ 'line' ] == point[ 'line' ]:
2990-
return max( 0, point[ 'character' ] - end[ 'character' ] )
2996+
# +1 takes into account that, visually, end is one character farther.
2997+
return max( 0, point[ 'character' ] - end[ 'character' ] + 1 )
29912998
# If not on the first or last line, then point is within range for sure.
29922999
return 0
29933000

ycmd/completers/typescript/typescript_completer.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,9 @@ def GetDetailedDiagnostic( self, request_data ):
656656
if not ts_diagnostics_on_line:
657657
raise ValueError( NO_DIAGNOSTIC_MESSAGE )
658658

659+
# Prefer errors to warnings and warnings to infos.
660+
ts_diagnostics_on_line.sort( key = _TsDiagToLspSeverity )
661+
659662
closest_ts_diagnostic = None
660663
distance_to_closest_ts_diagnostic = None
661664

@@ -1264,3 +1267,12 @@ def _BuildTsFormatRange( request_data ):
12641267

12651268
def _DisplayPartsToString( parts ):
12661269
return ''.join( [ p[ 'text' ] for p in parts ] )
1270+
1271+
1272+
def _TsDiagToLspSeverity( diag ):
1273+
category = diag[ 'category' ]
1274+
if category == 'error':
1275+
return 1
1276+
if category == 'warning':
1277+
return 2
1278+
return 3

ycmd/tests/clangd/diagnostics_test.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ def test_Diagnostics_Works( self, app ):
151151
has_entry( 'message', contains_string( "Expected ';'" ) ) )
152152

153153

154+
@IsolatedYcmd( { 'clangd_args': [ '--clang-tidy=0' ] } )
155+
def test_Diagnostics_WarningAndErrorOnSameColumn( self, app ):
156+
for col in [ 2, 22 ]:
157+
with self.subTest( col = col ):
158+
filepath = PathToTestFile( 'diag_ranges', 'detailed_diagnostic.cc' )
159+
request = { 'filepath': filepath, 'filetype': 'cpp', 'column_num': col }
160+
test = { 'request': request, 'route': '/receive_messages' }
161+
RunAfterInitialized( app, test )
162+
diag_data = BuildRequest( line_num = 3,
163+
filepath = filepath,
164+
filetype = 'cpp' )
165+
result = app.post_json( '/detailed_diagnostic', diag_data ).json
166+
assert_that( result,
167+
has_entry( 'message',
168+
contains_string( 'uninitialized' ) ) )
169+
170+
154171
@IsolatedYcmd()
155172
def test_Diagnostics_Multiline( self, app ):
156173
contents = """
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-Wno-error
2+
-Wfor-loop-analysis
3+
-Wno-error=for-loop-analysis
4+
-Werror=uninitialized
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
int main() {
2+
int i;
3+
for (int j; j;i){}
4+
}

ycmd/tests/language_server/language_server_completer_test.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,7 +1497,8 @@ def test_LanguageServerCompleter_DistanceOfPointToRange_SingleLineRange(
14971497
# Point inside range.
14981498
_Check_Distance( ( 0, 4 ), ( 0, 2 ), ( 0, 5 ) , 0 )
14991499
# Point to the right of range.
1500-
_Check_Distance( ( 0, 8 ), ( 0, 2 ), ( 0, 5 ) , 3 )
1500+
# +1 because diags are half-open ranges.
1501+
_Check_Distance( ( 0, 8 ), ( 0, 2 ), ( 0, 5 ) , 4 )
15011502

15021503

15031504
def test_LanguageServerCompleter_DistanceOfPointToRange_MultiLineRange(
@@ -1507,4 +1508,5 @@ def test_LanguageServerCompleter_DistanceOfPointToRange_MultiLineRange(
15071508
# Point inside range.
15081509
_Check_Distance( ( 1, 4 ), ( 0, 2 ), ( 3, 5 ) , 0 )
15091510
# Point to the right of range.
1510-
_Check_Distance( ( 3, 8 ), ( 0, 2 ), ( 3, 5 ) , 3 )
1511+
# +1 because diags are half-open ranges.
1512+
_Check_Distance( ( 3, 8 ), ( 0, 2 ), ( 3, 5 ) , 4 )

0 commit comments

Comments
 (0)