diff --git a/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp b/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp index c40aa1ee..e70f365a 100644 --- a/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp +++ b/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp @@ -61,4 +61,21 @@ TEST( ClangCompleterTest, CandidatesForQueryAndLocationInFileAsync ) { EXPECT_TRUE( !completions_future.GetResults()->empty() ); } +TEST( ClangCompleterTest, GetDefinitionLocation ) { + ClangCompleter completer; + std::string filename = PathToTestFile( "basic.cpp" ).string(); + + // Clang operates on the reasonable assumption that line and column numbers + // are 1-based. + Location actual_location = + completer.GetDefinitionLocation( + filename, + 9, + 3, + std::vector< UnsavedFile >(), + std::vector< std::string >() ); + + EXPECT_EQ( Location( filename, 1, 8 ), actual_location ); +} + } // namespace YouCompleteMe diff --git a/cpp/ycm/tests/testdata/basic.cpp b/cpp/ycm/tests/testdata/basic.cpp index b5bdf7f6..722d6bc3 100644 --- a/cpp/ycm/tests/testdata/basic.cpp +++ b/cpp/ycm/tests/testdata/basic.cpp @@ -2,7 +2,7 @@ struct Foo { int x; int y; char c; -} +}; int main() { diff --git a/python/ycm/client/command_request.py b/python/ycm/client/command_request.py index 4c2630fc..d3fe5ad3 100644 --- a/python/ycm/client/command_request.py +++ b/python/ycm/client/command_request.py @@ -63,7 +63,7 @@ class CommandRequest( BaseRequest ): else: vimsupport.JumpToLocation( self._response[ 'filepath' ], self._response[ 'line_num' ] + 1, - self._response[ 'column_num' ] ) + self._response[ 'column_num' ] + 1) diff --git a/python/ycm/completers/cpp/clang_completer.py b/python/ycm/completers/cpp/clang_completer.py index a4028f5a..3e2e318a 100644 --- a/python/ycm/completers/cpp/clang_completer.py +++ b/python/ycm/completers/cpp/clang_completer.py @@ -24,7 +24,7 @@ from ycm.server import responses from ycm import extra_conf_store from ycm.utils import ToUtf8IfNeeded from ycm.completers.completer import Completer -from ycm.completers.cpp.flags import Flags +from ycm.completers.cpp.flags import Flags, PrepareFlagsForClang CLANG_FILETYPES = set( [ 'c', 'cpp', 'objc', 'objcpp' ] ) MIN_LINES_IN_FILE_TO_PARSE = 5 @@ -96,7 +96,7 @@ class ClangCompleter( Completer ): return responses.BuildDisplayMessageResponse( PARSING_FILE_MESSAGE ) - flags = self.flags.FlagsForFile( filename ) + flags = self._FlagsForRequest( request_data ) if not flags: self.completions_future = None self._logger.info( NO_COMPILE_FLAGS_MESSAGE ) @@ -160,14 +160,12 @@ class ClangCompleter( Completer ): filename = request_data[ 'filepath' ] if not filename: self._logger.warning( INVALID_FILE_MESSAGE ) - return responses.BuildDisplayMessageResponse( - INVALID_FILE_MESSAGE ) + raise ValueError( INVALID_FILE_MESSAGE ) - flags = self.flags.FlagsForFile( filename ) + flags = self._FlagsForRequest( request_data ) if not flags: self._logger.info( NO_COMPILE_FLAGS_MESSAGE ) - return responses.BuildDisplayMessageResponse( - NO_COMPILE_FLAGS_MESSAGE ) + raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] + 1 @@ -186,8 +184,8 @@ class ClangCompleter( Completer ): raise RuntimeError( 'Can\'t jump to definition.' ) return responses.BuildGoToResponse( location.filename_, - location.line_number_, - location.column_number_ ) + location.line_number_ - 1, + location.column_number_ - 1) def _GoToDeclaration( self, request_data ): @@ -196,8 +194,8 @@ class ClangCompleter( Completer ): raise RuntimeError( 'Can\'t jump to declaration.' ) return responses.BuildGoToResponse( location.filename_, - location.line_number_, - location.column_number_ ) + location.line_number_ - 1, + location.column_number_ - 1) def _GoToDefinitionElseDeclaration( self, request_data ): @@ -208,8 +206,8 @@ class ClangCompleter( Completer ): raise RuntimeError( 'Can\'t jump to definition or declaration.' ) return responses.BuildGoToResponse( location.filename_, - location.line_number_, - location.column_number_ ) + location.line_number_ - 1, + location.column_number_ - 1) @@ -234,7 +232,7 @@ class ClangCompleter( Completer ): self.extra_parse_desired = True return - flags = self.flags.FlagsForFile( filename ) + flags = self._FlagsForRequest( request_data ) if not flags: self.parse_future = None self._logger.info( NO_COMPILE_FLAGS_MESSAGE ) @@ -319,13 +317,20 @@ class ClangCompleter( Completer ): filename = request_data[ 'filepath' ] if not filename: return '' - flags = self.flags.FlagsForFile( filename ) or [] + flags = self._FlagsForRequest( request_data ) or [] source = extra_conf_store.ModuleFileForSourceFile( filename ) return responses.BuildDisplayMessageResponse( 'Flags for {0} loaded from {1}:\n{2}'.format( filename, source, list( flags ) ) ) + def _FlagsForRequest( self, request_data ): + filename = request_data[ 'filepath' ] + if 'compilation_flags' in request_data: + return PrepareFlagsForClang( request_data[ 'compilation_flags' ], + filename ) + return self.flags.FlagsForFile( filename ) + # TODO: Make this work again # def DiagnosticToDict( diagnostic ): # # see :h getqflist for a description of the dictionary fields diff --git a/python/ycm/completers/cpp/flags.py b/python/ycm/completers/cpp/flags.py index 17c4981a..a896986f 100644 --- a/python/ycm/completers/cpp/flags.py +++ b/python/ycm/completers/cpp/flags.py @@ -20,6 +20,7 @@ import ycm_core import os from ycm import extra_conf_store +from ycm.utils import ToUtf8IfNeeded NO_EXTRA_CONF_FILENAME_MESSAGE = ( 'No {0} file detected, so no compile flags ' 'are available. Thus no semantic support for C/C++/ObjC/ObjC++. Go READ THE ' @@ -54,7 +55,7 @@ class Flags( object ): flags = list( results[ 'flags' ] ) if add_special_clang_flags: flags += self.special_clang_flags - sanitized_flags = _PrepareFlagsForClang( flags, filename ) + sanitized_flags = PrepareFlagsForClang( flags, filename ) if results[ 'do_cache' ]: self.flags_for_file[ filename ] = sanitized_flags @@ -90,7 +91,7 @@ class Flags( object ): self.flags_for_file.clear() -def _PrepareFlagsForClang( flags, filename ): +def PrepareFlagsForClang( flags, filename ): flags = _RemoveUnusedFlags( flags, filename ) flags = _SanitizeFlags( flags ) return flags @@ -116,7 +117,7 @@ def _SanitizeFlags( flags ): vector = ycm_core.StringVec() for flag in sanitized_flags: - vector.append( flag ) + vector.append( ToUtf8IfNeeded( flag ) ) return vector diff --git a/python/ycm/server/tests/basic_test.py b/python/ycm/server/tests/basic_test.py index 3f2b6214..632e9d40 100644 --- a/python/ycm/server/tests/basic_test.py +++ b/python/ycm/server/tests/basic_test.py @@ -137,7 +137,6 @@ foo() 'column_num': 0, 'filetypes': ['python'], 'filepath': '/foo.py', - 'line_value': contents, 'file_data': { '/foo.py': { 'contents': contents, @@ -155,6 +154,49 @@ foo() app.post_json( '/run_completer_command', goto_data ).json ) +@with_setup( Setup ) +def RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test(): + app = TestApp( ycmd.app ) + contents = """ +struct Foo { + int x; + int y; + char c; +}; + +int main() +{ + Foo foo; + return 0; +} +""" + + filename = '/foo.cpp' + goto_data = { + 'compilation_flags': ['-x', 'c++'], + 'completer_target': 'filetype_default', + 'command_arguments': ['GoToDefinition'], + 'line_num': 9, + 'column_num': 2, + 'filetypes': ['cpp'], + 'filepath': filename, + 'file_data': { + filename: { + 'contents': contents, + 'filetypes': ['cpp'] + } + } + } + + # 0-based line and column! + eq_( { + 'filepath': '/foo.cpp', + 'line_num': 1, + 'column_num': 7 + }, + app.post_json( '/run_completer_command', goto_data ).json ) + + @with_setup( Setup ) def FiletypeCompletionAvailable_Works_test(): app = TestApp( ycmd.app )