From 443b99f69d4932b8feab43f6841a1480d3e7edc7 Mon Sep 17 00:00:00 2001 From: solawing <316786359@qq.com> Date: Sun, 29 Mar 2015 14:23:18 +0800 Subject: [PATCH] fixed complete in objective-c. when completing multi-param in objective-c files, the origin implementation only completed the last param. this commit fixed it. it will complete the first param, then after the user input param, call completion again to get second param, and so on. it also support completing declared methods or inherited methods. the user can call the completion after input '+ ' or '- ' --- cpp/ycm/ClangCompleter/CompletionData.cpp | 49 ++++++++++++++++--- cpp/ycm/ClangCompleter/CompletionData.h | 3 +- .../ClangCompleter/ClangCompleter_test.cpp | 29 +++++++++++ cpp/ycm/tests/testdata/SWObject.h | 7 +++ cpp/ycm/tests/testdata/SWObject.m | 11 +++++ 5 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 cpp/ycm/tests/testdata/SWObject.h create mode 100644 cpp/ycm/tests/testdata/SWObject.m diff --git a/cpp/ycm/ClangCompleter/CompletionData.cpp b/cpp/ycm/ClangCompleter/CompletionData.cpp index 0b4b4d8e08..00f46bfa19 100644 --- a/cpp/ycm/ClangCompleter/CompletionData.cpp +++ b/cpp/ycm/ClangCompleter/CompletionData.cpp @@ -32,6 +32,8 @@ CompletionKind CursorKindToCompletionKind( CXCursorKind kind ) { case CXCursor_ClassDecl: case CXCursor_ClassTemplate: + case CXCursor_ObjCInterfaceDecl: + case CXCursor_ObjCImplementationDecl: return CLASS; case CXCursor_EnumDecl: @@ -43,6 +45,9 @@ CompletionKind CursorKindToCompletionKind( CXCursorKind kind ) { return TYPE; case CXCursor_FieldDecl: + case CXCursor_ObjCIvarDecl: + case CXCursor_ObjCPropertyDecl: + case CXCursor_EnumConstantDecl: return MEMBER; case CXCursor_FunctionDecl: @@ -51,6 +56,8 @@ CompletionKind CursorKindToCompletionKind( CXCursorKind kind ) { case CXCursor_ConversionFunction: case CXCursor_Constructor: case CXCursor_Destructor: + case CXCursor_ObjCClassMethodDecl: + case CXCursor_ObjCInstanceMethodDecl: return FUNCTION; case CXCursor_VarDecl: @@ -90,7 +97,8 @@ bool IsMainCompletionTextInfo( CXCompletionChunkKind kind ) { kind == CXCompletionChunk_SemiColon || kind == CXCompletionChunk_Equal || kind == CXCompletionChunk_Informative || - kind == CXCompletionChunk_HorizontalSpace; + kind == CXCompletionChunk_HorizontalSpace || + kind == CXCompletionChunk_Text; } @@ -161,12 +169,18 @@ CompletionData::CompletionData( const CXCompletionResult &completion_result ) { uint num_chunks = clang_getNumCompletionChunks( completion_string ); bool saw_left_paren = false; bool saw_function_params = false; + bool saw_placeholder = false; for ( uint j = 0; j < num_chunks; ++j ) { ExtractDataFromChunk( completion_string, j, saw_left_paren, - saw_function_params ); + saw_function_params, + saw_placeholder ); + } + if ( original_string_.size() > 0 && + original_string_[ original_string_.size() - 1 ] == '(' ) { + original_string_.erase( original_string_.size() - 1, 1 ); } kind_ = CursorKindToCompletionKind( completion_result.CursorKind ); @@ -194,7 +208,8 @@ CompletionData::CompletionData( const CXCompletionResult &completion_result ) { void CompletionData::ExtractDataFromChunk( CXCompletionString completion_string, uint chunk_num, bool &saw_left_paren, - bool &saw_function_params ) { + bool &saw_function_params, + bool &saw_placeholder ) { CXCompletionChunkKind kind = clang_getCompletionChunkKind( completion_string, chunk_num ); @@ -212,6 +227,8 @@ void CompletionData::ExtractDataFromChunk( CXCompletionString completion_string, } else if ( saw_function_params && kind == CXCompletionChunk_RightParen ) { + saw_left_paren = false; + saw_function_params = false; // fix objc have more than one () everything_except_return_type_.append( " " ); } @@ -226,11 +243,27 @@ void CompletionData::ExtractDataFromChunk( CXCompletionString completion_string, } } - if ( kind == CXCompletionChunk_ResultType ) - return_type_ = ChunkToString( completion_string, chunk_num ); - - if ( kind == CXCompletionChunk_TypedText ) - original_string_ = ChunkToString( completion_string, chunk_num ); + switch ( kind ) { + case CXCompletionChunk_ResultType: + return_type_ = ChunkToString( completion_string, chunk_num ); + break; + case CXCompletionChunk_Placeholder: + saw_placeholder = true; + break; + case CXCompletionChunk_TypedText: + case CXCompletionChunk_Text: + // need to add paren to insert string + // when implementing inherited methods or declared methods in objc. + case CXCompletionChunk_LeftParen: + case CXCompletionChunk_RightParen: + case CXCompletionChunk_HorizontalSpace: + if ( !saw_placeholder ) { + original_string_ += ChunkToString( completion_string, chunk_num ); + } + break; + default: + break; + } } } // namespace YouCompleteMe diff --git a/cpp/ycm/ClangCompleter/CompletionData.h b/cpp/ycm/ClangCompleter/CompletionData.h index dbbb268a35..c4b67c7307 100644 --- a/cpp/ycm/ClangCompleter/CompletionData.h +++ b/cpp/ycm/ClangCompleter/CompletionData.h @@ -118,7 +118,8 @@ struct CompletionData { void ExtractDataFromChunk( CXCompletionString completion_string, uint chunk_num, bool &saw_left_paren, - bool &saw_function_params ); + bool &saw_function_params, + bool &saw_placeholder); }; } // namespace YouCompleteMe diff --git a/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp b/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp index a822a0e8f2..478da2124d 100644 --- a/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp +++ b/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp @@ -41,6 +41,35 @@ TEST( ClangCompleterTest, CandidatesForLocationInFile ) { EXPECT_TRUE( !completions.empty() ); } + +TEST( ClangCompleterTest, CandidatesObjCForLocationInFile ) { + ClangCompleter completer; + std::vector< CompletionData > completions = + completer.CandidatesForLocationInFile( + PathToTestFile( "SWObject.m" ).string(), + 6, + 16, + std::vector< UnsavedFile >(), + std::vector< std::string >{"-x", "objective-c"} ); + + EXPECT_TRUE( !completions.empty() && completions[0].TextToInsertInBuffer() == "withArg2:"); +} + +TEST( ClangCompleterTest, CandidatesObjCFuncForLocationInFile ) { + ClangCompleter completer; + std::vector< CompletionData > completions = + completer.CandidatesForLocationInFile( + PathToTestFile( "SWObject.m" ).string(), + 9, + 3, + std::vector< UnsavedFile >(), + std::vector< std::string >{"-x", "objective-c"} ); + + EXPECT_TRUE( !completions.empty() && + completions[0].TextToInsertInBuffer() + == "(void)test:(int)arg1 withArg2:(int)arg2 withArg3:(int)arg3"); +} + TEST( ClangCompleterTest, GetDefinitionLocation ) { diff --git a/cpp/ycm/tests/testdata/SWObject.h b/cpp/ycm/tests/testdata/SWObject.h new file mode 100644 index 0000000000..c3c1262fb0 --- /dev/null +++ b/cpp/ycm/tests/testdata/SWObject.h @@ -0,0 +1,7 @@ +@interface SWObject +/** testFunc + * + * a detail description + */ +- (void)test:(int)arg1 withArg2:(int)arg2 withArg3:(int)arg3; +@end diff --git a/cpp/ycm/tests/testdata/SWObject.m b/cpp/ycm/tests/testdata/SWObject.m new file mode 100644 index 0000000000..a61559b491 --- /dev/null +++ b/cpp/ycm/tests/testdata/SWObject.m @@ -0,0 +1,11 @@ +#import "SWObject.h" + +@implementation SWObject + +- (void)test { + [self test:0 /*complete at here*/] +} + +- /*complete at here*/ + +@end