Now highlighting the full identifier for diag

Instead of just underlining the first char of an identifier, we now underline.
the full identifier.
This commit is contained in:
Strahinja Val Markovic 2014-01-05 16:09:40 -08:00
parent 6fdddc861b
commit 05552efd19
10 changed files with 107 additions and 13 deletions

View File

@ -107,6 +107,42 @@ std::vector< Range > GetRanges( const DiagnosticWrap &diagnostic_wrap ) {
return ranges; return ranges;
} }
Range GetLocationExtent( CXSourceLocation source_location,
CXTranslationUnit translation_unit ) {
// If you think the below code is an idiotic way of getting the source range
// for an identifier at a specific source location, you are not the only one.
// I cannot believe that this is the only way to achieve this with the
// libclang API in a robust way.
// I've tried many simpler ways of doing this and they all fail in various
// situations.
CXSourceRange range = clang_getCursorExtent(
clang_getCursor( translation_unit, source_location ) );
CXToken *tokens;
uint num_tokens;
clang_tokenize( translation_unit, range, &tokens, &num_tokens );
Location location( source_location );
Range final_range;
for ( uint i = 0; i < num_tokens; ++i ) {
Location token_location( clang_getTokenLocation( translation_unit,
tokens[ i ] ) );
if ( token_location == location ) {
std::string name = CXStringToString(
clang_getTokenSpelling( translation_unit, tokens[ i ] ) );
Location end_location = location;
end_location.column_number_ += name.length();
final_range = Range( location, end_location );
break;
}
}
clang_disposeTokens( translation_unit, tokens, num_tokens );
return final_range;
}
} // unnamed namespace } // unnamed namespace
std::vector< CXUnsavedFile > ToCXUnsavedFiles( std::vector< CXUnsavedFile > ToCXUnsavedFiles(
@ -164,7 +200,8 @@ std::vector< CompletionData > ToCompletionDataVector(
} }
Diagnostic DiagnosticWrapToDiagnostic( DiagnosticWrap diagnostic_wrap ) { Diagnostic BuildDiagnostic( DiagnosticWrap diagnostic_wrap,
CXTranslationUnit translation_unit ) {
Diagnostic diagnostic; Diagnostic diagnostic;
if ( !diagnostic_wrap ) if ( !diagnostic_wrap )
@ -178,8 +215,11 @@ Diagnostic DiagnosticWrapToDiagnostic( DiagnosticWrap diagnostic_wrap ) {
if ( diagnostic.kind_ == 'I' ) if ( diagnostic.kind_ == 'I' )
return diagnostic; return diagnostic;
diagnostic.location_ = Location( CXSourceLocation source_location =
clang_getDiagnosticLocation( diagnostic_wrap.get() ) ); clang_getDiagnosticLocation( diagnostic_wrap.get() );
diagnostic.location_ = Location( source_location );
diagnostic.location_extent_ = GetLocationExtent( source_location,
translation_unit );
diagnostic.ranges_ = GetRanges( diagnostic_wrap ); diagnostic.ranges_ = GetRanges( diagnostic_wrap );
diagnostic.text_ = CXStringToString( diagnostic.text_ = CXStringToString(
clang_getDiagnosticSpelling( diagnostic_wrap.get() ) ); clang_getDiagnosticSpelling( diagnostic_wrap.get() ) );

View File

@ -40,7 +40,8 @@ std::vector< CompletionData > ToCompletionDataVector(
std::vector< CXUnsavedFile > ToCXUnsavedFiles( std::vector< CXUnsavedFile > ToCXUnsavedFiles(
const std::vector< UnsavedFile > &unsaved_files ); const std::vector< UnsavedFile > &unsaved_files );
Diagnostic DiagnosticWrapToDiagnostic( DiagnosticWrap diagnostic_wrap ); Diagnostic BuildDiagnostic( DiagnosticWrap diagnostic_wrap,
CXTranslationUnit translation_unit );
} // namespace YouCompleteMe } // namespace YouCompleteMe

View File

@ -37,6 +37,8 @@ struct Diagnostic {
Location location_; Location location_;
Range location_extent_;
std::vector< Range > ranges_; std::vector< Range > ranges_;
// Vim's error "kind" // Vim's error "kind"

View File

@ -23,6 +23,7 @@
namespace YouCompleteMe { namespace YouCompleteMe {
// Half-open, [start, end>
struct Range { struct Range {
Range() {} Range() {}

View File

@ -270,9 +270,10 @@ void TranslationUnit::UpdateLatestDiagnostics() {
for ( uint i = 0; i < num_diagnostics; ++i ) { for ( uint i = 0; i < num_diagnostics; ++i ) {
Diagnostic diagnostic = Diagnostic diagnostic =
DiagnosticWrapToDiagnostic( BuildDiagnostic(
DiagnosticWrap( clang_getDiagnostic( clang_translation_unit_, i ), DiagnosticWrap( clang_getDiagnostic( clang_translation_unit_, i ),
clang_disposeDiagnostic ) ); clang_disposeDiagnostic ),
clang_translation_unit_ );
if ( diagnostic.kind_ != 'I' ) if ( diagnostic.kind_ != 'I' )
latest_diagnostics_.push_back( diagnostic ); latest_diagnostics_.push_back( diagnostic );

View File

@ -128,6 +128,7 @@ BOOST_PYTHON_MODULE(ycm_core)
class_< Diagnostic >( "Diagnostic" ) class_< Diagnostic >( "Diagnostic" )
.def_readonly( "ranges_", &Diagnostic::ranges_ ) .def_readonly( "ranges_", &Diagnostic::ranges_ )
.def_readonly( "location_", &Diagnostic::location_ ) .def_readonly( "location_", &Diagnostic::location_ )
.def_readonly( "location_extent_", &Diagnostic::location_extent_ )
.def_readonly( "kind_", &Diagnostic::kind_ ) .def_readonly( "kind_", &Diagnostic::kind_ )
.def_readonly( "text_", &Diagnostic::text_ ) .def_readonly( "text_", &Diagnostic::text_ )
.def_readonly( "long_formatted_text_", &Diagnostic::long_formatted_text_ ); .def_readonly( "long_formatted_text_", &Diagnostic::long_formatted_text_ );

View File

@ -62,14 +62,18 @@ def _UpdateSquiggles( buffer_number_to_line_to_diags ):
for diags in line_to_diags.itervalues(): for diags in line_to_diags.itervalues():
for diag in diags: for diag in diags:
location = diag[ 'location' ] location_extent = diag[ 'location_extent' ]
is_error = _DiagnosticIsError( diag ) is_error = _DiagnosticIsError( diag )
vimsupport.AddDiagnosticSyntaxMatch( vimsupport.AddDiagnosticSyntaxMatch(
location[ 'line_num' ] + 1, location_extent[ 'start' ][ 'line_num' ] + 1,
location[ 'column_num' ] + 1, location_extent[ 'start' ][ 'column_num' ] + 1,
location_extent[ 'end' ][ 'line_num' ] + 1,
location_extent[ 'end' ][ 'column_num' ] + 1,
is_error = is_error ) is_error = is_error )
vimsupport.EchoText( diag )
for diag_range in diag[ 'ranges' ]: for diag_range in diag[ 'ranges' ]:
vimsupport.AddDiagnosticSyntaxMatch( vimsupport.AddDiagnosticSyntaxMatch(
diag_range[ 'start' ][ 'line_num' ] + 1, diag_range[ 'start' ][ 'line_num' ] + 1,

View File

@ -118,6 +118,7 @@ def BuildDiagnosticData( diagnostic ):
return { return {
'ranges': [ BuildRangeData( x ) for x in diagnostic.ranges_ ], 'ranges': [ BuildRangeData( x ) for x in diagnostic.ranges_ ],
'location': BuildLocationData( diagnostic.location_ ), 'location': BuildLocationData( diagnostic.location_ ),
'location_extent': BuildRangeData( diagnostic.location_extent_ ),
'text': diagnostic.text_, 'text': diagnostic.text_,
'kind': diagnostic.kind_ 'kind': diagnostic.kind_
} }

View File

@ -48,7 +48,6 @@ void foo() {
filetype = 'cpp' ) filetype = 'cpp' )
results = app.post_json( '/event_notification', event_data ).json results = app.post_json( '/event_notification', event_data ).json
print results
assert_that( results, assert_that( results,
contains( contains(
has_entries( { has_entries( {
@ -66,9 +65,53 @@ void foo() {
'location': has_entries( { 'location': has_entries( {
'line_num': 2, 'line_num': 2,
'column_num': 9 'column_num': 9
} ),
'location_extent': has_entries( {
'start': has_entries( {
'line_num': 2,
'column_num': 9,
} ),
'end': has_entries( {
'line_num': 2,
'column_num': 12,
} ),
} ) } )
} ) ) ) } ) ) )
@with_setup( Setup )
def Diagnostics_ClangCompleter_SimpleLocationExtent_test():
app = TestApp( handlers.app )
contents = """
void foo() {
baz = 5;
}
// Padding to 5 lines
// Padding to 5 lines
"""
event_data = BuildRequest( compilation_flags = ['-x', 'c++'],
event_name = 'FileReadyToParse',
contents = contents,
filetype = 'cpp' )
results = app.post_json( '/event_notification', event_data ).json
assert_that( results,
contains(
has_entries( {
'location_extent': has_entries( {
'start': has_entries( {
'line_num': 2,
'column_num': 2,
} ),
'end': has_entries( {
'line_num': 2,
'column_num': 5,
} ),
} )
} ) ) )
@with_setup( Setup ) @with_setup( Setup )
def Diagnostics_ClangCompleter_PragmaOnceWarningIgnored_test(): def Diagnostics_ClangCompleter_PragmaOnceWarningIgnored_test():
app = TestApp( handlers.app ) app = TestApp( handlers.app )

View File

@ -143,7 +143,7 @@ def AddDiagnosticSyntaxMatch( line_num,
"matchadd('{0}', '\%{1}l\%{2}c')".format( group, line_num, column_num ) ) "matchadd('{0}', '\%{1}l\%{2}c')".format( group, line_num, column_num ) )
else: else:
return GetIntValue( return GetIntValue(
"matchadd('{0}', '\%{1}l\%{2}c.*\%{3}l\%{4}c')".format( "matchadd('{0}', '\%{1}l\%{2}c\_.*\%{3}l\%{4}c')".format(
group, line_num, column_num, line_end_num, column_end_num ) ) group, line_num, column_num, line_end_num, column_end_num ) )
@ -253,14 +253,14 @@ def EchoText( text, log_as_message = True ):
command = 'echom' if log_as_message else 'echo' command = 'echom' if log_as_message else 'echo'
vim.command( "{0} '{1}'".format( command, EscapeForVim( text ) ) ) vim.command( "{0} '{1}'".format( command, EscapeForVim( text ) ) )
for line in text.split( '\n' ): for line in str( text ).split( '\n' ):
EchoLine( line ) EchoLine( line )
# Echos text but truncates the text so that it all fits on one line # Echos text but truncates the text so that it all fits on one line
def EchoTextVimWidth( text ): def EchoTextVimWidth( text ):
vim_width = GetIntValue( '&columns' ) vim_width = GetIntValue( '&columns' )
truncated_text = text[ : int( vim_width * 0.9 ) ] truncated_text = str( text )[ : int( vim_width * 0.9 ) ]
truncated_text.replace( '\n', ' ' ) truncated_text.replace( '\n', ' ' )
EchoText( truncated_text, False ) EchoText( truncated_text, False )