Adding diagnostic extraction support

Next step is to add support to Syntastic so that it uses this new functionality
This commit is contained in:
Strahinja Val Markovic 2012-07-28 15:27:30 -07:00
parent bfafad4f50
commit 958a008462
10 changed files with 180 additions and 5 deletions

View File

@ -132,6 +132,7 @@ function! s:OnInsertLeave()
let s:omnifunc_mode = 0 let s:omnifunc_mode = 0
endfunction endfunction
function! s:IdentifierFinishedOperations() function! s:IdentifierFinishedOperations()
if !pyeval( 'ycm.CurrentIdentifierFinished()' ) if !pyeval( 'ycm.CurrentIdentifierFinished()' )
return return
@ -273,6 +274,14 @@ function! youcompleteme#ClangOmniComplete( findstart, base )
endif endif
endfunction endfunction
function! youcompleteme#CurrentFileDiagnostics()
if s:ClangEnabledForCurrentFile()
return pyeval( 'clangcomp.GetDiagnosticsForCurrentFile()' )
endif
return []
endfunction
" This is basic vim plugin boilerplate " This is basic vim plugin boilerplate
let &cpo = s:save_cpo let &cpo = s:save_cpo
unlet s:save_cpo unlet s:save_cpo

View File

@ -80,14 +80,14 @@ set_target_properties( ${PROJECT_NAME} PROPERTIES
if( CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG ) if( CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG )
# We want all warnings, and warnings should be treated as errors # We want all warnings, and warnings should be treated as errors
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror" )
endif() endif()
############################################################################# #############################################################################
# We want warnings if we accidentally use C++11 features # We want warnings if we accidentally use C++11 features
if ( COMPILER_IS_CLANG ) if ( COMPILER_IS_CLANG )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wc++98-compat") set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wc++98-compat" )
endif() endif()
############################################################################# #############################################################################

View File

@ -168,6 +168,28 @@ char CursorKindToVimKind( CXCursorKind kind )
} }
char DiagnosticSeverityToType( CXDiagnosticSeverity severity )
{
switch ( severity )
{
case CXDiagnostic_Ignored:
case CXDiagnostic_Note:
return 'I';
case CXDiagnostic_Warning:
return 'W';
case CXDiagnostic_Error:
case CXDiagnostic_Fatal:
return 'E';
default:
return 'E';
}
}
// TODO: this should be a constructor
CompletionData CompletionResultToCompletionData( CompletionData CompletionResultToCompletionData(
const CXCompletionResult &completion_result ) const CXCompletionResult &completion_result )
{ {
@ -238,6 +260,34 @@ std::vector< CompletionData > ToCompletionDataVector(
} }
Diagnostic CXDiagnosticToDiagnostic( CXDiagnostic cxdiagnostic )
{
Diagnostic diagnostic;
diagnostic.kind_ = DiagnosticSeverityToType(
clang_getDiagnosticSeverity( cxdiagnostic ) );
// If this is an "ignored" diagnostic, there's no point in continuing since we
// won't display those to the user
if ( diagnostic.kind_ == 'I' )
return diagnostic;
CXSourceLocation location = clang_getDiagnosticLocation( cxdiagnostic );
CXFile file;
uint unused_offset;
clang_getSpellingLocation( location,
&file,
&diagnostic.line_number_,
&diagnostic.column_number_,
&unused_offset );
diagnostic.filename_ = CXStringToString( clang_getFileName( file ) );
diagnostic.text_ = CXStringToString(
clang_getDiagnosticSpelling( cxdiagnostic ) );
clang_disposeDiagnostic( cxdiagnostic );
return diagnostic;
}
} // unnamed namespace } // unnamed namespace
@ -287,6 +337,32 @@ void ClangCompleter::SetFileCompileFlags(
} }
std::vector< Diagnostic > ClangCompleter::DiagnosticsForFile(
const std::string &filename )
{
CXTranslationUnit unit = FindWithDefault( filename_to_translation_unit_,
filename,
NULL );
std::vector< Diagnostic > diagnostics;
if ( !unit )
return diagnostics;
uint num_diagnostics = clang_getNumDiagnostics( unit );
diagnostics.reserve( num_diagnostics );
for ( uint i = 0; i < num_diagnostics; ++i )
{
Diagnostic diagnostic = CXDiagnosticToDiagnostic(
clang_getDiagnostic( unit, i ) );
if ( diagnostic.kind_ != 'I' )
diagnostics.push_back( diagnostic );
}
return diagnostics;
}
bool ClangCompleter::UpdatingTranslationUnit() bool ClangCompleter::UpdatingTranslationUnit()
{ {
lock_guard< mutex > lock( file_parse_task_mutex_ ); lock_guard< mutex > lock( file_parse_task_mutex_ );

View File

@ -21,6 +21,7 @@
#include "ConcurrentLatestValue.h" #include "ConcurrentLatestValue.h"
#include "Future.h" #include "Future.h"
#include "UnsavedFile.h" #include "UnsavedFile.h"
#include "Diagnostic.h"
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
@ -60,6 +61,8 @@ public:
void SetFileCompileFlags( const std::string &filename, void SetFileCompileFlags( const std::string &filename,
const std::vector< std::string > &flags ); const std::vector< std::string > &flags );
std::vector< Diagnostic > DiagnosticsForFile( const std::string &filename );
bool UpdatingTranslationUnit(); bool UpdatingTranslationUnit();
void UpdateTranslationUnit( const std::string &filename, void UpdateTranslationUnit( const std::string &filename,

View File

@ -18,6 +18,8 @@
#ifndef COMPLETIONDATA_H_2JCTF1NU #ifndef COMPLETIONDATA_H_2JCTF1NU
#define COMPLETIONDATA_H_2JCTF1NU #define COMPLETIONDATA_H_2JCTF1NU
#include <string>
namespace YouCompleteMe namespace YouCompleteMe
{ {

54
cpp/ycm/Diagnostic.h Normal file
View File

@ -0,0 +1,54 @@
// Copyright (C) 2011, 2012 Strahinja Val Markovic <val@markovic.io>
//
// This file is part of YouCompleteMe.
//
// YouCompleteMe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// YouCompleteMe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
#ifndef DIAGNOSTIC_H_BZH3BWIZ
#define DIAGNOSTIC_H_BZH3BWIZ
#include "standard.h"
#include <string>
namespace YouCompleteMe
{
struct Diagnostic
{
bool operator== ( const Diagnostic &other ) const
{
return
line_number_ == other.line_number_ &&
column_number_ == other.column_number_ &&
kind_ == other.kind_ &&
text_ == other.text_;
}
uint line_number_;
uint column_number_;
// Vim's error "kind"
// 'I' -> informational
// 'W' -> warning
// 'E' -> error
char kind_;
std::string filename_;
std::string text_;
};
} // namespace YouCompleteMe
#endif /* end of include guard: DIAGNOSTIC_H_BZH3BWIZ */

View File

@ -55,13 +55,13 @@ bool ContainsKey( Container &container, const Key &key )
template <class Container, class Key> template <class Container, class Key>
const typename Container::mapped_type & typename Container::mapped_type
FindWithDefault( Container &container, FindWithDefault( Container &container,
const Key &key, const Key &key,
const typename Container::mapped_type &value ) const typename Container::mapped_type &value )
{ {
typename Container::iterator it = container.find( key ); typename Container::iterator it = container.find( key );
return it != container.end() ? *it : value; return it != container.end() ? it->second : value;
} }
} // namespace YouCompleteMe } // namespace YouCompleteMe

View File

@ -19,6 +19,7 @@
#include "ClangCompleter.h" #include "ClangCompleter.h"
#include "Future.h" #include "Future.h"
#include "CompletionData.h" #include "CompletionData.h"
#include "Diagnostic.h"
#include "UnsavedFile.h" #include "UnsavedFile.h"
#include <boost/python.hpp> #include <boost/python.hpp>
@ -47,6 +48,16 @@ BOOST_PYTHON_MODULE(indexer)
"CompletionVec" ) "CompletionVec" )
.def( vector_indexing_suite< std::vector< CompletionData > >() ); .def( vector_indexing_suite< std::vector< CompletionData > >() );
class_< Diagnostic >( "Diagnostic" )
.def_readonly( "line_number_", &Diagnostic::line_number_ )
.def_readonly( "column_number_", &Diagnostic::column_number_ )
.def_readonly( "kind_", &Diagnostic::kind_ )
.def_readonly( "filename_", &Diagnostic::filename_ )
.def_readonly( "text_", &Diagnostic::text_ );
class_< std::vector< Diagnostic > >( "DiagnosticVec" )
.def( vector_indexing_suite< std::vector< Diagnostic > >() );
class_< Future< AsyncResults > >( "Future" ) class_< Future< AsyncResults > >( "Future" )
.def( "ResultsReady", &Future< AsyncResults >::ResultsReady ) .def( "ResultsReady", &Future< AsyncResults >::ResultsReady )
.def( "GetResults", &Future< AsyncResults >::GetResults ); .def( "GetResults", &Future< AsyncResults >::GetResults );
@ -86,6 +97,7 @@ BOOST_PYTHON_MODULE(indexer)
.def( "EnableThreading", &ClangCompleter::EnableThreading ) .def( "EnableThreading", &ClangCompleter::EnableThreading )
.def( "SetGlobalCompileFlags", &ClangCompleter::SetGlobalCompileFlags ) .def( "SetGlobalCompileFlags", &ClangCompleter::SetGlobalCompileFlags )
.def( "SetFileCompileFlags", &ClangCompleter::SetFileCompileFlags ) .def( "SetFileCompileFlags", &ClangCompleter::SetFileCompileFlags )
.def( "DiagnosticsForFile", &ClangCompleter::DiagnosticsForFile )
.def( "UpdatingTranslationUnit", &ClangCompleter::UpdatingTranslationUnit ) .def( "UpdatingTranslationUnit", &ClangCompleter::UpdatingTranslationUnit )
.def( "UpdateTranslationUnitAsync", .def( "UpdateTranslationUnitAsync",
&ClangCompleter::UpdateTranslationUnitAsync ) &ClangCompleter::UpdateTranslationUnitAsync )

View File

@ -15,8 +15,9 @@
" You should have received a copy of the GNU General Public License " You should have received a copy of the GNU General Public License
" along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. " along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
if exists("g:loaded_youcompleteme") if exists( "g:loaded_youcompleteme" )
finish finish
" TODO: check for python too
elseif v:version < 703 || !has( 'patch584' ) elseif v:version < 703 || !has( 'patch584' )
echohl WarningMsg | echohl WarningMsg |
\ echomsg "YouCompleteMe unavailable: requires Vim 7.3.584+" | \ echomsg "YouCompleteMe unavailable: requires Vim 7.3.584+" |

View File

@ -184,6 +184,12 @@ class ClangCompleter( Completer ):
self.GetUnsavedFilesVector() ) self.GetUnsavedFilesVector() )
def GetDiagnosticsForCurrentFile( self ):
return [ DiagnosticToDict( x ) for x in
self.completer.DiagnosticsForFile( vim.current.buffer.name ) ]
def PostVimMessage( message ): def PostVimMessage( message ):
# TODO: escape the message string before formating it # TODO: escape the message string before formating it
vim.command( 'echohl WarningMsg | echomsg "{0}" | echohl None' vim.command( 'echohl WarningMsg | echomsg "{0}" | echohl None'
@ -210,6 +216,18 @@ def CompletionDataToDict( completion_data ):
} }
def DiagnosticToDict( diagnostic ):
# see :h getqflist for a description of the dictionary fields
return {
'bufnr' : int( vim.eval( "bufnr('" + diagnostic.filename_ + "', 1)" ) ),
'lnum' : diagnostic.line_number_,
'col' : diagnostic.column_number_,
'text' : diagnostic.text_,
'type' : diagnostic.kind_,
'valid' : 1
}
def CurrentColumn(): def CurrentColumn():
"""Do NOT access the CurrentColumn in vim.current.line. It doesn't exist yet. """Do NOT access the CurrentColumn in vim.current.line. It doesn't exist yet.
Only the chars before the current column exist in vim.current.line.""" Only the chars before the current column exist in vim.current.line."""