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
endfunction
function! s:IdentifierFinishedOperations()
if !pyeval( 'ycm.CurrentIdentifierFinished()' )
return
@ -273,6 +274,14 @@ function! youcompleteme#ClangOmniComplete( findstart, base )
endif
endfunction
function! youcompleteme#CurrentFileDiagnostics()
if s:ClangEnabledForCurrentFile()
return pyeval( 'clangcomp.GetDiagnosticsForCurrentFile()' )
endif
return []
endfunction
" This is basic vim plugin boilerplate
let &cpo = 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 )
# 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()
#############################################################################
# We want warnings if we accidentally use C++11 features
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()
#############################################################################

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(
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
@ -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()
{
lock_guard< mutex > lock( file_parse_task_mutex_ );

View File

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

View File

@ -18,6 +18,8 @@
#ifndef COMPLETIONDATA_H_2JCTF1NU
#define COMPLETIONDATA_H_2JCTF1NU
#include <string>
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>
const typename Container::mapped_type &
typename Container::mapped_type
FindWithDefault( Container &container,
const Key &key,
const typename Container::mapped_type &value )
{
typename Container::iterator it = container.find( key );
return it != container.end() ? *it : value;
return it != container.end() ? it->second : value;
}
} // namespace YouCompleteMe

View File

@ -19,6 +19,7 @@
#include "ClangCompleter.h"
#include "Future.h"
#include "CompletionData.h"
#include "Diagnostic.h"
#include "UnsavedFile.h"
#include <boost/python.hpp>
@ -47,6 +48,16 @@ BOOST_PYTHON_MODULE(indexer)
"CompletionVec" )
.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" )
.def( "ResultsReady", &Future< AsyncResults >::ResultsReady )
.def( "GetResults", &Future< AsyncResults >::GetResults );
@ -86,6 +97,7 @@ BOOST_PYTHON_MODULE(indexer)
.def( "EnableThreading", &ClangCompleter::EnableThreading )
.def( "SetGlobalCompileFlags", &ClangCompleter::SetGlobalCompileFlags )
.def( "SetFileCompileFlags", &ClangCompleter::SetFileCompileFlags )
.def( "DiagnosticsForFile", &ClangCompleter::DiagnosticsForFile )
.def( "UpdatingTranslationUnit", &ClangCompleter::UpdatingTranslationUnit )
.def( "UpdateTranslationUnitAsync",
&ClangCompleter::UpdateTranslationUnitAsync )

View File

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

View File

@ -184,6 +184,12 @@ class ClangCompleter( Completer ):
self.GetUnsavedFilesVector() )
def GetDiagnosticsForCurrentFile( self ):
return [ DiagnosticToDict( x ) for x in
self.completer.DiagnosticsForFile( vim.current.buffer.name ) ]
def PostVimMessage( message ):
# TODO: escape the message string before formating it
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():
"""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."""