From 7cf86a8ea4b351b65a18d623a7bc8ec03f41fcad Mon Sep 17 00:00:00 2001 From: Vladimir Galajda Date: Thu, 22 Aug 2013 14:36:50 +0200 Subject: [PATCH 1/4] update regex for function name and args, remove needless split(), join() Fixes: #15 --- autoload/phpcomplete.vim | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/autoload/phpcomplete.vim b/autoload/phpcomplete.vim index cd226193..06ffa9e2 100644 --- a/autoload/phpcomplete.vim +++ b/autoload/phpcomplete.vim @@ -747,14 +747,13 @@ function! phpcomplete#CompleteUserClass(scontext, base, sccontent, classAccess) \ 'v:val =~ "^\\s*\\(' . a:classAccess . '\\s\\+\\)*function"') endif - let sfuncs = split(join(functions, ' '), 'function\s\+') let c_functions = {} let c_doc = {} - for i in sfuncs + for i in functions let f_name = matchstr(i, - \ '^&\?\zs[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\ze') + \ '^&\?\s*\(\(static\|public\|protected\|private\)\s*\)*function\s*\zs[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\ze') let f_args = matchstr(i, - \ '^&\?[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\s*(\zs.\{-}\ze)\_s*\({\|$\)') + \ '^&\?\s*\(\(static\|public\|protected\|private\)\s*\)*function\s*[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\s*(\zs.\{-}\ze)\_s*\({\|\_$\)') if f_name != '' let c_functions[f_name.'('] = f_args if g:phpcomplete_parse_docblock_comments From 80c9a5ab40b73028d6745f106f55ccf833d2eaeb Mon Sep 17 00:00:00 2001 From: Vladimir Galajda Date: Thu, 22 Aug 2013 18:08:12 +0200 Subject: [PATCH 2/4] improve regex start matching with 'function' fix not accepting & before function name --- autoload/phpcomplete.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoload/phpcomplete.vim b/autoload/phpcomplete.vim index 06ffa9e2..7e4e18cb 100644 --- a/autoload/phpcomplete.vim +++ b/autoload/phpcomplete.vim @@ -751,9 +751,9 @@ function! phpcomplete#CompleteUserClass(scontext, base, sccontent, classAccess) let c_doc = {} for i in functions let f_name = matchstr(i, - \ '^&\?\s*\(\(static\|public\|protected\|private\)\s*\)*function\s*\zs[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\ze') + \ 'function\s*&\?\zs[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\ze') let f_args = matchstr(i, - \ '^&\?\s*\(\(static\|public\|protected\|private\)\s*\)*function\s*[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\s*(\zs.\{-}\ze)\_s*\({\|\_$\)') + \ 'function\s*&\?[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*\s*(\zs.\{-}\ze)\_s*\({\|\_$\)') if f_name != '' let c_functions[f_name.'('] = f_args if g:phpcomplete_parse_docblock_comments From 3f9d1a71bb253963c225258a3e8af80c18e1a904 Mon Sep 17 00:00:00 2001 From: Vladimir Galajda Date: Fri, 23 Aug 2013 20:46:38 +0200 Subject: [PATCH 3/4] update filter regex to accept final and abstract keywords --- autoload/phpcomplete.vim | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/autoload/phpcomplete.vim b/autoload/phpcomplete.vim index 7e4e18cb..f416659d 100644 --- a/autoload/phpcomplete.vim +++ b/autoload/phpcomplete.vim @@ -732,21 +732,20 @@ function! phpcomplete#CompleteUserClass(scontext, base, sccontent, classAccess) let res = [] " limit based on context to static or normal methods + let static_con = '' if a:scontext =~ '::' if g:phpcomplete_relax_static_constraint == 1 - let functions = filter(deepcopy(a:sccontent), - \ 'v:val =~ "^\\s*\\(static\\s\\+\\(' . a:classAccess . '\\)*\\|\\(' . a:classAccess . '\\s\\+\\)*static\\)\\s\\+function"') - let functions += filter(deepcopy(a:sccontent), - \ 'v:val =~ "^\\s*\\(' . a:classAccess . '\\s\\+\\)*function"') - else - let functions = filter(deepcopy(a:sccontent), - \ 'v:val =~ "^\\s*\\(static\\s\\+\\(' . a:classAccess . '\\)*\\|\\(' . a:classAccess . '\\s\\+\\)*static\\)\\s\\+function"') + let static_con = '' + else + let static_con = '\\(.*\\\\)\\@=' endif elseif a:scontext =~ '->' - let functions = filter(deepcopy(a:sccontent), - \ 'v:val =~ "^\\s*\\(' . a:classAccess . '\\s\\+\\)*function"') + let static_con = '\\(.*\\\\)\\@!' endif + let functions = filter(deepcopy(a:sccontent), + \ 'v:val =~ "^\\s*\\(.*\\<' . a:classAccess . '\\>\\)\\@=' . static_con . '\\(public\\|protected\\|private\\|static\\|final\\|abstract\\|\\s\\)\\+function"') + let c_functions = {} let c_doc = {} for i in functions From 296bc78ad92a575af67ac0c4405a66ddcf8840cd Mon Sep 17 00:00:00 2001 From: Vladimir Galajda Date: Fri, 23 Aug 2013 20:47:39 +0200 Subject: [PATCH 4/4] extend completeUserClass test cases --- tests/CompleteUserClass2_test.vim | 125 ++++++++++++++++++ .../CompleteUserClass/user_extended.class.php | 70 ++++++++++ 2 files changed, 195 insertions(+) create mode 100644 tests/CompleteUserClass2_test.vim create mode 100644 tests/fixtures/CompleteUserClass/user_extended.class.php diff --git a/tests/CompleteUserClass2_test.vim b/tests/CompleteUserClass2_test.vim new file mode 100644 index 00000000..620ebd7e --- /dev/null +++ b/tests/CompleteUserClass2_test.vim @@ -0,0 +1,125 @@ +fun! SetUp() + let g:fixture_class_content = readfile(expand('%:p:h').'/'.'fixtures/CompleteUserClass/user_extended.class.php')[2:] + let g:commented_fixture_class_content = readfile(expand('%:p:h').'/'.'fixtures/CompleteUserClass/commented_foo.class.php')[2:] + let g:phpcomplete_relax_static_constraint = 0 + let g:phpcomplete_parse_docblock_comments = 0 +endf + +fun! TestCase_returns_everyting_instance_related_when_scope_is_in_class() + call SetUp() + + let ret = phpcomplete#CompleteUserClass('$u->', '', g:fixture_class_content, '\\(public\\|private\\|protected\\)') + call VUAssertEquals([ + \{'word': 'A_CONST', 'info': 'A_CONST', 'menu': '', 'kind': 'd'}, + \{'word': '__construct(', 'info': '__construct()', 'menu': ')', 'kind': 'f'}, + \{'word': 'final_private_method(', 'info': 'final_private_method($foo = null)', 'menu': '$foo = null)', 'kind': 'f'}, + \{'word': 'private_method(', 'info': 'private_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \{'word': 'private_property', 'info': '', 'menu': '', 'kind': 'v'}, + \{'word': 'protected_method(', 'info': 'protected_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \{'word': 'protected_property', 'info': '', 'menu': '', 'kind': 'v'}, + \{'word': 'public_final_method(', 'info': 'public_final_method($foo, $anotherfoo = '''')', 'menu': '$foo, $anotherfoo = '''')', 'kind': 'f'}, + \{'word': 'public_method(', 'info': 'public_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \{'word': 'public_method_with_amp(', 'info': 'public_method_with_amp($foo)', 'menu': '$foo)', 'kind': 'f'}, + \{'word': 'public_property1', 'info': '', 'menu': '', 'kind': 'v'}, + \{'word': 'public_property2', 'info': '', 'menu': '', 'kind': 'v'}], + \ ret) +endfun + +fun! TestCase_returns_everyting_instance_related_when_scope_is_out_of_class() + call SetUp() + + let ret = phpcomplete#CompleteUserClass('$u->', '', g:fixture_class_content, 'public') + call VUAssertEquals([ + \{'word': 'A_CONST', 'info': 'A_CONST', 'menu': '', 'kind': 'd'}, + \{'word': '__construct(', 'info': '__construct()', 'menu': ')', 'kind': 'f'}, + \{'word': 'public_final_method(', 'info': 'public_final_method($foo, $anotherfoo = '''')', 'menu': '$foo, $anotherfoo = '''')', 'kind': 'f'}, + \{'word': 'public_method(', 'info': 'public_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \{'word': 'public_method_with_amp(', 'info': 'public_method_with_amp($foo)', 'menu': '$foo)', 'kind': 'f'}, + \{'word': 'public_property1', 'info': '', 'menu': '', 'kind': 'v'}, + \{'word': 'public_property2', 'info': '', 'menu': '', 'kind': 'v'}], + \ ret) +endfun + +fun! TestCase_returns_everyting_static_when_scope_is_in_class() + call SetUp() + + let ret = phpcomplete#CompleteUserClass('UserClass::', '', g:fixture_class_content, '\\(public\\|private\\|protected\\)') + call VUAssertEquals([ + \ {'word': '$private_static_property', 'info': '', 'menu': '', 'kind': 'v'}, + \ {'word': '$protected_static_property', 'info': '', 'menu': '', 'kind': 'v'}, + \ {'word': '$public_static_property', 'info': '', 'menu': '', 'kind': 'v'}, + \ {'word': 'A_CONST', 'info': 'A_CONST', 'menu': '', 'kind': 'd'}, + \ {'word': 'final_static_public_method(', 'info': 'final_static_public_method()', 'menu': ')', 'kind': 'f'}, + \ {'word': 'private_static_method(', 'info': 'private_static_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'protected_static_method(', 'info': 'protected_static_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'public_final_static_method(', 'info': 'public_final_static_method( $foo, $anotherfoo = array() )', 'menu': ' $foo, $anotherfoo = array() )', 'kind': 'f'}, + \ {'word': 'public_static_method(', 'info': 'public_static_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'static_final_protected_method(', 'info': 'static_final_protected_method()', 'menu': ')', 'kind': 'f'}, + \ {'word': 'static_public_method(', 'info': 'static_public_method($foo)', 'menu': '$foo)', 'kind': 'f'}], + \ ret) +endfun + +fun! TestCase_filters_for_instane_level_prefix() + call SetUp() + + let ret = phpcomplete#CompleteUserClass('$u->', 'public_', g:fixture_class_content, '\\(public\\|private\\|protected\\)') + call VUAssertEquals([ + \ {'word': 'public_final_method(', 'info': 'public_final_method($foo, $anotherfoo = '''')', 'menu': '$foo, $anotherfoo = '''')', 'kind': 'f'}, + \ {'word': 'public_method(', 'info': 'public_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'public_method_with_amp(', 'info': 'public_method_with_amp($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'public_property1', 'info': '', 'menu': '', 'kind': 'v'}, + \ {'word': 'public_property2', 'info': '', 'menu': '', 'kind': 'v'}], + \ ret) +endfun + +fun! TestCase_filters_for_static_property_names() + call SetUp() + + let ret = phpcomplete#CompleteUserClass('UserClass::', '$private_', g:fixture_class_content, '\\(public\\|private\\|protected\\)') + call VUAssertEquals([ + \ {'word': '$private_static_property', 'info': '', 'menu': '', 'kind': 'v'}], + \ ret) +endfun + +fun! TestCase_returns_everyting_static_when_scope_is_out_of_class() + call SetUp() + + let ret = phpcomplete#CompleteUserClass('UserClass::', '', g:fixture_class_content, 'public') + call VUAssertEquals([ + \ {'word': '$public_static_property', 'info': '', 'menu': '', 'kind': 'v'}, + \ {'word': 'A_CONST', 'info': 'A_CONST', 'menu': '', 'kind': 'd'}, + \ {'word': 'final_static_public_method(', 'info': 'final_static_public_method()', 'menu': ')', 'kind': 'f'}, + \ {'word': 'public_final_static_method(', 'info': 'public_final_static_method( $foo, $anotherfoo = array() )', 'menu': ' $foo, $anotherfoo = array() )', 'kind': 'f'}, + \ {'word': 'public_static_method(', 'info': 'public_static_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'static_public_method(', 'info': 'static_public_method($foo)', 'menu': '$foo)', 'kind': 'f'}], + \ ret) +endfun + +fun! TestCase_returns_non_explicit_static_methods_when_phpcomplete_relax_static_constraint_enabled() + call SetUp() + let g:phpcomplete_relax_static_constraint = 1 + let ret = phpcomplete#CompleteUserClass('UserClass::', '', g:fixture_class_content, 'public') + call VUAssertEquals([ + \ {'word': '$public_static_property', 'info': '', 'menu': '', 'kind': 'v'}, + \ {'word': 'A_CONST', 'info': 'A_CONST', 'menu': '', 'kind': 'd'}, + \ {'word': '__construct(', 'info': '__construct()', 'menu': ')', 'kind': 'f'}, + \ {'word': 'final_static_public_method(', 'info': 'final_static_public_method()', 'menu': ')', 'kind': 'f'}, + \ {'word': 'public_final_method(', 'info': 'public_final_method($foo, $anotherfoo = '''')', 'menu': '$foo, $anotherfoo = '''')', 'kind': 'f'}, + \ {'word': 'public_final_static_method(', 'info': 'public_final_static_method( $foo, $anotherfoo = array() )', 'menu': ' $foo, $anotherfoo = array() )', 'kind': 'f'}, + \ {'word': 'public_method(', 'info': 'public_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'public_method_with_amp(', 'info': 'public_method_with_amp($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'public_static_method(', 'info': 'public_static_method($foo)', 'menu': '$foo)', 'kind': 'f'}, + \ {'word': 'static_public_method(', 'info': 'static_public_method($foo)', 'menu': '$foo)', 'kind': 'f'}], + \ ret) +endfun + +fun! TestCase_returns_types_for_properties_and_return_types_from_docblock_comments() + call SetUp() + let g:phpcomplete_parse_docblock_comments = 1 + + let ret = phpcomplete#CompleteUserClass('$u->', 'commented', g:commented_fixture_class_content, 'public') + call VUAssertEquals([ + \ {'word': 'commented_method(', 'info': "commented_method($foo, $bar, $baz = '')\n\nReturn:\n\tstring: description of return\n", 'menu': "$foo, $bar, $baz = '') | string", 'kind': 'f'}, + \ {'word': 'commented_property', 'info': "Type:\n\tFoo\n", 'menu': 'Foo', 'kind': 'v'}], + \ ret) +endfun diff --git a/tests/fixtures/CompleteUserClass/user_extended.class.php b/tests/fixtures/CompleteUserClass/user_extended.class.php new file mode 100644 index 00000000..87146649 --- /dev/null +++ b/tests/fixtures/CompleteUserClass/user_extended.class.php @@ -0,0 +1,70 @@ +