ycmd-0+20161219+git486b809.orig/0000700000175000017500000000000013026170316014150 5ustar onuronurycmd-0+20161219+git486b809.orig/run_tests.py0000755000175000017500000001667113026170313016575 0ustar onuronur#!/usr/bin/env python from __future__ import print_function from __future__ import division from __future__ import unicode_literals from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import platform import os import subprocess import os.path as p import sys DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) ) DIR_OF_THIRD_PARTY = p.join( DIR_OF_THIS_SCRIPT, 'third_party' ) python_path = [] for folder in os.listdir( DIR_OF_THIRD_PARTY ): # We skip python-future because it needs to be inserted in sys.path AFTER # the standard library imports but we can't do that with PYTHONPATH because # the std lib paths are always appended to PYTHONPATH. We do it correctly in # prod in ycmd/utils.py because we have access to the right sys.path. # So for dev, we rely on python-future being installed correctly with # pip install -r test_requirements.txt # # Pip knows how to install this correctly so that it doesn't matter where in # sys.path the path is. if folder == 'python-future': continue python_path.append( p.abspath( p.join( DIR_OF_THIRD_PARTY, folder ) ) ) if os.environ.get( 'PYTHONPATH' ) is not None: python_path.append( os.environ['PYTHONPATH'] ) os.environ[ 'PYTHONPATH' ] = os.pathsep.join( python_path ) sys.path.insert( 1, p.abspath( p.join( DIR_OF_THIRD_PARTY, 'argparse' ) ) ) import argparse def RunFlake8(): print( 'Running flake8' ) subprocess.check_call( [ 'flake8', p.join( DIR_OF_THIS_SCRIPT, 'ycmd' ) ] ) COMPLETERS = { 'cfamily': { 'build': [ '--clang-completer' ], 'test': [ '--exclude-dir=ycmd/tests/clang' ], 'aliases': [ 'c', 'cpp', 'c++', 'objc', 'clang', ] }, 'cs': { 'build': [ '--omnisharp-completer' ], 'test': [ '--exclude-dir=ycmd/tests/cs' ], 'aliases': [ 'omnisharp', 'csharp', 'c#' ] }, 'javascript': { 'build': [ '--tern-completer' ], 'test': [ '--exclude-dir=ycmd/tests/javascript' ], 'aliases': [ 'js', 'tern' ] }, 'go': { 'build': [ '--gocode-completer' ], 'test': [ '--exclude-dir=ycmd/tests/go' ], 'aliases': [ 'gocode' ] }, 'rust': { 'build': [ '--racer-completer' ], 'test': [ '--exclude-dir=ycmd/tests/rust' ], 'aliases': [ 'racer', 'racerd', ] }, 'typescript': { 'build': [], 'test': [ '--exclude-dir=ycmd/tests/typescript' ], 'aliases': [] }, 'python': { 'build': [], 'test': [ '--exclude-dir=ycmd/tests/python' ], 'aliases': [ 'jedi', 'jedihttp', ] }, } def CompleterType( value ): value = value.lower() if value in COMPLETERS: return value else: aliases_to_completer = dict( ( i, k ) for k, v in COMPLETERS.items() for i in v[ 'aliases' ] ) if value in aliases_to_completer: return aliases_to_completer[ value ] else: raise argparse.ArgumentTypeError( '{0} is not a valid completer - should be one of {1}'.format( value, COMPLETERS.keys() ) ) def ParseArguments(): parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument( '--no-clang-completer', action = 'store_true', help = argparse.SUPPRESS ) # deprecated group.add_argument( '--no-completers', nargs ='*', type = CompleterType, help = 'Do not build or test with listed semantic ' 'completion engine(s). Valid values: {0}'.format( COMPLETERS.keys()) ) group.add_argument( '--completers', nargs ='*', type = CompleterType, help = 'Only build and test with listed semantic ' 'completion engine(s). Valid values: {0}'.format( COMPLETERS.keys()) ) parser.add_argument( '--skip-build', action = 'store_true', help = 'Do not build ycmd before testing.' ) parser.add_argument( '--msvc', type = int, choices = [ 11, 12, 14 ], help = 'Choose the Microsoft Visual ' 'Studio version. (default: 14).' ) parser.add_argument( '--coverage', action = 'store_true', help = 'Enable coverage report (requires coverage pkg)' ) parser.add_argument( '--no-flake8', action = 'store_true', help = 'Disable flake8 run.' ) parser.add_argument( '--dump-path', action = 'store_true', help = 'Dump the PYTHONPATH required to run tests ' 'manually, then exit.' ) parsed_args, nosetests_args = parser.parse_known_args() parsed_args.completers = FixupCompleters( parsed_args ) if 'COVERAGE' in os.environ: parsed_args.coverage = ( os.environ[ 'COVERAGE' ] == 'true' ) return parsed_args, nosetests_args def FixupCompleters( parsed_args ): completers = set( COMPLETERS.keys() ) if parsed_args.completers is not None: completers = set( parsed_args.completers ) elif parsed_args.no_completers is not None: completers = completers.difference( parsed_args.no_completers ) elif parsed_args.no_clang_completer: print( 'WARNING: The "--no-clang-completer" flag is deprecated. ' 'Please use "--no-completer cfamily" instead.' ) completers.remove( 'cfamily' ) if 'USE_CLANG_COMPLETER' in os.environ: if os.environ[ 'USE_CLANG_COMPLETER' ] == 'false': completers.remove( 'cfamily' ) else: completers.add( 'cfamily' ) return list( completers ) def BuildYcmdLibs( args ): if not args.skip_build: if 'EXTRA_CMAKE_ARGS' in os.environ: os.environ[ 'EXTRA_CMAKE_ARGS' ] += ' -DUSE_DEV_FLAGS=ON' else: os.environ[ 'EXTRA_CMAKE_ARGS' ] = '-DUSE_DEV_FLAGS=ON' os.environ[ 'YCM_TESTRUN' ] = '1' build_cmd = [ sys.executable, p.join( DIR_OF_THIS_SCRIPT, 'build.py' ), ] for key in COMPLETERS: if key in args.completers: build_cmd.extend( COMPLETERS[ key ][ 'build' ] ) if args.msvc: build_cmd.extend( [ '--msvc', str( args.msvc ) ] ) if args.coverage: # In order to generate coverage data for C++, we use gcov. This requires # some files generated when building (*.gcno), so we store the build # output in a known directory, which is then used by the CI infrastructure # to generate the c++ coverage information. build_cmd.extend( [ '--enable-coverage', '--build-dir', '.build' ] ) subprocess.check_call( build_cmd ) def NoseTests( parsed_args, extra_nosetests_args ): # Always passing --with-id to nosetests enables non-surprising usage of # its --failed flag. nosetests_args = [ '-v', '--with-id' ] for key in COMPLETERS: if key not in parsed_args.completers: nosetests_args.extend( COMPLETERS[ key ][ 'test' ] ) if parsed_args.coverage: nosetests_args += [ '--with-coverage', '--cover-erase', '--cover-package=ycmd', '--cover-html' ] if extra_nosetests_args: nosetests_args.extend( extra_nosetests_args ) else: nosetests_args.append( p.join( DIR_OF_THIS_SCRIPT, 'ycmd' ) ) subprocess.check_call( [ 'nosetests' ] + nosetests_args ) def Main(): parsed_args, nosetests_args = ParseArguments() if parsed_args.dump_path: print( os.environ[ 'PYTHONPATH' ] ) sys.exit() print( 'Running tests on Python', platform.python_version() ) if not parsed_args.no_flake8: RunFlake8() BuildYcmdLibs( parsed_args ) NoseTests( parsed_args, nosetests_args ) if __name__ == "__main__": Main() ycmd-0+20161219+git486b809.orig/DEV_SETUP.md0000644000175000017500000001151213026170313016077 0ustar onuronur# Setting up for ycmd development We use Vagrant for development. The VM will have **all** dependencies already set up correctly so you won't have to do anything. (If you find something missing, please file a bug.) NOTE: The virtual machine that is created requires 3GB of RAM, so you likely need at least 8GB of RAM to use this environment. 1. Install [Vagrant][]. 2. `cd` into the folder where you checked out ycmd. 3. `$ vagrant up && vagrant ssh`. This will take a while because the VM is being built and set up. Only needs to happen once though. 4. You are now in the VM. Run the tests with `$ ./run_tests.py`. 5. Hack away. When done, exit the ssh connection with `exit`. 6. `$ vagrant suspend` so that you can quickly get back to hacking later. 7. Later on: `$ vagrant resume && vagrant ssh`. This will be _much_ faster. That's it! You can switch between Python versions with `pyenv global 2.6.6` and `pyenv global 3.3.0`. If you ever feel like you've screwed up the VM, just kill it with `vagrant destroy` and then run `vagrant up` again to get to a clean state. # Debugging the Python layer There are a number of Python debuggers. Presented here are just a couple of options known to work for certain developers on the ycmd project. The options presented are: - Using [`ipdb`][ipdb] (this is known not to work well on OS X). - Using [pyclewn][] and attaching to the running Python process. ## Using `ipdb` 1. If you're not using vagrant, install `ipdb` (`pip install ipdb`). 2. At the point in the code you want to break, add the following lines: ```python import ipdb; ipdb.set_trace() ``` 3. Run the tests without `flake8`, e.g. ```sh ./run_tests.py --skip-build --no-flake8 ycmd/tests/get_completions_test.py ``` 4. The test breaks at your code breakpoint and offers a command interface to debug. See the `ipdb` docs for more info. ## Using `pyclewn` in Vim The procedure is similar to using `ipdb` but you attach to the suspended process and use Vim as a graphical debugger: 1. Install [pyclewna][pyclewn-install] 2. At the point you want to break, add the following lines: ```python import clewn.vim as clewn; clewn.pdb() ``` 3. Run the tests without `flake8`, e.g. ```sh ./run_tests.py --skip-build --no-flake8 ycmd/tests/get_completions_test.py ``` 4. The tests will pause at the breakpoint. Now within Vim attach the debugger with `:Pyclewn pdb`. Hope that it works. It can be a bit flaky. See the pyclewn docs for more info. # Debugging the C++ layer (C++ Python library) If you want to debug the c++ code using gdb (or your favourite graphical debugger, e.g. [pyclewn][] in Vim), there are a few things you need to do: 1. Ensure your Python is built with debug enabled. In the vagrant system that's as simple as: ```sh vagrant up vagrant ssh export OPT='-g' # Ensure Python binary has debugging info export PYTHON_CONFIGURE_OPTS='--enable-shared --with-pydebug' pyenv install 2.7.11 # or whatever version ``` On OS X, you need a working debugger. You can either use `lldb` which comes with XCode or `brew install gdb`. Note: If you use `gdb` from homebrew, then you need to sign the binary otherwise you can't debug anything. See later steps for a link. 2. Build ycm_core library with debugging information (and link against debug Python): ```sh pyenv shell 2.7.11 ./build.py --all --enable-debug ``` 3. Enable debugging in the OS. On Linux (Ubuntu at least, which is what all of our tests are run on), you must set the following sysctl parameter (you can make it permanent if you like by adding it to `/etc/sysctl.conf` or via any other appropriate mechanism): ```sh sudo sysctl kernel.yama.ptrace_scope=0 ``` On OS X it is more fiddly: - The binary must be signed. See https://sourceware.org/gdb/wiki/BuildingOnDarwin - You *can not* debug system Python. Again: you *must* use a Python that is *not* the one provided by Apple. Use pyenv. That is the rule. Don't argue. Don't ask why. It's for security. 3. Here you have choices: either use a Python debugger to break the tests, or manually use Vim to simulate the scenario you want to debug. In any case, you will need the PID of the running Python process hosting ycmd to attach to. Getting this is left as an exercise, but one approach is to simply install vim with `apt-get install vim` and to get a copy of YouCompleteMe into `$HOME/.vim/bundle` and symlink `/vargant` as `$HOME/.vim/bundle/third_party/ycmd`. Anyway, once you have the PID you can simply attach to the Python process, for example: - `:YcmDebugInfo` to get the pid - `gdb: attach ` - `break YouCompleteMe::FilterAndSortCandidates` [vagrant]: https://www.vagrantup.com/ [pyclewn]: http://pyclewn.sourceforge.net [pyclewn-install]: http://pyclewn.sourceforge.net/install.html [ipdb]: https://pypi.python.org/pypi/ipdb ycmd-0+20161219+git486b809.orig/tox.ini0000644000175000017500000000027413026170313015475 0ustar onuronur[flake8] ignore = E111,E114,E121,E125,E126,E127,E128,E129,E131,E133,E201,E202,E203,E211,E221,E222,E241,E251,E261,E303,E402,W503 max-complexity = 10 max-line-length = 80 exclude = testdata ycmd-0+20161219+git486b809.orig/Vagrantfile0000644000175000017500000000156013026170313016346 0ustar onuronur# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure(2) do |config| # TODO: update to xenial64 when that comes out config.vm.box = "ubuntu/trusty64" # On startup, run our bootstrap script to setup the VM config.vm.provision :shell, :path => "vagrant_bootstrap.sh" config.vm.provider "virtualbox" do |v| # MAGIC for faster guest networking v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] v.customize ["modifyvm", :id, "--natdnsproxy1", "on"] v.customize ["modifyvm", :id, "--nictype1", "virtio"] # We need quite a bit of memory to compile more than one ycmd C++ file at a # time. v.memory = 3072 v.cpus = 2 end config.vm.provider "parallels" do |v, override| override.vm.box = 'parallels/ubuntu-14.04' v.memory = 3072 v.cpus = 4 v.linked_clone = true v.update_guest_tools = true end end ycmd-0+20161219+git486b809.orig/update_boost.py0000755000175000017500000001363513026170313017234 0ustar onuronur#!/usr/bin/env python from __future__ import print_function from __future__ import division from __future__ import unicode_literals from __future__ import absolute_import import os import platform import re import subprocess import sys import tarfile from tempfile import mkdtemp from shutil import rmtree from distutils.dir_util import copy_tree DIR_OF_THIS_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) ) DIR_OF_THIRD_PARTY = os.path.join( DIR_OF_THIS_SCRIPT, 'third_party' ) sys.path.insert( 1, os.path.abspath( os.path.join( DIR_OF_THIRD_PARTY, 'argparse' ) ) ) sys.path.insert( 1, os.path.abspath( os.path.join( DIR_OF_THIRD_PARTY, 'requests' ) ) ) import argparse import requests CHUNK_SIZE = 1024 * 1024 # 1 MB BOOST_VERSION_REGEX = re.compile( 'Version (\d+\.\d+\.\d+)' ) BOOST_URL = ( 'https://sourceforge.net/projects/boost/files/boost/' '{version}/{archive}/download' ) BOOST_NAME = 'boost_{version_}' BOOST_ARCHIVE = BOOST_NAME + '.tar.bz2' BOOST_PARTS = [ 'boost/utility.hpp', 'boost/python.hpp', 'boost/bind.hpp', 'boost/lambda/lambda.hpp', 'boost/exception/all.hpp', 'boost/tuple/tuple_io.hpp', 'boost/tuple/tuple_comparison.hpp', 'boost/regex.hpp', 'boost/foreach.hpp', 'boost/smart_ptr.hpp', 'boost/algorithm/string_regex.hpp', 'boost/thread.hpp', 'boost/unordered_map.hpp', 'boost/unordered_set.hpp', 'boost/format.hpp', 'boost/ptr_container/ptr_container.hpp', 'boost/filesystem.hpp', 'boost/filesystem/fstream.hpp', 'boost/utility.hpp', 'boost/algorithm/cxx11/any_of.hpp', 'atomic', 'lockfree', 'assign', 'system' ] BOOST_LIBS_FOLDERS_TO_REMOVE = [ 'assign', 'mpi', 'config', 'lockfree', 'doc', 'test', 'examples', 'build' ] BOOST_LIBS_FILES_TO_REMOVE = [ # Extracted with Boost 1.61.0 and breaks the build on Windows. 'xml_woarchive.cpp' ] BOOST_LIBS_EXTENSIONS_TO_KEEP = [ '.hpp', '.cpp', '.ipp', '.inl' ] def OnWindows(): return platform.system() == 'Windows' def Download( url, dest ): print( 'Downloading {0}.'.format( os.path.basename( dest ) ) ) r = requests.get( url, stream = True ) with open( dest, 'wb') as f: for chunk in r.iter_content( chunk_size = CHUNK_SIZE ): if chunk: f.write( chunk ) r.close() def Extract( path, folder = os.curdir ): print( 'Extracting {0}.'.format( os.path.basename( path ) ) ) with tarfile.open( path ) as f: f.extractall( folder ) def GetLatestBoostVersion(): download_page = requests.get( 'http://www.boost.org/users/download/' ) version_match = BOOST_VERSION_REGEX.search( download_page.text ) if not version_match: return None return version_match.group( 1 ) def GetBoostName( version ): return BOOST_NAME.format( version_ = version.replace( '.', '_' ) ) def GetBoostArchiveName( version ): return BOOST_ARCHIVE.format( version_ = version.replace( '.', '_' ) ) def GetBoostArchiveUrl( version ): return BOOST_URL.format( version = version, archive = GetBoostArchiveName( version ) ) def DownloadBoostLibrary( version, folder ): archive_path = os.path.join( folder, GetBoostArchiveName( version ) ) Download( GetBoostArchiveUrl( version ), archive_path ) def CleanBoostParts( boost_libs_dir ): for root, dirs, files in os.walk( boost_libs_dir ): for directory in dirs: if directory in BOOST_LIBS_FOLDERS_TO_REMOVE: rmtree( os.path.join( root, directory ) ) for filename in files: extension = os.path.splitext( filename )[ 1 ] if ( filename in BOOST_LIBS_FILES_TO_REMOVE or extension not in BOOST_LIBS_EXTENSIONS_TO_KEEP ): os.remove( os.path.join( root, filename ) ) def ExtractBoostParts( args ): print( 'Updating Boost to version {0}.'.format( args.version ) ) boost_dir = mkdtemp( prefix = 'boost.' ) try: os.chdir( boost_dir ) DownloadBoostLibrary( args.version, os.curdir ) Extract( os.path.join( os.curdir, GetBoostArchiveName( args.version ) ), os.curdir ) os.chdir( os.path.join( os.curdir, GetBoostName( args.version ) ) ) bootstrap = os.path.join( os.curdir, 'bootstrap' + ( '.bat' if OnWindows() else '.sh' ) ) subprocess.call( [ bootstrap ] ) subprocess.call( [ os.path.join( os.curdir, 'b2' ), os.path.join( 'tools', 'bcp' ) ] ) boost_parts_dir = os.path.join( os.curdir, 'boost_parts' ) os.mkdir( boost_parts_dir ) subprocess.call( [ os.path.join( os.curdir, 'dist', 'bin', 'bcp' ) ] + BOOST_PARTS + [ boost_parts_dir ] ) CleanBoostParts( os.path.join( boost_parts_dir, 'libs' ) ) dest_libs_dir = os.path.join( DIR_OF_THIS_SCRIPT, 'cpp', 'BoostParts', 'libs' ) dest_boost_dir = os.path.join( DIR_OF_THIS_SCRIPT, 'cpp', 'BoostParts', 'boost' ) if os.path.exists( dest_libs_dir ): rmtree( dest_libs_dir ) if os.path.exists( dest_boost_dir ): rmtree( dest_boost_dir ) copy_tree( os.path.join( boost_parts_dir, 'libs' ), dest_libs_dir ) copy_tree( os.path.join( boost_parts_dir, 'boost' ), dest_boost_dir ) finally: os.chdir( DIR_OF_THIS_SCRIPT ) rmtree( boost_dir ) def ParseArguments(): parser = argparse.ArgumentParser( description = 'Update Boost parts to the latest Boost version ' 'or the specified one.' ) parser.add_argument( '--version', help = 'Set Boost version. ' 'Default to latest version.' ) args = parser.parse_args() if not args.version: latest_version = GetLatestBoostVersion() if not latest_version: sys.exit( 'No latest version found. Set Boost version with ' 'the --version option.' ) args.version = latest_version return args def Main(): args = ParseArguments() ExtractBoostParts( args ) if __name__ == '__main__': Main() ycmd-0+20161219+git486b809.orig/CORE_VERSION0000644000175000017500000000000313026170313016030 0ustar onuronur25 ycmd-0+20161219+git486b809.orig/.coveragerc0000644000175000017500000000022213026170313016274 0ustar onuronur[report] omit = */third_party/requests/* */tests/* */__init__.py [run] parallel = True source = ycmd [paths] source = ycmd/ ycmd-0+20161219+git486b809.orig/COPYING.txt0000644000175000017500000010451313026170313016034 0ustar onuronur GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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 this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ycmd-0+20161219+git486b809.orig/third_party/0000755000175000017500000000000013026170313016510 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/tern_runtime/0000755000175000017500000000000013026170313021223 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/tern_runtime/package.json0000644000175000017500000000020313026170313023504 0ustar onuronur{ "description": "ycmd tern runtime area with required tern version and plugins", "dependencies": { "tern": "0.20.0" } } ycmd-0+20161219+git486b809.orig/third_party/waitress/0000755000175000017500000000000013026170313020351 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/OmniSharpServer/0000755000175000017500000000000013026170313021577 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/argparse/0000755000175000017500000000000013026170313020314 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/bottle/0000755000175000017500000000000013026170313020001 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/0000755000175000017500000000000013026170316020066 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/tox.ini0000644000175000017500000000052113026170315021376 0ustar onuronur[tox] envlist = py26, py27, py33, flake8 skipsdist = True [testenv] deps = -r{toxinidir}/test_requirements.txt commands = nosetests -v [testenv:py26] deps = {[testenv]deps} unittest2 ordereddict [testenv:flake8] deps = {[testenv]deps} commands = flake8 --select=F,C9 --max-complexity=10 --exclude=fixtures jedihttp tests ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/LICENSE0000644000175000017500000002613613026170315021102 0ustar onuronur Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/0000755000175000017500000000000013026170315021700 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/0000755000175000017500000000000013026170315023042 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/end_to_end_test.py0000644000175000017500000001234713026170315026560 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from . import utils from .utils import with_jedihttp, py2only import requests import subprocess from jedihttp import hmaclib from os import path from hamcrest import assert_that, equal_to try: from http import client as httplib except ImportError: import httplib class HmacAuth( requests.auth.AuthBase ): def __init__( self, secret ): self._hmac_helper = hmaclib.JediHTTPHmacHelper( secret ) def __call__( self, req ): self._hmac_helper.SignRequestHeaders( req.headers, req.method, req.path_url, req.body ) return req PORT = 50000 SECRET = 'secret' PATH_TO_JEDIHTTP = path.abspath( path.join( path.dirname( __file__ ), '..', '..', 'jedihttp.py' ) ) def wait_for_jedihttp_to_start( jedihttp ): line = jedihttp.stdout.readline().decode( 'utf8' ) good_start = line.startswith( 'serving on' ) reason = jedihttp.stdout.read().decode( 'utf8' ) if not good_start else '' return good_start, reason def setup_jedihttp(): with hmaclib.TemporaryHmacSecretFile( SECRET ) as hmac_file: command = [ utils.python(), '-u', # this flag makes stdout non buffered PATH_TO_JEDIHTTP, '--port', str( PORT ), '--hmac-file-secret', hmac_file.name ] return utils.SafePopen( command, stderr = subprocess.STDOUT, stdout = subprocess.PIPE ) def teardown_jedihttp( jedihttp ): utils.TerminateProcess( jedihttp.pid ) @with_jedihttp( setup_jedihttp, teardown_jedihttp ) def test_client_request_without_parameters( jedihttp ): good_start, reason = wait_for_jedihttp_to_start( jedihttp ) assert_that( good_start, reason ) response = requests.post( 'http://127.0.0.1:{0}/ready'.format( PORT ), auth = HmacAuth( SECRET ) ) assert_that( response.status_code, equal_to( httplib.OK ) ) hmachelper = hmaclib.JediHTTPHmacHelper( SECRET ) assert_that( hmachelper.IsResponseAuthenticated( response.headers, response.content ) ) @with_jedihttp( setup_jedihttp, teardown_jedihttp ) def test_client_request_with_parameters( jedihttp ): good_start, reason = wait_for_jedihttp_to_start( jedihttp ) assert_that( good_start, reason ) filepath = utils.fixture_filepath( 'goto.py' ) request_data = { 'source': open( filepath ).read(), 'line': 10, 'col': 3, 'source_path': filepath } response = requests.post( 'http://127.0.0.1:{0}/gotodefinition'.format( PORT ), json = request_data, auth = HmacAuth( SECRET ) ) assert_that( response.status_code, equal_to( httplib.OK ) ) hmachelper = hmaclib.JediHTTPHmacHelper( SECRET ) assert_that( hmachelper.IsResponseAuthenticated( response.headers, response.content ) ) @with_jedihttp( setup_jedihttp, teardown_jedihttp ) def test_client_bad_request_with_parameters( jedihttp ): good_start, reason = wait_for_jedihttp_to_start( jedihttp ) assert_that( good_start, reason ) filepath = utils.fixture_filepath( 'goto.py' ) request_data = { 'source': open( filepath ).read(), 'line': 100, 'col': 1, 'source_path': filepath } response = requests.post( 'http://127.0.0.1:{0}/gotodefinition'.format( PORT ), json = request_data, auth = HmacAuth( SECRET ) ) assert_that( response.status_code, equal_to( httplib.INTERNAL_SERVER_ERROR ) ) hmachelper = hmaclib.JediHTTPHmacHelper( SECRET ) assert_that( hmachelper.IsResponseAuthenticated( response.headers, response.content ) ) @py2only @with_jedihttp( setup_jedihttp, teardown_jedihttp ) def test_client_python3_specific_syntax_completion( jedihttp ): good_start, reason = wait_for_jedihttp_to_start( jedihttp ) assert_that( good_start, reason ) filepath = utils.fixture_filepath( 'py3.py' ) request_data = { 'source': open( filepath ).read(), 'line': 19, 'col': 11, 'source_path': filepath } response = requests.post( 'http://127.0.0.1:{0}/completions'.format( PORT ), json = request_data, auth = HmacAuth( SECRET ) ) assert_that( response.status_code, equal_to( httplib.OK ) ) hmachelper = hmaclib.JediHTTPHmacHelper( SECRET ) assert_that( hmachelper.IsResponseAuthenticated( response.headers, response.content ) ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/__init__.py0000644000175000017500000000000013026170315025141 0ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/utils.py0000644000175000017500000001114713026170315024560 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Almost all the functions are taken from # https://github.com/Valloric/ycmd/blob/master/ycmd/utils.py import sys import os import signal import subprocess # python3 compatibility try: basestring except NameError: basestring = str try: import unittest2 as unittest except ImportError: import unittest py3only = unittest.skipIf( sys.version_info < ( 3, 0 ), "Python 3.x only test" ) py2only = unittest.skipIf( sys.version_info >= ( 3, 0 ), "Python 2.x only test" ) def python3(): if OnWindows(): return os.path.abspath( '/Python33/python' ) else: return 'python3' def python(): if sys.version_info < ( 3, 0 ) and 'CROSS_PYTHON_TESTS' in os.environ: return python3() else: return sys.executable def with_jedihttp( setup, teardown ): """Decorator which pass the return value of the setup function to the test function and to the teardown function.""" def decorate( func ): class Namespace: pass ns = Namespace() ns.jedihttp = None def test_wrapped(): func( ns.jedihttp ) def setup_wrapped(): ns.jedihttp = setup() def teardown_wrapped(): teardown( ns.jedihttp ) test_wrapped.__name__ = func.__name__ test_wrapped.setup = setup_wrapped test_wrapped.teardown = teardown_wrapped return test_wrapped return decorate def fixture_filepath( *components ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'fixtures', *components ) # Creation flag to disable creating a console window on Windows. See # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx CREATE_NO_WINDOW = 0x08000000 def OnWindows(): return sys.platform == 'win32' # Convert paths in arguments command to short path ones def ConvertArgsToShortPath( args ): def ConvertIfPath( arg ): if os.path.exists( arg ): return GetShortPathName( arg ) return arg if isinstance( args, basestring ): return ConvertIfPath( args ) return [ ConvertIfPath( arg ) for arg in args ] # Get the Windows short path name. # Based on http://stackoverflow.com/a/23598461/200291 def GetShortPathName( path ): from ctypes import windll, wintypes, create_unicode_buffer # Set the GetShortPathNameW prototype _GetShortPathNameW = windll.kernel32.GetShortPathNameW _GetShortPathNameW.argtypes = [ wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD] _GetShortPathNameW.restype = wintypes.DWORD output_buf_size = 0 while True: output_buf = create_unicode_buffer( output_buf_size ) needed = _GetShortPathNameW( path, output_buf, output_buf_size ) if output_buf_size >= needed: return output_buf.value else: output_buf_size = needed # A wrapper for subprocess.Popen that fixes quirks on Windows. def SafePopen( args, **kwargs ): if OnWindows(): # We need this to start the server otherwise bad things happen. # See issue #637. if kwargs.get( 'stdin_windows' ) is subprocess.PIPE: kwargs[ 'stdin' ] = subprocess.PIPE # Do not create a console window kwargs[ 'creationflags' ] = CREATE_NO_WINDOW # Python 2 fails to spawn a process from a command containing unicode # characters on Windows. See https://bugs.python.org/issue19264 and # http://bugs.python.org/issue1759845. # Since paths are likely to contains such characters, we convert them to # short ones to obtain paths with only ascii characters. args = ConvertArgsToShortPath( args ) kwargs.pop( 'stdin_windows', None ) return subprocess.Popen( args, **kwargs ) # From here: http://stackoverflow.com/a/8536476/1672783 def TerminateProcess( pid ): if OnWindows(): import ctypes PROCESS_TERMINATE = 1 handle = ctypes.windll.kernel32.OpenProcess( PROCESS_TERMINATE, False, pid ) ctypes.windll.kernel32.TerminateProcess( handle, -1 ) ctypes.windll.kernel32.CloseHandle( handle ) else: os.kill( pid, signal.SIGTERM ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/0000755000175000017500000000000013026170315024713 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/follow_imports/0000755000175000017500000000000013026170315027772 5ustar onuronur././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/follow_imports/imported.pyycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/follow_imports/imported0000644000175000017500000000004213026170315031534 0ustar onuronurdef imported_function(): pass ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/follow_imports/importer.pyycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/follow_imports/importer0000644000175000017500000000007413026170315031557 0ustar onuronurfrom imported import imported_function imported_function() ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/basic.py0000644000175000017500000000012513026170315026344 0ustar onuronurclass Foo(object): def __init__(self): self.a = 1 self.b = 2 f = Foo() f. ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/usages.py0000644000175000017500000000016313026170315026554 0ustar onuronurdef f(): """ Module method docs Are dedented, like you might expect""" return 1 a = f() b = f() c = f() ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/goto.py0000644000175000017500000000044513026170315026240 0ustar onuronurdef f(): """ Module method docs Are dedented, like you might expect""" pass class C: """ Class Documentation""" pass variable = f if random.choice( [ 0, 1 ] ) else C def foo(): print 'foo' alias = foo _list = [ 1, None, alias ] inception = _list[ 2 ] inception() ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/fixtures/py3.py0000644000175000017500000000061113026170315025776 0ustar onuronurdef make_scoreboard( frame, score = 0 ): label = Label( frame ) label.pack() for i in [ -10, -1, 1, 10 ]: def increment(step=i): nonlocal score score = score + step label['text'] = score button = Button( frame, text='%+d' % i, command=increment ) button.pack() return label d = { 'key1': 'value1', 'key2': 'value2', 'key3': 'value3' } values = d. ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/tests/handlers_test.py0000644000175000017500000002405313026170315026257 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from __future__ import absolute_import from .utils import fixture_filepath, py3only from webtest import TestApp from jedihttp import handlers from nose.tools import ok_ from hamcrest import ( assert_that, only_contains, all_of, is_not, has_key, has_item, has_items, has_entry, has_length, equal_to, is_, empty ) import bottle bottle.debug( True ) def CompletionEntry( name ): return has_entry( 'name', name ) def valid_completions(): return all_of( has_key( 'docstring' ), has_key( 'name' ), has_key( 'description' ) ) def test_healthy(): app = TestApp( handlers.app ) ok_( app.post( '/healthy' ) ) def test_ready(): app = TestApp( handlers.app ) ok_( app.post( '/ready' ) ) # XXX(vheon): test for unicode, specially for python3 # where encoding must be specified def test_completion(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'basic.py' ) request_data = { 'source': open( filepath ).read(), 'line': 7, 'col': 2, 'source_path': filepath } completions = app.post_json( '/completions', request_data ).json[ 'completions' ] assert_that( completions, only_contains( valid_completions() ) ) assert_that( completions, has_items( CompletionEntry( 'a' ), CompletionEntry( 'b' ) ) ) def test_good_gotodefinition(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'goto.py' ) request_data = { 'source': open( filepath ).read(), 'line': 10, 'col': 3, 'source_path': filepath } definitions = app.post_json( '/gotodefinition', request_data ).json[ 'definitions' ] assert_that( definitions, has_length( 2 ) ) assert_that( definitions, has_items( { 'module_path': filepath, 'name': 'f', 'in_builtin_module': False, 'line': 1, 'column': 4, 'docstring': 'f()\n\nModule method docs\nAre ' 'dedented, like you might expect', 'description': 'def f', 'is_keyword': False, }, { 'module_path': filepath, 'name': 'C', 'in_builtin_module': False, 'line': 6, 'column': 6, 'docstring': 'Class Documentation', 'description': 'class C', 'is_keyword': False } ) ) def test_bad_gotodefinitions_blank_line(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'goto.py' ) request_data = { 'source': open( filepath ).read(), 'line': 9, 'col': 1, 'source_path': filepath } definitions = app.post_json( '/gotodefinition', request_data ).json[ 'definitions' ] assert_that( definitions, is_( empty() ) ) def test_bad_gotodefinitions_not_on_valid_position(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'goto.py' ) request_data = { 'source': open( filepath ).read(), 'line': 100, 'col': 1, 'source_path': filepath } response = app.post_json( '/gotodefinition', request_data, expect_errors = True ) assert_that( response.status_int, equal_to( 500 ) ) def test_good_gotoassignment(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'goto.py' ) request_data = { 'source': open( filepath ).read(), 'line': 20, 'col': 1, 'source_path': filepath } definitions = app.post_json( '/gotoassignment', request_data ).json[ 'definitions' ] assert_that( definitions, has_length( 1 ) ) assert_that( definitions, has_item( { 'module_path': filepath, 'name': 'inception', 'in_builtin_module': False, 'line': 18, 'column': 0, 'docstring': '', 'description': 'inception = _list[ 2 ]', 'is_keyword': False } ) ) def test_good_gotoassignment_do_not_follow_imports(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'follow_imports', 'importer.py' ) request_data = { 'source': open( filepath ).read(), 'line': 3, 'col': 9, 'source_path': filepath } expected_definition = { 'module_path': filepath, 'name': 'imported_function', 'in_builtin_module': False, 'line': 1, 'column': 21, 'docstring': '', 'description': 'from imported ' 'import imported_function', 'is_keyword': False } definitions = app.post_json( '/gotoassignment', request_data ).json[ 'definitions' ] assert_that( definitions, has_length( 1 ) ) assert_that( definitions, has_item( expected_definition ) ) request_data[ 'follow_imports' ] = False definitions = app.post_json( '/gotoassignment', request_data ).json[ 'definitions' ] assert_that( definitions, has_length( 1 ) ) assert_that( definitions, has_item( expected_definition ) ) def test_good_gotoassignment_follow_imports(): app = TestApp( handlers.app ) importer_filepath = fixture_filepath( 'follow_imports', 'importer.py' ) imported_filepath = fixture_filepath( 'follow_imports', 'imported.py' ) request_data = { 'source': open( importer_filepath ).read(), 'line': 3, 'col': 9, 'source_path': importer_filepath, 'follow_imports': True } definitions = app.post_json( '/gotoassignment', request_data ).json[ 'definitions' ] assert_that( definitions, has_length( 1 ) ) assert_that( definitions, has_item( { 'module_path': imported_filepath, 'name': 'imported_function', 'in_builtin_module': False, 'line': 1, 'column': 4, 'docstring': 'imported_function()\n\n', 'description': 'def imported_function', 'is_keyword': False } ) ) def test_usages(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'usages.py' ) request_data = { 'source': open( filepath ).read(), 'line': 8, 'col': 5, 'source_path': filepath } definitions = app.post_json( '/usages', request_data ).json[ 'definitions' ] assert_that( definitions, has_length( 4 ) ) assert_that( definitions, has_items( { 'module_path': filepath, 'name': 'f', 'in_builtin_module': False, 'line': 1, 'column': 4, 'docstring': 'f()\n\nModule method docs\nAre dedented, like you might expect', 'description': 'def f', 'is_keyword': False }, { 'module_path': filepath, 'name': 'f', 'in_builtin_module': False, 'line': 6, 'column': 4, 'description': 'a = f()', 'docstring': '', 'is_keyword': False }, { 'module_path': filepath, 'name': 'f', 'in_builtin_module': False, 'line': 7, 'column': 4, 'description': 'b = f()', 'docstring': '', 'is_keyword': False }, { 'module_path': filepath, 'name': 'f', 'in_builtin_module': False, 'line': 8, 'column': 4, 'description': 'c = f()', 'docstring': '', 'is_keyword': False } ) ) @py3only def test_py3(): app = TestApp( handlers.app ) filepath = fixture_filepath( 'py3.py' ) request_data = { 'source': open( filepath ).read(), 'line': 19, 'col': 11, 'source_path': filepath } completions = app.post_json( '/completions', request_data ).json[ 'completions' ] assert_that( completions, has_item( CompletionEntry( 'values' ) ) ) assert_that( completions, is_not( has_item( CompletionEntry( 'itervalues' ) ) ) ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/__init__.py0000644000175000017500000000000013026170315023777 0ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/handlers.py0000644000175000017500000001054613026170315024060 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from jedihttp import utils utils.AddVendorFolderToSysPath() import jedi import logging import json import bottle from jedihttp import hmaclib from bottle import response, request, Bottle from threading import Lock try: import httplib except ImportError: from http import client as httplib # num bytes for the request body buffer; request.json only works if the request # size is less than this bottle.Request.MEMFILE_MAX = 1000 * 1024 logger = logging.getLogger( __name__ ) app = Bottle( __name__ ) # Jedi is not thread safe. jedi_lock = Lock() @app.post( '/healthy' ) def healthy(): logger.debug( 'received /healthy request' ) return _JsonResponse( True ) @app.post( '/ready' ) def ready(): logger.debug( 'received /ready request' ) return _JsonResponse( True ) @app.post( '/completions' ) def completions(): logger.debug( 'received /completions request' ) with jedi_lock: script = _GetJediScript( request.json ) response = { 'completions': [ { 'module_path': completion.module_path, 'name': completion.name, 'line': completion.line, 'column': completion.column, 'docstring': completion.docstring(), 'description': completion.description, 'type': completion.type } for completion in script.completions() ] } return _JsonResponse( response ) @app.post( '/gotodefinition' ) def gotodefinition(): logger.debug( 'received /gotodefinition request' ) with jedi_lock: script = _GetJediScript( request.json ) response = _FormatDefinitions( script.goto_definitions() ) return _JsonResponse( response ) @app.post( '/gotoassignment' ) def gotoassignments(): logger.debug( 'received /gotoassignment request' ) with jedi_lock: request_json = request.json follow_imports = ( 'follow_imports' in request_json and request_json[ 'follow_imports' ] ) script = _GetJediScript( request_json ) response = _FormatDefinitions( script.goto_assignments( follow_imports ) ) return _JsonResponse( response ) @app.post( '/usages' ) def usages(): logger.debug( 'received /usages request' ) with jedi_lock: script = _GetJediScript( request.json ) response = _FormatDefinitions( script.usages() ) return _JsonResponse( response ) def _FormatDefinitions( definitions ): return { 'definitions': [ { 'module_path': definition.module_path, 'name': definition.name, 'in_builtin_module': definition.in_builtin_module(), 'line': definition.line, 'column': definition.column, 'docstring': definition.docstring(), 'description': definition.description, 'is_keyword': definition.is_keyword } for definition in definitions ] } def _GetJediScript( request_data ): return jedi.Script( request_data[ 'source' ], request_data[ 'line' ], request_data[ 'col' ], request_data[ 'source_path' ] ) @app.error( httplib.INTERNAL_SERVER_ERROR ) def ErrorHandler( httperror ): body = _JsonResponse( { 'exception': httperror.exception, 'message': str( httperror.exception ), 'traceback': httperror.traceback } ) if 'jedihttp.hmac_secret' in app.config: hmac_secret = app.config[ 'jedihttp.hmac_secret' ] hmachelper = hmaclib.JediHTTPHmacHelper( hmac_secret ) hmachelper.SignResponseHeaders( response.headers, body ) return body def _JsonResponse( data ): response.content_type = 'application/json' return json.dumps( data, default = _Serializer ) def _Serializer( obj ): try: serialized = obj.__dict__.copy() serialized[ 'TYPE' ] = type( obj ).__name__ return serialized except AttributeError: return str( obj ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/compatibility.py0000644000175000017500000000407413026170315025130 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys if sys.version_info[0] >= 3: basestring = str unicode = str def encode_string( value ): return value.encode('utf-8') if isinstance(value, unicode) else value def decode_string(value): return value if isinstance(value, basestring) else value.decode('utf-8') # hmac.compare_digest were introduced in python 2.7.7 if sys.version_info >= ( 2, 7, 7 ): from hmac import compare_digest as SecureStringsEqual else: # This is the compare_digest function from python 3.4, adapted for 2.6: # http://hg.python.org/cpython/file/460407f35aa9/Lib/hmac.py#l16 # # Stolen from https://github.com/Valloric/ycmd def SecureStringsEqual( a, b ): """Returns the equivalent of 'a == b', but avoids content based short circuiting to reduce the vulnerability to timing attacks.""" # Consistent timing matters more here than data type flexibility if not ( isinstance( a, str ) and isinstance( b, str ) ): raise TypeError( "inputs must be str instances" ) # We assume the length of the expected digest is public knowledge, # thus this early return isn't leaking anything an attacker wouldn't # already know if len( a ) != len( b ): return False # We assume that integers in the bytes range are all cached, # thus timing shouldn't vary much due to integer object creation result = 0 for x, y in zip( a, b ): result |= ord( x ) ^ ord( y ) return result == 0 def compare_digest( a, b ): return SecureStringsEqual( a, b ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/utils.py0000644000175000017500000000173113026170315023414 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys def AddVendorFolderToSysPath(): vendor_folder = os.path.join( os.path.dirname( __file__ ), '..', 'vendor' ) for folder in os.listdir( vendor_folder ): sys.path.insert( 0, os.path.realpath( os.path.join( vendor_folder, folder ) ) ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/hmac_plugin.py0000644000175000017500000000457013026170315024546 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import logging from bottle import request, response, abort from jedihttp import hmaclib try: from urlparse import urlparse import httplib except ImportError: from urllib.parse import urlparse from http import client as httplib class HmacPlugin( object ): """ Bottle plugin for hmac request authentication http://bottlepy.org/docs/dev/plugindev.html """ name = 'hmac' api = 2 def __init__( self ): self._logger = logging.getLogger( __name__ ) def setup( self, app ): hmac_secret = app.config[ 'jedihttp.hmac_secret' ] self._hmachelper = hmaclib.JediHTTPHmacHelper( hmac_secret ) def __call__( self, callback ): def wrapper( *args, **kwargs ): if not IsLocalRequest(): self._logger.info( 'Dropping request with bad Host header.' ) abort( httplib.UNAUTHORIZED, 'Unauthorized, received request from non-local Host.' ) return if not self.IsRequestAuthenticated(): self._logger.info( 'Dropping request with bad HMAC.' ) abort( httplib.UNAUTHORIZED, 'Unauthorized, received bad HMAC.' ) return body = callback( *args, **kwargs ) self.SignResponseHeaders( response.headers, body ) return body return wrapper def IsRequestAuthenticated( self ): return self._hmachelper.IsRequestAuthenticated( request.headers, request.method, request.path, request.body.read() ) def SignResponseHeaders( self, headers, body ): self._hmachelper.SignResponseHeaders( headers, body ) def IsLocalRequest(): host = urlparse( 'http://' + request.headers[ 'host' ] ).hostname return host == '127.0.0.1' or host == 'localhost' ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp/hmaclib.py0000644000175000017500000000613713026170315023660 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import json import hmac import hashlib import tempfile from base64 import b64encode, b64decode from jedihttp.compatibility import encode_string, decode_string, compare_digest def TemporaryHmacSecretFile( secret ): """Helper function for passing the hmac secret when starting a JediHTTP server with TemporaryHmacSecretFile( 'mysecret' ) as hmac_file: jedihttp = subprocess.Popen( ['python', 'jedihttp', '--hmac-file-secret', hmac_file.name ] ) The JediHTTP Server as soon as it reads the hmac secret will remove the file """ hmac_file = tempfile.NamedTemporaryFile( 'w', delete = False ) encoded_secret = decode_string( b64encode( encode_string( secret ) ) ) json.dump( { 'hmac_secret': encoded_secret }, hmac_file ) return hmac_file _HMAC_HEADER = 'x-jedihttp-hmac' class JediHTTPHmacHelper( object ): """Helper class to correctly signing requests and validating responses when communicating with a JediHTTP server.""" def __init__( self, secret ): self._secret = encode_string( secret ) def _HasHeader( self, headers ): return _HMAC_HEADER in headers def _SetHmacHeader( self, headers, hmac ): headers[ _HMAC_HEADER ] = decode_string( b64encode( hmac ) ) def _GetHmacHeader( self, headers ): return b64decode( headers[ _HMAC_HEADER ] ) def _Hmac( self, content ): return hmac.new( self._secret, msg = encode_string( content ), digestmod = hashlib.sha256 ).digest() def _ComputeRequestHmac( self, method, path, body ): if not body: body = '' return self._Hmac( b''.join( ( self._Hmac( method ), self._Hmac( path ), self._Hmac( body ) ) ) ) def SignRequestHeaders( self, headers, method, path, body ): self._SetHmacHeader( headers, self._ComputeRequestHmac( method, path, body ) ) def IsRequestAuthenticated( self, headers, method, path, body ): if not self._HasHeader( headers ): return False return compare_digest( self._GetHmacHeader( headers ), self._ComputeRequestHmac( method, path, body ) ) def SignResponseHeaders( self, headers, body ): self._SetHmacHeader( headers, self._Hmac( body ) ) def IsResponseAuthenticated( self, headers, content ): if not self._HasHeader( headers ): return False return compare_digest( self._GetHmacHeader( headers ), self._Hmac( content ) ) ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/.travis.yml0000644000175000017500000000253013026170315022176 0ustar onuronurlanguage: python sudo: false matrix: include: # TOXENV specify under which environment tox should launch the tests # https://testrun.org/tox/latest/ - python: 2.6 env: TOXENV=py26 - python: 2.7 env: TOXENV=py27 - python: 3.3 env: TOXENV=py33 - python: 2.6 env: - TOXENV=py26 - CROSS_PYTHON_TESTS=true - python: 2.7 env: - TOXENV=py27 - CROSS_PYTHON_TESTS=true - python: 2.7 env: TOXENV=flake8 - python: 3.3 env: TOXENV=flake8 - language: generic os: osx osx_image: xcode7 env: TOXENV=py26 - language: generic os: osx osx_image: xcode7 env: TOXENV=py27 - language: generic os: osx osx_image: xcode7 env: - TOXENV=py26 - CROSS_PYTHON_TESTS=true - language: generic os: osx osx_image: xcode7 env: - TOXENV=py27 - CROSS_PYTHON_TESTS=true - language: generic os: osx osx_image: xcode7 env: TOXENV=py33 - language: generic os: osx osx_image: xcode7 env: TOXENV=flake8 - language: generic os: osx osx_image: xcode7 env: TOXENV=flake8 before_install: git submodule update --init --recursive install: ./travis/install.sh script: ./travis/run.sh notifications: email: false ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/appveyor.yml0000644000175000017500000000413513026170315022460 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # used https://github.com/ogrisel/python-appveyor-demo/blob/master/appveyor.yml # for guidance environment: matrix: - PYTHON: "C:\\Python27" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "32" TOXENV: "py27" - PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" TOXENV: "py27" - PYTHON: "C:\\Python27" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "32" TOXENV: "py27" CROSS_PYTHON_TESTS: "true" - PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" TOXENV: "py27" CROSS_PYTHON_TESTS: "true" - PYTHON: "C:\\Python33" PYTHON_VERSION: "3.3.x" PYTHON_ARCH: "32" TOXENV: "py33" - PYTHON: "C:\\Python33-x64" PYTHON_VERSION: "3.3.x" PYTHON_ARCH: "64" TOXENV: "py33" - PYTHON: "C:\\Python33-x64" PYTHON_VERSION: "3.3.x" PYTHON_ARCH: "64" TOXENV: "flake8" - PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" TOXENV: "flake8" install: - git submodule update --init --recursive # Prepend newly installed Python to the PATH of this build (this cannot be # done from inside the powershell script as it would require to restart # the parent CMD process). - set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH% # Upgrade to the latest version of pip to avoid it displaying warnings # about it being out of date. - pip install --disable-pip-version-check --user --upgrade pip - pip install tox build_script: - tox ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/README.md0000644000175000017500000001276013026170315021352 0ustar onuronur# JediHTTP [![Build Status](https://travis-ci.org/vheon/JediHTTP.svg?branch=master)](https://travis-ci.org/vheon/JediHTTP) [![Build status](https://ci.appveyor.com/api/projects/status/28ebc35ocjk9eaew/branch/master?svg=true)](https://ci.appveyor.com/project/vheon/jedihttp/branch/master) A simple http/json wrapper around [jedi][]. ## Why It's only purpose for me is to integrate it with [YouCompleteMe][] allowing to run [jedi][] under python3 and get python3 completions, but that would not exclude other uses :). At the moment not all the API It has been wrapped. ## Command-line For starting the server, after you have cloned it somewhere: ``` python /path/to/JediHTTP/jedihttp.py [options] ``` ### Options #### `--host` ADDRESS If not specified, 127.0.0.1 is used. #### `--port` PORT Listen on PORT. If not specified, will use any available port. #### `--log` LEVEL Set logging level to LEVEL. Available levels, from most verbose to least verbose, are: `debug`, `info`, `warning`, `error`, and `critical`. Default value is `info`. #### `--hmac-secret-file` PATH PATH is the path of a JSON file containing a key named `hmac_secret`. Its value will be used as the secret for HMAC Auth and the file will be deleted as soon as it's read. ## API I thought JediHTTP as a simple wrapper around Jedi so its JSON API resembles the original python one very much so for more information about what the parameters are and what they represent look at the original docs [jedi-plugin-api][]. ### POST /healthy Return a 200 status code if the server is up. ### POST /ready Return a 200 status code if the server is up. Is the same as `/healthy`. ### POST /completions Parameters: ```javascript { "source": "def f():\n pass", "line": 1, "col": 0, "path": "/home/user/code/src/file.py" } ``` Response: ```javascript { "completions": [ { "name": "name", // Name of variable/function/class/module. "description": "A textual description of the object.", "docstring": "A document string for this completion object.", "module_path": "/usr/lib/python2.7/os.py", // Shows the file path of a module "line": 4, // The line where the definition occurs (starting with 1). "column": 2 // The column where the definition occurs (starting with 0). }, ... ] } ``` ### POST /gotodefinition Parameters: ```javascript { "source": "def f():\n pass", "line": 1, "col": 0, "path": "/home/user/code/src/file.py" } ``` Response: ```javascript { "definitions": [ { "module_path": "/usr/lib/python2.7/os.py", // Shows the file path of a module "line": 3, // The line where the definition occurs (starting with 1). "column": 1 // The column where the definition occurs (starting with 0). "in_builtin_module": false, // Whether this is a builtin module. "is_keyword": false, "description": "A description of the Definition object", "docstring": "A document string for this Definition object.", } ] } ``` ### POST /gotoassignment Parameters: ```javascript { "source": "def f():\n pass", "line": 1, "col": 0, "path": "/home/user/code/src/file.py", "follow_imports": true, // Optional (default is false) } ``` Response: ```javascript { "definitions": [ { "module_path": "/usr/lib/python2.7/os.py", // Shows the file path of a module "line": 3, // The line where the definition occurs (starting with 1). "column": 1 // The column where the definition occurs (starting with 0). "in_builtin_module": false, // Whether this is a builtin module. "is_keyword": false, "description": "A description of the Definition object", "docstring": "A document string for this Definition object.", } ] } ``` ### POST /usages Parameters: ```javascript { "source": "def f():\n pass\n\na = f()\nb = f()", "line": 1, "col": 4, "path": "/home/user/code/src/file.py" } ``` Response: ```javascript { "definitions": [ { 'description': 'def f', 'in_builtin_module': False, 'is_keyword': False, 'module_path': '/home/user/code/src/file.py', 'column': 4, 'line': 1, 'docstring': '' }, { 'description': 'a = f()', 'in_builtin_module': False, 'is_keyword': False, 'module_path': /home/user/code/src/file.py, 'column': 4, 'line': 4, 'docstring': '' }, { 'description': 'b = f()', 'in_builtin_module': False, 'is_keyword': False, 'module_path': '/home/user/code/src/file.py', 'column': 4, 'line': 5, 'docstring': '' } ] } ``` ### In case of errors Response: ```javascript { "exception": "ValueError" "message": "`column` parameter is not in a valid range.", "traceback": "Traceback ..." } ``` status code: 500 ## HMAC Auth If the server is started with the `--hmac-file-secret` then the JediHTTP will require every request and response has to be HMAC signed based on the secred provided in the file putting the HMAC signature in a header called `x-jedihttp-hmac` Assuming `||` stands for concatenation: - requests signature: HMAC( HMAC( body ) || HMAC( http method ) || HMAC( request path ) ). For example, HMAC(HMAC('foo') || HMAC('GET') || HMAC('/healthy')) - Responses: HMAC( body ) ## Disclaimer I'm not a python programmer but I'm using this to experiment with python a bit. [jedi]: http://github.com/davidhalter/jedi [jedi-plugin-api]: http://jedi.jedidjah.ch/en/latest/docs/plugin-api.html#module-jedi.api [YouCompleteMe]: http://github.com/Valloric/YouCompleteMe ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/travis/0000755000175000017500000000000013026170315021375 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/travis/run.sh0000755000175000017500000000121713026170315022541 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #!/bin/bash set -e source ~/.venv/bin/activate tox ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/travis/install.sh0000755000175000017500000000263113026170315023404 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #!/bin/bash # Adapted from: # https://github.com/pyca/cryptography/blob/master/.travis/install.sh set -e if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then # install pyenv git clone --branch=v20151103 --depth=1 https://github.com/yyuu/pyenv.git ~/.pyenv PYENV_ROOT="$HOME/.pyenv" PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" pyenv install 3.3.6 echo "3.3.6" >> .python-version case "${TOXENV}" in py26) curl -O https://bootstrap.pypa.io/get-pip.py python get-pip.py --user ;; py27) curl -O https://bootstrap.pypa.io/get-pip.py python get-pip.py --user ;; py33) pyenv global 3.3.6 ;; esac pyenv rehash python -m pip install --user virtualenv else pip install virtualenv fi python -m virtualenv ~/.venv source ~/.venv/bin/activate pip install tox ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/jedihttp.py0000644000175000017500000000531413026170315022255 0ustar onuronur# Copyright 2015 Cedraro Andrea # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from jedihttp import utils utils.AddVendorFolderToSysPath() import logging import json import os import sys from base64 import b64decode from argparse import ArgumentParser from waitress import serve from jedihttp import handlers from jedihttp.hmac_plugin import HmacPlugin def ParseArgs(): parser = ArgumentParser() parser.add_argument( '--host', type = str, default = '127.0.0.1', help = 'server host' ) parser.add_argument( '--port', type = int, default = 0, help = 'server port' ) parser.add_argument( '--log', type = str, default = 'info', choices = [ 'debug', 'info', 'warning', 'error', 'critical' ], help = 'log level' ) parser.add_argument( '--hmac-file-secret', type = str, help = 'file containing hmac secret' ) return parser.parse_args() def SetUpLogging( log_level ): numeric_level = getattr( logging, log_level.upper(), None ) if not isinstance( numeric_level, int ): raise ValueError( 'Invalid log level: {0}'.format( log_level ) ) # Has to be called before any call to logging.getLogger(). logging.basicConfig( format = '%(asctime)s - %(levelname)s - %(message)s', level = numeric_level ) def GetSecretFromTempFile( tfile ): key = 'hmac_secret' with open( tfile ) as hmac_file: try: data = json.load( hmac_file ) if key not in data: sys.exit( "A json file with a key named 'secret' was expected for " "the secret exchange, but wasn't found" ) hmac_secret = data[ key ] except ValueError: sys.exit( "A JSON was expected for the secret exchange" ) os.remove( tfile ) return hmac_secret def Main(): args = ParseArgs() SetUpLogging( args.log ) if args.hmac_file_secret: hmac_secret = GetSecretFromTempFile( args.hmac_file_secret ) handlers.app.config[ 'jedihttp.hmac_secret' ] = b64decode( hmac_secret ) handlers.app.install( HmacPlugin() ) serve( handlers.app, host = args.host, port = args.port ) if __name__ == "__main__": Main() ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/vendor/0000755000175000017500000000000013026170315021362 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/vendor/waitress/0000755000175000017500000000000013026170315023223 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/vendor/argparse/0000755000175000017500000000000013026170315023166 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/vendor/bottle/0000755000175000017500000000000013026170315022653 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/vendor/jedi/0000755000175000017500000000000013026170315022275 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/JediHTTP/test_requirements.txt0000644000175000017500000000011113026170315024401 0ustar onuronurflake8>=2.0 nose>=1.3.0 WebTest>=2.0.0 PyHamcrest>=1.8.0 requests>=2.8.1 ycmd-0+20161219+git486b809.orig/third_party/JediHTTP/NOTICE0000644000175000017500000000156113026170315020774 0ustar onuronur Copyright 2015 Cedraro Andrea Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. This project includes Jedi (http://jedi.jedidjah.ch) Copyright (c) 2013 David Halter and others This project includes Bottle (http://bottlepy.org/) Copyright (c) 2012, Marcel Hellkamp. This project includes Waitress (http://docs.pylonsproject.org/projects/waitress) Zope Foundation and Contributors ycmd-0+20161219+git486b809.orig/third_party/python-future/0000755000175000017500000000000013026170313021341 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/godef/0000755000175000017500000000000013026170313017574 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/gocode/0000755000175000017500000000000013026170313017750 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/racerd/0000755000175000017500000000000013026170313017750 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/requests/0000755000175000017500000000000013026170313020363 5ustar onuronurycmd-0+20161219+git486b809.orig/third_party/frozendict/0000755000175000017500000000000013026170313020657 5ustar onuronurycmd-0+20161219+git486b809.orig/ci/0000755000175000017500000000000013026170313014552 5ustar onuronurycmd-0+20161219+git486b809.orig/ci/appveyor/0000755000175000017500000000000013026170313016417 5ustar onuronurycmd-0+20161219+git486b809.orig/ci/appveyor/appveyor_install.bat0000644000175000017500000000273013026170313022504 0ustar onuronur:: Since we are caching target folder in racerd submodule and git cannot clone :: a submodule in a non-empty folder, we move out the cached folder and move it :: back after cloning submodules. if exist third_party\racerd\target ( move third_party\racerd\target racerd_target ) git submodule update --init --recursive :: Batch script will not exit if a command returns an error, so we manually do :: it for commands that may fail. if %errorlevel% neq 0 exit /b %errorlevel% if exist racerd_target ( move racerd_target third_party\racerd\target ) :: :: Python configuration :: if %arch% == 32 ( set python_path=C:\Python%python% ) else ( set python_path=C:\Python%python%-x64 ) set PATH=%python_path%;%python_path%\Scripts;%PATH% python --version appveyor DownloadFile https://bootstrap.pypa.io/get-pip.py python get-pip.py pip install -r test_requirements.txt if %errorlevel% neq 0 exit /b %errorlevel% pip install codecov if %errorlevel% neq 0 exit /b %errorlevel% :: :: Typescript configuration :: :: Since npm executable is a batch file, we need to prefix it with a call :: statement. See https://github.com/npm/npm/issues/2938 call npm install -g typescript if %errorlevel% neq 0 exit /b %errorlevel% :: :: Rust configuration :: appveyor DownloadFile https://static.rust-lang.org/dist/rust-1.8.0-x86_64-pc-windows-msvc.exe rust-1.8.0-x86_64-pc-windows-msvc.exe /VERYSILENT /NORESTART /DIR="C:\Program Files\Rust" set PATH=C:\Program Files\Rust\bin;%PATH% rustc -Vv cargo -V ycmd-0+20161219+git486b809.orig/ci/README.md0000644000175000017500000000026713026170313016036 0ustar onuronurTravis and AppVeyor Scripts =========================== This directory contains scripts used for testing `ycmd` on Travis and AppVeyor CIs. They should not normally be run by users. ycmd-0+20161219+git486b809.orig/ci/travis/0000755000175000017500000000000013026170313016062 5ustar onuronurycmd-0+20161219+git486b809.orig/ci/travis/travis_install.linux.sh0000644000175000017500000000114313026170313022611 0ustar onuronur# Linux-specific installation # We can't use sudo, so we have to approximate the behaviour of the following: # $ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 90 mkdir ${HOME}/bin ln -s /usr/bin/g++-4.8 ${HOME}/bin/c++ ln -s /usr/bin/gcc-4.8 ${HOME}/bin/cc ln -s /usr/bin/gcov-4.8 ${HOME}/bin/gcov export PATH=${HOME}/bin:${PATH} # In order to work with ycmd, python *must* be built as a shared library. This # is set via the PYTHON_CONFIGURE_OPTS option. export PYTHON_CONFIGURE_OPTS="--enable-shared" # Pre-installed Node.js is too old. Install latest Node.js v4 LTS. nvm install 4 ycmd-0+20161219+git486b809.orig/ci/travis/travis_install.sh0000644000175000017500000000452513026170313021462 0ustar onuronur#!/bin/bash # Exit immediately if a command returns a non-zero status. set -e #################### # OS-specific setup #################### # Requirements of OS-specific install: # - install any software which is not installed by Travis configuration # - set up everything necessary so that pyenv can build python source ci/travis/travis_install.${TRAVIS_OS_NAME}.sh ############# # pyenv setup ############# export PYENV_ROOT="${HOME}/.pyenv" if [ ! -d "${PYENV_ROOT}/.git" ]; then git clone https://github.com/yyuu/pyenv.git ${PYENV_ROOT} fi pushd ${PYENV_ROOT} git fetch --tags git checkout v20160202 popd export PATH="${PYENV_ROOT}/bin:${PATH}" eval "$(pyenv init -)" if [ "${YCMD_PYTHON_VERSION}" == "2.6" ]; then PYENV_VERSION="2.6.6" elif [ "${YCMD_PYTHON_VERSION}" == "2.7" ]; then # We need a recent enough version of Python 2.7 on OS X or an error occurs # when installing the psutil dependency for our tests. PYENV_VERSION="2.7.8" else PYENV_VERSION="3.3.6" fi pyenv install --skip-existing ${PYENV_VERSION} pyenv rehash pyenv global ${PYENV_VERSION} # It is quite easy to get the above series of steps wrong. Verify that the # version of python actually in the path and used is the version that was # requested, and fail the build if we broke the travis setup python_version=$(python -c 'import sys; print( "{0}.{1}".format( sys.version_info[0], sys.version_info[1] ) )') echo "Checking python version (actual ${python_version} vs expected ${YCMD_PYTHON_VERSION})" test ${python_version} == ${YCMD_PYTHON_VERSION} ############ # pip setup ############ pip install -U pip wheel setuptools pip install -r test_requirements.txt # Enable coverage for Python subprocesses. See: # http://coverage.readthedocs.org/en/coverage-4.0.3/subprocess.html echo -e "import coverage\ncoverage.process_startup()" > \ ${PYENV_ROOT}/versions/${PYENV_VERSION}/lib/python${YCMD_PYTHON_VERSION}/site-packages/sitecustomize.py ############ # rust setup ############ # Need rust available, but travis doesn't give it to you without language: rust pushd ${HOME} git clone --recursive https://github.com/brson/multirust cd multirust git reset --hard f3974f2b966476ad656afba311b50a9c23fe6d2e ./build.sh ./install.sh --prefix=${HOME} popd multirust update stable multirust default stable ############### # Node.js setup ############### npm install -g typescript set +e ycmd-0+20161219+git486b809.orig/ci/travis/travis_install.osx.sh0000644000175000017500000000174513026170313022273 0ustar onuronur# OS X-specific installation # There's a homebrew bug which causes brew update to fail the first time. Run # it twice to workaround. https://github.com/Homebrew/homebrew/issues/42553 brew update || brew update # List of homebrew formulae to install in the order they appear. # We require node, go and ninja for our build and tests, and all the others are # dependencies of pyenv. REQUIREMENTS="node.js go ninja readline autoconf pkg-config openssl" # Install node, go, ninja, pyenv and dependencies. for pkg in $REQUIREMENTS; do # Install package, or upgrade it if it is already installed. brew install $pkg || brew outdated $pkg || brew upgrade $pkg done # In order to work with ycmd, python *must* be built as a shared library. The # most compatible way to do this on OS X is with --enable-framework. This is # set via the PYTHON_CONFIGURE_OPTS option. export PYTHON_CONFIGURE_OPTS="--enable-framework" ycmd-0+20161219+git486b809.orig/codecov.yml0000644000175000017500000000134113026170313016323 0ustar onuronurcodecov: notify: require_ci_to_pass: yes coverage: precision: 2 round: down range: 70...100 status: # Learn more at https://codecov.io/docs#yaml_default_commit_status project: true patch: true changes: true # We don't want statistics for the tests themselves and certainly not for the # boost libraries. Note that while we exclude the gcov data for these patterns # in the codecov call (codecov --gcov-glob ...), the fact that our code # references these areas also means we need to tell codecov itself to ignore # them from the stats. ignore: - .*/tests/.* - .*/BoostParts/.* comment: layout: "header, diff, changes, uncovered" behavior: default # update if exists else create new ycmd-0+20161219+git486b809.orig/appveyor.yml0000644000175000017500000000172013026170313016547 0ustar onuronurversion: '{build}' branches: # Since Homu does not support AppVeyor, we ignore the branch it uses. except: - auto environment: USE_CLANG_COMPLETER: true COVERAGE: true matrix: # We only test MSVC 11 and 12 with Python 3.5 on 64 bits. - msvc: 11 arch: 64 python: 35 - msvc: 12 arch: 64 python: 35 - msvc: 14 arch: 32 python: 35 # We only test Python 2.7 with MSVC 14 on 64 bits. - msvc: 14 arch: 64 python: 27 - msvc: 14 arch: 64 python: 35 install: - ci\appveyor\appveyor_install.bat build_script: - python run_tests.py --msvc %MSVC% after_build: - codecov # Disable automatic tests test: off cache: - '%LOCALAPPDATA%\pip\cache' # Python packages from pip - '%APPDATA%\npm-cache' # Node packages from npm - '%USERPROFILE%\.cargo' # Cargo package deps - '%APPVEYOR_BUILD_FOLDER%\clang_archives' # Clang downloads - '%APPVEYOR_BUILD_FOLDER%\third_party\racerd\target' # Racerd compilation ycmd-0+20161219+git486b809.orig/CODE_OF_CONDUCT.md0000644000175000017500000000452113026170313016760 0ustar onuronur# Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at val@markovic.io. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [http://contributor-covenant.org/version/1/3/0/][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/3/0/ ycmd-0+20161219+git486b809.orig/CONTRIBUTING.md0000644000175000017500000001777113026170313016425 0ustar onuronurWriting good issue reports ========================== First things first: **the issue tracker is NOT for tech support**. It is for reporting bugs and requesting features. If your issue amounts to "I can't get ycmd to work on my machine" and the reason why is obviously related to your machine configuration and the problem would not be resolved with _reasonable_ changes to the ycmd codebase, then the issue is likely to be closed. **A good place to ask questions is the [ycmd-users][] Google group**. Rule of thumb: if you're not sure whether your problem is a real bug, ask on the group. **ycmd compiles just fine**; [the build bots say so][build-bots]. If the bots are green and ycmd doesn't compile on your machine, then _your machine is the root cause_. Now read the first paragraph again. Realize that quite literally _thousands_ of people have gotten ycmd to work successfully so if you can't, it's probably because you have a peculiar system/Vim configuration or you didn't go through the docs carefully enough. It's very unlikely to be caused by an actual bug in ycmd because someone would have already found it and reported it. This leads us to point #2: **make sure you have checked the docs before reporting an issue**. The docs are extensive and cover a ton of things; there's also an FAQ at the bottom that quite possibly addresses your problem. Further, **search the issue tracker for similar issues** before creating a new one. There's no point in duplication; if an existing issue addresses your problem, please comment there instead of creating a duplicate. You should also **search the archives of the [ycmd-users][] mailing list**. Lastly, **make sure you are running the latest version of ycmd**. The issue you have encountered may have already been fixed. **Don't forget to recompile ycm_core.so too** (usually by just running `install.py` again). OK, so we've reached this far. You need to create an issue. First realize that the time it takes to fix your issue is a multiple of how long it takes the developer to reproduce it. The easier it is to reproduce, the quicker it'll be fixed. Here are the things you should do when creating an issue: 1. **Write a step-by-step procedure that when performed repeatedly reproduces your issue.** If we can't reproduce the issue, then we can't fix it. It's that simple. 2. **Create a test case for your issue**. This is critical. Don't talk about how "when I have X in my file" or similar, _create a file with X in it_ and put the contents inside code blocks in your issue description. Try to make this test file _as small as possible_. Don't just paste a huge, 500 line source file you were editing and present that as a test. _Minimize_ the file so that the problem is reproduced with the smallest possible amount of test data. 3. **Include your OS and OS version.** Creating good pull requests =========================== 1. **Follow the code style of the existing codebase.** - The Python code **DOES NOT** follow PEP 8. This is not an oversight, this is by choice. You can dislike this as much as you want, but you still need to follow the existing style. Look at other Python files to see what the style is. - The C++ code has an automated formatter (`style_format.sh` that runs `astyle`) but it's not perfect. Again, look at the other C++ files and match the code style you see. 2. **Your code needs to be well written and easy to maintain**. This is of the _utmost_ importance. Other people will have to maintain your code so don't just throw stuff against the wall until things kinda work. 3. **Split your pull request into several smaller ones if possible.** This makes it easier to review your changes, which means they will be merged faster. 4. **Write tests for your code**. Your pull request is unlikely to be merged without tests. See [TESTS.md][ycmd-tests] for instructions on running the tests. 5. **Explain in detail why your pull request makes sense.** Ask yourself, would this feature be helpful to others? Not just a few people, but a lot of ycmd's users? See, good features are useful to many. If your feature is only useful to you and _maybe_ a couple of others, then that's not a good feature. There is such a thing as “feature overload”. When software accumulates so many features of which most are only useful to a handful, then that software has become “bloated”. We don't want that. Requests for features that are obscure or are helpful to but a few, or are not part of ycmd's "vision" will be rejected. Yes, even if you provide a patch that completely implements it. Please include details on exactly what you would like to see, and why. The why is important - it's not always clear why a feature is really useful. And sometimes what you want can be done in a different way if the reason for the change is known. _What goal is your change trying to accomplish?_ You should also use our [Vagrant config when working on ycmd][dev-setup]. There's _tons_ of gotchas when setting up the correct environment and they've all been worked out for you with Vagrant. Save yourself the trouble and use it. Writing code that runs on Python 2 & 3 ====================================== We support Python 2.6, 2.7 and 3.3+. Since we use [`python-future`][python-future], you should mostly write Python 3 as normal. Here's what you should watch out for: - New files should start with the following prologue after the copyright header: ```python from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa ``` - Write `dict(a=1, b=2)` instead of `{'a':1, 'b':2}`. `python-future` patches `dict()` to return a dictionary like the one from Python 3, but it can't patch dictionary literals. You could also create a dict with `d = dict()` and then use `d.update()` on it with a dict literal. - Read the [_What Else You Need to Know_][what-else] doc from `python-future`. - Create `bytes` objects from literals like so: `bytes( b'foo' )`. Note that `bytes` is patched by `python-future` on py2. - Be careful when passing the `bytes` type from `python-future` to python libraries (includes the standard library) on py2; while that type should in theory behave just like `str` on py2, some libraries might have issues. If you encounter any, pass the value through `future.utils`'s `native()` function which will convert `bytes` to a real `str` (again, only on py2). Heed this advice for your own sanity; behind it are 40 hours of debugging and an instance of tears-down-the-cheek crying at 2 am. - **Use the `ToBytes()` and `ToUnicode()` helper functions from `ycmd/utils.py`.** They work around weirdness, complexity and bugs in `python-future` and behave as you would expect. They're also extensively covered with tests. - Use `from future.utils import iteritems` then `for key, value in iteritems( dict_obj )` to efficiently iterate dicts on py2 & py3 - Use `from future.utils import itervalues` then `for value in itervalues( dict_obj )` to efficiently iterate over values in dicts on py2 & py3 - `future.utils` has `PY2` and `PY3` constants that are `True` in the respective interpreter; be careful about checking for py3 (better to check for py2); don't write code that will break on py4! - If you run tests and get failures on importing ycm_core that mention `initycm_core` or `PyInit_ycm_core`, you've built the C++ parts of ycmd for py2 and are trying to run tests in py3 (or vice-versa). Rebuild! [build-bots]: https://travis-ci.org/Valloric/ycmd [ycmd-users]: https://groups.google.com/forum/?hl=en#!forum/ycmd-users [ycmd-tests]: https://github.com/Valloric/ycmd/blob/master/TESTS.md [dev-setup]: https://github.com/Valloric/ycmd/blob/master/DEV_SETUP.md [python-future]: http://python-future.org/index.html [what-else]: http://python-future.org/what_else.html ycmd-0+20161219+git486b809.orig/cpp/0000755000175000017500000000000013026170316014744 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/CMakeLists.txt0000644000175000017500000001753713026170313017516 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # 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 . if ( APPLE ) # OSX requires CMake >= 2.8.12, see YCM issue #1439 cmake_minimum_required( VERSION 2.8.12 ) else() # CMake 2.8.11 is the latest available version on RHEL/CentOS 7 cmake_minimum_required( VERSION 2.8.11 ) endif() project( YouCompleteMe ) # Get the core version file( STRINGS "../CORE_VERSION" YCMD_CORE_VERSION ) add_definitions( -DYCMD_CORE_VERSION=${YCMD_CORE_VERSION} ) option( UNIVERSAL "Build universal mac binary" OFF ) if ( CMAKE_GENERATOR STREQUAL Xcode ) set( CMAKE_GENERATOR_IS_XCODE true ) endif() if ( ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" ) set( SYSTEM_IS_FREEBSD true ) endif() if ( ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD" ) set( SYSTEM_IS_OPENBSD true ) endif() if ( ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" ) set( SYSTEM_IS_SUNOS true ) endif() # Check if platform is 64 bit if( CMAKE_SIZEOF_VOID_P EQUAL 4 ) set( 64_BIT_PLATFORM 0 ) else() set( 64_BIT_PLATFORM 1 ) endif() ############################################################################# # Turning on this flag tells cmake to emit a compile_commands.json file. # This file can be used to load compilation flags into YCM. See here for more # details: http://clang.llvm.org/docs/JSONCompilationDatabase.html set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) ############################################################################# # This is needed so that on macs, the library is built in both 32 bit and 64 bit # versions. Without this python might refuse to load the module, depending on # how python was built. # On Mac, boost needs to be compiled universal as well, if used instead of the # included BoostParts lib. For brew, that's # "brew install boost --universal" # If the user chose to use the system libclang.dylib (or the libclang.dylib # binary downloaded from llvm.org) on a mac, then we don't specify universal # binary building since the system libclang on macs is not universal (and thus # linking would fail with universal). if ( UNIVERSAL AND NOT USE_SYSTEM_LIBCLANG ) set( CMAKE_OSX_ARCHITECTURES "i386;x86_64" ) endif() ############################################################################# # To shut up the warning about CMake policy CMP0042 set( CMAKE_MACOSX_RPATH ON ) ############################################################################# if ( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) set( COMPILER_IS_CLANG true ) # Linux machines don't necessarily have libc++ installed alongside clang, # but HAS_LIBCXX11 doesn't always trigger for machines that DO have libc++. We # know that at least all the Mac OS versions we support that use Clang have # libc++, so we're safe there. On FreeBSD 9 libc++ is an optional build # toggle. On FreeBSD 10 it is the default. if ( HAS_LIBCXX11 OR APPLE OR SYSTEM_IS_FREEBSD ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++" ) endif() # Ninja will by default prevent Clang from outputting diagnostics in color, so # we force color output if ( CMAKE_GENERATOR STREQUAL "Ninja" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics" ) endif() endif() ############################################################################# # Force release build by default, speed is of the essence if ( NOT CMAKE_BUILD_TYPE ) set( CMAKE_BUILD_TYPE Release ) endif() ############################################################################# # Determining the presence of C++11 support in the compiler set( CPP11_AVAILABLE false ) if ( CMAKE_COMPILER_IS_GNUCXX ) execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if ( GCC_VERSION VERSION_GREATER 4.6 OR GCC_VERSION VERSION_EQUAL 4.6 ) set( CPP11_AVAILABLE true ) endif() elseif( COMPILER_IS_CLANG ) set( CPP11_AVAILABLE true ) set( CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11" ) set( CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++" ) endif() ############################################################################# # For MSVC enable UNICODE and compilation on multiple processors if ( MSVC ) add_definitions( /DUNICODE /D_UNICODE /Zc:wchar_t- ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP" ) endif() # Solves the conflict in names of hypot in python sources and boost::python if ( MINGW ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include cmath") endif() # Due to a bug/misconfiguration/stupidity, boost 1.52 and libc++ don't like each # other much: a compilation error "Constexpr function never produces a constant # expression" pops up when trying to compile anything that uses # boost/chrono/duration.hpp (namely boost/thread for us). This is a workaround # that prevents this from happening. Also present in cpp/BoostParts/CMakeLists.txt. # See here for more details: https://svn.boost.org/trac/boost/ticket/7671 # TODO: remove this when it's fixed upstream (probably boost 1.53). add_definitions( -DBOOST_THREAD_DONT_USE_CHRONO ) if( MSVC OR CYGWIN ) # BOOST_ALL_NO_LIB turns off MSVC library autolinking add_definitions( -DBOOST_ALL_NO_LIB ) endif() if( WIN32 OR CYGWIN ) # BOOST_PYTHON_SOURCE makes boost use the correct __declspec add_definitions( -DBOOST_PYTHON_SOURCE -DBOOST_THREAD_USE_LIB ) if ( 64_BIT_PLATFORM ) # Enables python compilation for 64-bit Windows add_definitions( -DMS_WIN64 ) endif() endif() ############################################################################# # When used with Clang, adding the -std=c++0x flag to CMAKE_CXX_FLAGS will cause # the compiler to output a warning during linking: # clang: warning: argument unused during compilation: '-std=c++0x' # This is caused by cmake passing this flag to the linking stage which it # shouldn't do. It's ignored so it does no harm, but the warning is annoying. # # Putting the flag in add_definitions() works around the issue, even though it # shouldn't in theory go there. if ( CPP11_AVAILABLE ) message( "Your C++ compiler supports C++11, compiling in that mode." ) # Cygwin needs its hand held a bit; see issue #473 if ( CYGWIN AND CMAKE_COMPILER_IS_GNUCXX ) add_definitions( -std=gnu++0x ) else() add_definitions( -std=c++0x ) endif() else() message( "Your C++ compiler does NOT support C++11, compiling in C++03 mode." ) endif() ############################################################################# # Note: build.py always explicitly sets this option, so the default used here # rarely matters. option( USE_PYTHON2 "If on, link to Python 2 instead of 3" ON ) if ( USE_PYTHON2 ) set( Python_ADDITIONAL_VERSIONS 2.7 2.6 ) find_package( PythonLibs 2.6 REQUIRED ) # 2.6 is ONLY the mininum if ( NOT PYTHONLIBS_VERSION_STRING VERSION_LESS "3.0.0" ) message( FATAL_ERROR "You set USE_PYTHON2 to make CMake find python2 libs only, but CMake " "found python3 libs instead. Either don't set USE_PYTHON2 or install the " "necessary python2 headers & libraries." ) endif() else() set( Python_ADDITIONAL_VERSIONS 3.6 3.5 3.4 3.3 ) find_package( PythonLibs 3.3 REQUIRED ) # 3.3 is ONLY the mininum endif() ############################################################################# option( USE_SYSTEM_BOOST "Set to ON to use the system boost libraries" OFF ) if (NOT USE_SYSTEM_BOOST) add_subdirectory( BoostParts ) endif() add_subdirectory( ycm ) ycmd-0+20161219+git486b809.orig/cpp/ycm/0000755000175000017500000000000013026170313015531 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/ycm/LetterNode.h0000644000175000017500000000336713026170313017760 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef LETTERNODE_H_EIZ6JVWC #define LETTERNODE_H_EIZ6JVWC #include "DLLDefines.h" #include "LetterNodeListMap.h" #include #include #include #include #include #include namespace YouCompleteMe { class LetterNode { public: LetterNode( char letter, int index ); YCM_DLL_EXPORT explicit LetterNode( const std::string &text ); inline bool LetterIsUppercase() const { return is_uppercase_; } inline const NearestLetterNodeIndices *NearestLetterNodesForLetter( char letter ) { return letters_.ListPointerAt( letter ); } void SetNodeIndexForLetterIfNearest( char letter, short index ); inline int Index() const { return index_; } inline LetterNode *operator[]( int index ) { return &letternode_per_text_index_[ index ]; } private: LetterNodeListMap letters_; std::vector letternode_per_text_index_; int index_; bool is_uppercase_; }; } // namespace YouCompleteMe #endif /* end of include guard: LETTERNODE_H_EIZ6JVWC */ ycmd-0+20161219+git486b809.orig/cpp/ycm/CMakeLists.txt0000644000175000017500000004645313026170313020305 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # 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 . cmake_minimum_required( VERSION 2.8.7 ) project( ycm_core ) option( USE_DEV_FLAGS "Use compilation flags meant for YCM developers" OFF ) option( USE_CLANG_COMPLETER "Use Clang semantic completer for C/C++/ObjC" OFF ) option( USE_SYSTEM_LIBCLANG "Set to ON to use the system libclang library" OFF ) set( PATH_TO_LLVM_ROOT "" CACHE PATH "Path to the root of a LLVM+Clang binary distribution" ) set( EXTERNAL_LIBCLANG_PATH "" CACHE PATH "Path to the libclang library to use" ) if ( USE_CLANG_COMPLETER AND NOT USE_SYSTEM_LIBCLANG AND NOT PATH_TO_LLVM_ROOT AND NOT EXTERNAL_LIBCLANG_PATH ) set( CLANG_VERSION "3.9.0" ) if ( APPLE ) set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-x86_64-apple-darwin" ) set( CLANG_SHA256 "bd689aaeafa19832016d5a4917405a73b21bc5281846c0cb816e9545cf99e82b" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) elseif ( WIN32 ) if( 64_BIT_PLATFORM ) set( CLANG_DIRNAME "LLVM-${CLANG_VERSION}-win64" ) set( CLANG_SHA256 "3e5b53a79266d3f7f1d5cb4d94283fe2bc61f9689e55f39e3939364f4076b0c9" ) else() set( CLANG_DIRNAME "LLVM-${CLANG_VERSION}-win32" ) set( CLANG_SHA256 "b4eaa1fa9872e2c76268f32fc597148cfa14c57b7d13e1edd9b9b6496cdf7de8" ) endif() set( CLANG_FILENAME "${CLANG_DIRNAME}.exe" ) elseif ( ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" ) if ( 64_BIT_PLATFORM ) set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-amd64-unknown-freebsd10" ) set( CLANG_SHA256 "df35eaeabec7a474b3c3737c798a0c817795ebbd12952c665c52b2f98abcb6de" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) else() set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-i386-unknown-freebsd10" ) set( CLANG_SHA256 "16c612019ece5ba1f846740e77c7c1a39b813acb5bcfbfe9f8af32d7c28caa60" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) endif() else() # Among the prebuilt binaries available upstream, only the Ubuntu 14.04 # and openSUSE 13.2 ones are working on Ubuntu 14.04 (and 12.04 which is # required for Travis builds). We choose openSUSE over Ubuntu 14.04 because # it does not have the terminfo library (libtinfo) dependency, which is not # needed for our use case and a source of problems on some distributions # (see YCM issues #778 and #2259), and is available for 32-bit and 64-bit # architectures. if ( 64_BIT_PLATFORM ) set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-x86_64-opensuse13.2" ) set( CLANG_SHA256 "9153b473dc37d2e21a260231e90e43b97aba1dff5d27f14c947815a90fbdc8d7" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) else() set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-i586-opensuse13.2" ) set( CLANG_SHA256 "92309be874810fb5ca3f9037bb400783be89fa6bc96ed141b04297f59e389692" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) endif() endif() # Check if the Clang archive is already downloaded and its checksum is correct. # If this is not the case, remove it if needed and download it. set( CLANG_DOWNLOAD ON ) set( CLANG_LOCAL_FILE "${CMAKE_SOURCE_DIR}/../clang_archives/${CLANG_FILENAME}" ) if( EXISTS "${CLANG_LOCAL_FILE}" ) file( SHA256 "${CLANG_LOCAL_FILE}" CLANG_LOCAL_SHA256 ) if( "${CLANG_LOCAL_SHA256}" STREQUAL "${CLANG_SHA256}" ) set( CLANG_DOWNLOAD OFF ) else() file( REMOVE "${CLANG_LOCAL_FILE}" ) endif() endif() if( CLANG_DOWNLOAD ) message( "Downloading Clang ${CLANG_VERSION}" ) set( CLANG_URL "http://llvm.org/releases/${CLANG_VERSION}" ) file( DOWNLOAD "${CLANG_URL}/${CLANG_FILENAME}" "${CLANG_LOCAL_FILE}" SHOW_PROGRESS EXPECTED_HASH SHA256=${CLANG_SHA256} ) else() message( "Using Clang archive: ${CLANG_LOCAL_FILE}" ) endif() # Copy and extract the Clang archive in the building directory. file( COPY "${CLANG_LOCAL_FILE}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/../" ) if ( CLANG_FILENAME MATCHES ".+bz2" ) execute_process( COMMAND tar -xjf ${CLANG_FILENAME} ) elseif( CLANG_FILENAME MATCHES ".+xz" ) execute_process( COMMAND tar -xJf ${CLANG_FILENAME} ) elseif( CLANG_FILENAME MATCHES ".+exe" ) # Find 7-zip executable in the PATH and using the registry find_program( 7Z_EXECUTABLE 7z PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\7-Zip;Path] ) if ( NOT 7Z_EXECUTABLE ) message( FATAL_ERROR "7-zip is needed to extract the files from the Clang installer. " "Install it and try again." ) endif() execute_process( COMMAND ${7Z_EXECUTABLE} x ${CLANG_FILENAME} OUTPUT_QUIET ) else() execute_process( COMMAND tar -xzf ${CLANG_FILENAME} ) endif() # We need to set PATH_TO_LLVM_ROOT. To do that, we first have to find the # folder name the archive produced. It isn't the archive base name. # On Windows, the find command is not available so we directly set the path. if ( WIN32 ) # Since 7-zip release version 15.12, files are not anymore extracted in # $_OUTDIR folder but directly to the root. So, we check the existence of # $_OUTDIR to appropriately set PATH_TO_LLVM_ROOT. if ( EXISTS ${CMAKE_CURRENT_BINARY_DIR}/../$_OUTDIR ) set( PATH_TO_LLVM_ROOT ${CMAKE_CURRENT_BINARY_DIR}/../$_OUTDIR ) else() set( PATH_TO_LLVM_ROOT ${CMAKE_CURRENT_BINARY_DIR}/.. ) endif() else() execute_process( COMMAND find ${CMAKE_CURRENT_BINARY_DIR}/.. -maxdepth 1 -type d -name clang* OUTPUT_VARIABLE PATH_TO_LLVM_ROOT OUTPUT_STRIP_TRAILING_WHITESPACE ) endif() endif() if ( PATH_TO_LLVM_ROOT OR USE_SYSTEM_LIBCLANG OR EXTERNAL_LIBCLANG_PATH ) set( USE_CLANG_COMPLETER TRUE ) endif() if ( USE_CLANG_COMPLETER AND NOT PATH_TO_LLVM_ROOT AND NOT USE_SYSTEM_LIBCLANG AND NOT EXTERNAL_LIBCLANG_PATH ) message( FATAL_ERROR "You have not specified which libclang to use. You have several options:\n" " 1. Set PATH_TO_LLVM_ROOT to a path to the root of a LLVM+Clang binary " "distribution. You can download such a binary distro from llvm.org. This " "is the recommended approach.\n" " 2. Set USE_SYSTEM_LIBCLANG to ON; this makes YCM search for the system " "version of libclang.\n" " 3. Set EXTERNAL_LIBCLANG_PATH to a path to whatever " "libclang.[so|dylib|dll] you wish to use.\n" "You HAVE to pick one option. See the docs for more information.") endif() if ( USE_CLANG_COMPLETER ) message( "Using libclang to provide semantic completion for C/C++/ObjC" ) else() message( "NOT using libclang, no semantic completion for C/C++/ObjC will be " "available" ) endif() if ( PATH_TO_LLVM_ROOT ) set( CLANG_INCLUDES_DIR "${PATH_TO_LLVM_ROOT}/include" ) else() set( CLANG_INCLUDES_DIR "${CMAKE_SOURCE_DIR}/llvm/include" ) endif() if ( NOT IS_ABSOLUTE "${CLANG_INCLUDES_DIR}" ) get_filename_component(CLANG_INCLUDES_DIR "${CMAKE_BINARY_DIR}/${CLANG_INCLUDES_DIR}" ABSOLUTE) endif() if ( NOT EXTERNAL_LIBCLANG_PATH AND PATH_TO_LLVM_ROOT ) if ( MINGW ) set( LIBCLANG_SEARCH_PATH "${PATH_TO_LLVM_ROOT}/bin" ) else() set( LIBCLANG_SEARCH_PATH "${PATH_TO_LLVM_ROOT}/lib" ) endif() # Need TEMP because find_library does not work with an option variable find_library( TEMP NAMES clang libclang PATHS ${LIBCLANG_SEARCH_PATH} NO_DEFAULT_PATH ) set( EXTERNAL_LIBCLANG_PATH ${TEMP} ) endif() # This is a workaround for a CMake bug with include_directories(SYSTEM ...) # on Mac OS X. Bug report: http://public.kitware.com/Bug/view.php?id=10837 if ( APPLE ) set( CMAKE_INCLUDE_SYSTEM_FLAG_CXX "-isystem " ) endif() if ( USE_SYSTEM_BOOST ) set( Boost_COMPONENTS filesystem system regex thread ) if( USE_PYTHON2 ) list( APPEND Boost_COMPONENTS python ) else() list( APPEND Boost_COMPONENTS python3 ) endif() find_package( Boost REQUIRED COMPONENTS ${Boost_COMPONENTS} ) else() set( Boost_INCLUDE_DIR ${BoostParts_SOURCE_DIR} ) set( Boost_LIBRARIES BoostParts ) endif() file( GLOB_RECURSE SERVER_SOURCES *.h *.cpp ) # The test sources are a part of a different target, so we remove them # The CMakeFiles cpp file is picked up when the user creates an in-source build, # and we don't want that. We also remove client-specific code file( GLOB_RECURSE to_remove tests/*.h tests/*.cpp CMakeFiles/*.cpp *client* ) if( to_remove ) list( REMOVE_ITEM SERVER_SOURCES ${to_remove} ) endif() if ( USE_CLANG_COMPLETER ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/ClangCompleter" ) add_definitions( -DUSE_CLANG_COMPLETER ) else() file( GLOB_RECURSE to_remove_clang ClangCompleter/*.h ClangCompleter/*.cpp ) if( to_remove_clang ) list( REMOVE_ITEM SERVER_SOURCES ${to_remove_clang} ) endif() endif() # The SYSTEM flag makes sure that -isystem[header path] is passed to the # compiler instead of the standard -I[header path]. Headers included with # -isystem do not generate warnings (and they shouldn't; e.g. boost warnings are # just noise for us since we won't be changing them). # Since there is no -isystem flag equivalent on Windows, headers from external # projects may conflict with our headers and override them. We prevent that by # including these directories after ours. include_directories( SYSTEM ${Boost_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS} ${CLANG_INCLUDES_DIR} ) ############################################################################# # One can use the system libclang.[so|dylib] like so: # cmake -DUSE_SYSTEM_LIBCLANG=1 [...] # One can also explicitely pick the external libclang.[so|dylib] for use like so: # cmake -DEXTERNAL_LIBCLANG_PATH=/path/to/libclang.so [...] # The final .so we build will then first look in the same dir in which it is # located for libclang.so. This is provided by the rpath = $ORIGIN feature. if ( EXTERNAL_LIBCLANG_PATH OR USE_SYSTEM_LIBCLANG ) if ( USE_SYSTEM_LIBCLANG ) if ( APPLE ) set( ENV_LIB_PATHS ENV DYLD_LIBRARY_PATH ) elseif ( UNIX ) set( ENV_LIB_PATHS ENV LD_LIBRARY_PATH ) elseif ( WIN32 ) set( ENV_LIB_PATHS ENV PATH ) else () set( ENV_LIB_PATHS "" ) endif() # On Debian-based systems, llvm installs into /usr/lib/llvm-x.y. file( GLOB SYS_LLVM_PATHS "/usr/lib/llvm*/lib" ) # Need TEMP because find_library does not work with an option variable # On Debian-based systems only a symlink to libclang.so.1 is created find_library( TEMP NAMES clang libclang.so.1 PATHS ${ENV_LIB_PATHS} /usr/lib /usr/lib/llvm ${SYS_LLVM_PATHS} /Library/Developer/CommandLineTools/usr/lib /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib ) set( EXTERNAL_LIBCLANG_PATH ${TEMP} ) else() # For Macs, we do things differently; look further in this file. if ( NOT APPLE ) # Setting this to true makes sure that libraries we build will have our # rpath set even without having to do "make install" set( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE ) set( CMAKE_INSTALL_RPATH "\$ORIGIN" ) # Add directories from all libraries outside the build tree to the rpath. # This makes the dynamic linker able to find non system libraries that # our libraries require, in particular the Python one (from pyenv for # instance). set( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE ) endif() endif() # In Clang 3.7, the library target is a symlink of the soversion one. # Since it will be copied in the project folder, we need the symlinked # library. get_filename_component( LIBCLANG_TARGET "${EXTERNAL_LIBCLANG_PATH}" REALPATH ) message( "Using external libclang: ${LIBCLANG_TARGET}" ) else() set( LIBCLANG_TARGET ) endif() if ( EXTRA_RPATH ) set( CMAKE_INSTALL_RPATH "${EXTRA_RPATH}:${CMAKE_INSTALL_RPATH}" ) endif() # Needed on Linux machines, but not on Macs and OpenBSD if ( UNIX AND NOT ( APPLE OR SYSTEM_IS_OPENBSD ) ) set( EXTRA_LIBS rt ) endif() ############################################################################# add_library( ${PROJECT_NAME} SHARED ${SERVER_SOURCES} ) if ( USE_CLANG_COMPLETER AND NOT LIBCLANG_TARGET ) message( FATAL_ERROR "Using Clang completer, but no libclang found. " "Try setting EXTERNAL_LIBCLANG_PATH or revise " "your configuration" ) endif() target_link_libraries( ${PROJECT_NAME} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${LIBCLANG_TARGET} ${EXTRA_LIBS} ) if( LIBCLANG_TARGET ) # When building with MSVC, we need to copy libclang.dll instead of libclang.lib if( MSVC ) add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${PATH_TO_LLVM_ROOT}/bin/libclang.dll" "$" ) else() add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${LIBCLANG_TARGET}" "$" ) if( APPLE ) # In OS X El Capitan, Apple introduced System Integrity Protection. # Amongst other things, this introduces features to the dynamic loader # (dyld) which cause it to "sanitise" (and complain about) embedded # LC_RPATH entries which contain @executable_path when then are loaded # into "restricted" binaries. For our purposes, "restricted" here means # "supplied by Apple" and includes the system versions of python. For # unknown reasons, the libclang.dylib that comes from llvm.org includes an # LC_RPATH entry '@executable_path/../lib' which causes the OS X dynamic # loader to print a cryptic warning to stderr of the form: # # dyld: warning, LC_RPATH @executable_path/../lib in # /path/to/ycmd/libclang.dylib being ignored in restricted program # because of @executable_path # # In order to prevent this harmless and annoying message appearing, we # simply strip the rpath entry from the dylib. There's no way any # @executable_path that python might have could be in any way useful to # libclang.dylib, so this seems perfectly safe. get_filename_component( LIBCLANG_TAIL ${LIBCLANG_TARGET} NAME ) add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND install_name_tool "-delete_rpath" "@executable_path/../lib" "$/${LIBCLANG_TAIL}" ) endif() endif() endif() ############################################################################# # Things are a bit different on Macs when using an external libclang.dylib; here # we want to make sure we use @loader_path/libclang.dylib instead of # @rpath/libclang.dylib in the final ycm_core.so. If we use the # @rpath version, then it may load the system libclang which the user # explicitely does not want (otherwise the user would specify # USE_SYSTEM_LIBCLANG). If we hardcode with `@loader_path/libclang.dylib`, # it guarantees to search `@loader_path` for libclang.dylib first and use it # only. So with `@loader_path`, we make sure that only the libclang.dylib # present in the same directory as our ycm_core.so is used. # And the extra `rpath` is helpful to find libclang.dylib's dependencies # if it is built with `--enable-shared` flag. if ( EXTERNAL_LIBCLANG_PATH AND APPLE ) get_filename_component(EXTRA_LIB_PATH ${EXTERNAL_LIBCLANG_PATH} DIRECTORY) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,${EXTRA_LIB_PATH}") add_custom_command( TARGET ${PROJECT_NAME} POST_BUILD COMMAND install_name_tool "-change" "@rpath/libclang.dylib" "@loader_path/libclang.dylib" "$" ) endif() ############################################################################# # We don't want the "lib" prefix, it can screw up python when it tries to search # for our module set_target_properties( ${PROJECT_NAME} PROPERTIES PREFIX "") if ( WIN32 OR CYGWIN ) # DLL platforms put dlls in the RUNTIME_OUTPUT_DIRECTORY # First for the generic no-config case (e.g. with mingw) set_target_properties( ${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../.. ) # Second, for multi-config builds (e.g. msvc) foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) set_target_properties( ${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_SOURCE_DIR}/../.. ) endforeach() if ( WIN32 ) # This is the extension for compiled Python modules on Windows set_target_properties( ${PROJECT_NAME} PROPERTIES SUFFIX ".pyd") elseif ( CYGWIN ) # This is the extension for compiled Python modules in Cygwin set_target_properties( ${PROJECT_NAME} PROPERTIES SUFFIX ".dll") endif() else() # Even on macs, we want a .so extension instead of a .dylib which is what # cmake would give us by default. Python won't recognize a .dylib as a module, # but it will recognize a .so set_target_properties( ${PROJECT_NAME} PROPERTIES SUFFIX ".so") endif() set_target_properties( ${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../.. ) ############################################################################# # For some reason, Xcode is too dumb to understand the -isystem flag and thus # borks on warnings in Boost. if ( USE_DEV_FLAGS AND ( CMAKE_COMPILER_IS_GNUCXX OR COMPILER_IS_CLANG ) AND NOT CMAKE_GENERATOR_IS_XCODE ) # We want all warnings, and warnings should be treated as errors set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror" ) endif() ############################################################################# # We want warnings if we accidentally use C++11 features # We can't use this warning on FreeBSD because std headers on that OS are dumb. # See here: https://github.com/Valloric/YouCompleteMe/issues/260 if ( USE_DEV_FLAGS AND COMPILER_IS_CLANG AND NOT CMAKE_GENERATOR_IS_XCODE AND NOT SYSTEM_IS_FREEBSD ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wc++98-compat" ) endif() ############################################################################# if( SYSTEM_IS_SUNOS ) # SunOS needs this setting for thread support set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads" ) endif() if( SYSTEM_IS_OPENBSD OR SYSTEM_IS_FREEBSD ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" ) endif() add_subdirectory( tests ) ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/0000755000175000017500000000000013026170313020430 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/ClangUtils.cpp0000644000175000017500000000307513026170313023206 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "ClangUtils.h" #include "standard.h" namespace YouCompleteMe { std::string CXStringToString( CXString text ) { std::string final_string; if ( !text.data ) return final_string; final_string = std::string( clang_getCString( text ) ); clang_disposeString( text ); return final_string; } bool CursorIsValid( CXCursor cursor ) { return !clang_Cursor_isNull( cursor ) && !clang_isInvalid( clang_getCursorKind( cursor ) ); } bool CursorIsReference( CXCursor cursor ) { return clang_isReference( clang_getCursorKind( cursor ) ); } bool CursorIsDeclaration( CXCursor cursor ) { return clang_isDeclaration( clang_getCursorKind( cursor ) ); } std::string CXFileToFilepath( CXFile file ) { return CXStringToString( clang_getFileName( file ) ); } std::string ClangVersion() { return CXStringToString( clang_getClangVersion() ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/Diagnostic.h0000644000175000017500000000556313026170313022676 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef DIAGNOSTIC_H_BZH3BWIZ #define DIAGNOSTIC_H_BZH3BWIZ #include "standard.h" #include "Range.h" #include "Location.h" #include #include namespace YouCompleteMe { enum DiagnosticKind { INFORMATION = 0, ERROR, WARNING }; /// Information about a replacement that can be made to the source to "fix" a /// diagnostic. struct FixItChunk { /// The replacement string. This string should replace the source range /// represented by 'range'. std::string replacement_text; /// The range within the file to replace with replacement_text. Range range; bool operator == ( const FixItChunk &other ) const { return replacement_text == other.replacement_text && range == other.range; } }; /// Collection of FixItChunks which, when applied together, fix a particular /// diagnostic. This structure forms the reply to the "FixIt" subcommand, and /// represents a lightweight view of a diagnostic. The location is included to /// aid clients in applying the most appropriate FixIt based on context. struct FixIt { std::vector< FixItChunk > chunks; Location location; /// This is the text of the diagnostic. This is useful when there are /// multiple diagnostics offering different fixit options. The text is /// displayed to the user, allowing them choose which diagnostic to apply. std::string text; bool operator==( const FixIt &other ) const { return chunks == other.chunks && location == other.location; } }; struct Diagnostic { bool operator== ( const Diagnostic &other ) const { return location_ == other.location_ && kind_ == other.kind_ && text_ == other.text_; } Location location_; Range location_extent_; std::vector< Range > ranges_; DiagnosticKind kind_; std::string text_; std::string long_formatted_text_; /// The (cached) changes required to fix this diagnostic. /// Note: when there are child diagnostics, there may be multiple possible /// FixIts for the main reported diagnostic. These are typically notes, /// offering alternative ways to fix the error. std::vector< FixIt > fixits_; }; } // namespace YouCompleteMe #endif /* end of include guard: DIAGNOSTIC_H_BZH3BWIZ */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/TranslationUnitStore.cpp0000644000175000017500000001037113026170313025311 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "TranslationUnitStore.h" #include "TranslationUnit.h" #include "Utils.h" #include "exceptions.h" #include #include #include using boost::lock_guard; using boost::shared_ptr; using boost::make_shared; using boost::mutex; namespace YouCompleteMe { namespace { std::size_t HashForFlags( const std::vector< std::string > &flags ) { return boost::hash< std::vector< std::string > >()( flags ); } } // unnamed namespace TranslationUnitStore::TranslationUnitStore( CXIndex clang_index ) : clang_index_( clang_index ) { } TranslationUnitStore::~TranslationUnitStore() { RemoveAll(); } shared_ptr< TranslationUnit > TranslationUnitStore::GetOrCreate( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ) { bool dont_care; return GetOrCreate( filename, unsaved_files, flags, dont_care ); } shared_ptr< TranslationUnit > TranslationUnitStore::GetOrCreate( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool &translation_unit_created ) { translation_unit_created = false; { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); shared_ptr< TranslationUnit > current_unit = GetNoLock( filename ); if ( current_unit && HashForFlags( flags ) == filename_to_flags_hash_[ filename ] ) { return current_unit; } // We create and store an invalid, sentinel TU so that other threads don't // try to create a TU for the same file while we are trying to create this // TU object. When we are done creating the TU, we will overwrite this value // with the valid object. filename_to_translation_unit_[ filename ] = make_shared< TranslationUnit >(); // We need to store the flags for the sentinel TU so that other threads end // up returning the sentinel TU while the real one is being created. filename_to_flags_hash_[ filename ] = HashForFlags( flags ); } boost::shared_ptr< TranslationUnit > unit; try { unit = boost::make_shared< TranslationUnit >( filename, unsaved_files, flags, clang_index_ ); } catch ( ClangParseError & ) { Remove( filename ); return unit; } { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); filename_to_translation_unit_[ filename ] = unit; // Flags have already been stored. } translation_unit_created = true; return unit; } shared_ptr< TranslationUnit > TranslationUnitStore::Get( const std::string &filename ) { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); return GetNoLock( filename ); } bool TranslationUnitStore::Remove( const std::string &filename ) { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); Erase( filename_to_flags_hash_, filename ); return Erase( filename_to_translation_unit_, filename ); } void TranslationUnitStore::RemoveAll() { lock_guard< mutex > lock( filename_to_translation_unit_and_flags_mutex_ ); filename_to_translation_unit_.clear(); filename_to_flags_hash_.clear(); } shared_ptr< TranslationUnit > TranslationUnitStore::GetNoLock( const std::string &filename ) { return FindWithDefault( filename_to_translation_unit_, filename, shared_ptr< TranslationUnit >() ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/Documentation.h0000644000175000017500000000352713026170313023421 0ustar onuronur// Copyright (C) 2015 ycmd contributors // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef DOCUMENTATION_H_POYSHVX8 #define DOCUMENTATION_H_POYSHVX8 #include #include namespace YouCompleteMe { /// This class holds information useful for generating a documentation response /// for a given cursor struct DocumentationData { /// Construct an empty object DocumentationData() {} /// Construct and extract information from the supplied cursor. The cursor /// should be pointing to a canonical declaration, such as returned by /// clang_getCanonicalCursor( clang_getCursorReferenced( cursor ) ) DocumentationData( const CXCursor &cursor ); /// XML data as parsed by libclang. This provides full semantic parsing of /// doxygen-syntax comments. std::string comment_xml; /// The raw text of the comment preceding the declaration std::string raw_comment; /// The brief comment (either first paragraph or \brief) as parsed by libclang std::string brief_comment; /// The canonical type of the referenced cursor std::string canonical_type; /// The display name of the referenced cursor std::string display_name; }; } // namespace YouCompleteMe #endif /* end of include guard: DOCUMENTATION_H_POYSHVX8 */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/CompilationDatabase.h0000644000175000017500000000411513026170313024505 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef COMPILATIONDATABASE_H_ZT7MQXPG #define COMPILATIONDATABASE_H_ZT7MQXPG #include #include #include #include #include #include #include namespace YouCompleteMe { struct CompilationInfoForFile { std::vector< std::string > compiler_flags_; std::string compiler_working_dir_; }; // Access to Clang's internal CompilationDatabase. This class is thread-safe. class CompilationDatabase : boost::noncopyable { public: // |path_to_directory| should be a string-like object. CompilationDatabase( const boost::python::object &path_to_directory ); ~CompilationDatabase(); bool DatabaseSuccessfullyLoaded(); // Returns true when a separate thread is already getting flags; this is // useful so that the caller doesn't need to block. bool AlreadyGettingFlags(); // NOTE: Multiple calls to this function from separate threads will be // serialized since Clang internals are not thread-safe. // |path_to_file| should be a string-like object. CompilationInfoForFile GetCompilationInfoForFile( const boost::python::object &path_to_file ); private: bool is_loaded_; CXCompilationDatabase compilation_database_; boost::mutex compilation_database_mutex_; }; } // namespace YouCompleteMe #endif /* end of include guard: COMPILATIONDATABASE_H_ZT7MQXPG */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/CompilationDatabase.cpp0000644000175000017500000000641513026170313025045 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "CompilationDatabase.h" #include "ClangUtils.h" #include "standard.h" #include "ReleaseGil.h" #include "PythonSupport.h" #include #include #include #include using boost::lock_guard; using boost::unique_lock; using boost::try_to_lock_t; using boost::remove_pointer; using boost::shared_ptr; using boost::mutex; namespace YouCompleteMe { typedef shared_ptr < remove_pointer< CXCompileCommands >::type > CompileCommandsWrap; CompilationDatabase::CompilationDatabase( const boost::python::object &path_to_directory ) : is_loaded_( false ) { CXCompilationDatabase_Error status; std::string path_to_directory_string = GetUtf8String( path_to_directory ); compilation_database_ = clang_CompilationDatabase_fromDirectory( path_to_directory_string.c_str(), &status ); is_loaded_ = status == CXCompilationDatabase_NoError; } CompilationDatabase::~CompilationDatabase() { clang_CompilationDatabase_dispose( compilation_database_ ); } bool CompilationDatabase::DatabaseSuccessfullyLoaded() { return is_loaded_; } bool CompilationDatabase::AlreadyGettingFlags() { unique_lock< mutex > lock( compilation_database_mutex_, try_to_lock_t() ); return !lock.owns_lock(); } CompilationInfoForFile CompilationDatabase::GetCompilationInfoForFile( const boost::python::object &path_to_file ) { CompilationInfoForFile info; if ( !is_loaded_ ) return info; std::string path_to_file_string = GetUtf8String( path_to_file ); ReleaseGil unlock; lock_guard< mutex > lock( compilation_database_mutex_ ); CompileCommandsWrap commands( clang_CompilationDatabase_getCompileCommands( compilation_database_, path_to_file_string.c_str() ), clang_CompileCommands_dispose ); uint num_commands = clang_CompileCommands_getSize( commands.get() ); if ( num_commands < 1 ) { return info; } // We always pick the first command offered CXCompileCommand command = clang_CompileCommands_getCommand( commands.get(), 0 ); info.compiler_working_dir_ = CXStringToString( clang_CompileCommand_getDirectory( command ) ); uint num_flags = clang_CompileCommand_getNumArgs( command ); info.compiler_flags_.reserve( num_flags ); for ( uint i = 0; i < num_flags; ++i ) { info.compiler_flags_.push_back( CXStringToString( clang_CompileCommand_getArg( command, i ) ) ); } return info; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/ClangHelpers.h0000644000175000017500000000310413026170313023146 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef CLANGHELPERS_H_T3ME71LG #define CLANGHELPERS_H_T3ME71LG #include "Diagnostic.h" #include "CompletionData.h" #include "UnsavedFile.h" #include #include #include #include namespace YouCompleteMe { typedef boost::shared_ptr < boost::remove_pointer< CXDiagnostic >::type > DiagnosticWrap; std::vector< CompletionData > ToCompletionDataVector( CXCodeCompleteResults *results ); // NOTE: CXUnsavedFiles store pointers to data in UnsavedFiles, so UnsavedFiles // need to outlive CXUnsavedFiles! std::vector< CXUnsavedFile > ToCXUnsavedFiles( const std::vector< UnsavedFile > &unsaved_files ); Diagnostic BuildDiagnostic( DiagnosticWrap diagnostic_wrap, CXTranslationUnit translation_unit ); } // namespace YouCompleteMe #endif /* end of include guard: CLANGHELPERS_H_T3ME71LG */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/ClangCompleter.cpp0000644000175000017500000001663113026170313024042 0ustar onuronur// Copyright (C) 2011-2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "ClangCompleter.h" #include "exceptions.h" #include "Result.h" #include "Candidate.h" #include "TranslationUnit.h" #include "standard.h" #include "CandidateRepository.h" #include "CompletionData.h" #include "Utils.h" #include "ClangUtils.h" #include "ReleaseGil.h" #include #include using boost::shared_ptr; using boost::unordered_map; namespace YouCompleteMe { ClangCompleter::ClangCompleter() : clang_index_( clang_createIndex( 0, 0 ) ), translation_unit_store_( clang_index_ ) { // The libclang docs don't say what is the default value for crash recovery. // I'm pretty sure it's turned on by default, but I'm not going to take any // chances. clang_toggleCrashRecovery( true ); } ClangCompleter::~ClangCompleter() { // We need to destroy all TUs before calling clang_disposeIndex because // the translation units need to be destroyed before the index is destroyed. // Technically, a thread could still be holding onto a shared_ptr object // when we destroy the clang index, but since we're shutting down, we don't // really care. // In practice, this situation shouldn't happen because the server threads are // Python deamon threads and will all be killed before the main thread exits. translation_unit_store_.RemoveAll(); clang_disposeIndex( clang_index_ ); } bool ClangCompleter::UpdatingTranslationUnit( const std::string &filename ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.Get( filename ); if ( !unit ) return false; // Thankfully, an invalid, sentinel TU always returns true for // IsCurrentlyUpdating, so no caller will try to rely on the TU object, even // if unit is currently pointing to a sentinel. return unit->IsCurrentlyUpdating(); } std::vector< Diagnostic > ClangCompleter::UpdateTranslationUnit( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ) { ReleaseGil unlock; bool translation_unit_created; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags, translation_unit_created ); if ( !unit ) return std::vector< Diagnostic >(); try { return unit->Reparse( unsaved_files ); } catch ( ClangParseError & ) { // If unit->Reparse fails, then the underlying TranslationUnit object is not // valid anymore and needs to be destroyed and removed from the filename -> // TU map. translation_unit_store_.Remove( filename ); } return std::vector< Diagnostic >(); } std::vector< CompletionData > ClangCompleter::CandidatesForLocationInFile( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) return std::vector< CompletionData >(); return unit->CandidatesForLocation( line, column, unsaved_files ); } Location ClangCompleter::GetDeclarationLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) { return Location(); } return unit->GetDeclarationLocation( line, column, unsaved_files, reparse ); } Location ClangCompleter::GetDefinitionLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) { return Location(); } return unit->GetDefinitionLocation( line, column, unsaved_files, reparse ); } std::string ClangCompleter::GetTypeAtLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) { return "no unit"; } return unit->GetTypeAtLocation( line, column, unsaved_files, reparse ); } std::string ClangCompleter::GetEnclosingFunctionAtLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) { return "no unit"; } return unit->GetEnclosingFunctionAtLocation( line, column, unsaved_files, reparse ); } std::vector< FixIt > ClangCompleter::GetFixItsForLocationInFile( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) { return std::vector< FixIt >(); } return unit->GetFixItsForLocationInFile( line, column, unsaved_files, reparse ); } DocumentationData ClangCompleter::GetDocsForLocationInFile( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse ) { ReleaseGil unlock; shared_ptr< TranslationUnit > unit = translation_unit_store_.GetOrCreate( filename, unsaved_files, flags ); if ( !unit ) { return DocumentationData(); } return unit->GetDocsForLocationInFile( line, column, unsaved_files, reparse ); } void ClangCompleter::DeleteCachesForFile( const std::string &filename ) { ReleaseGil unlock; translation_unit_store_.Remove( filename ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/Location.h0000644000175000017500000000367313026170313022362 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef LOCATION_H_6TLFQH4I #define LOCATION_H_6TLFQH4I #include "standard.h" #include "ClangUtils.h" #include #include namespace YouCompleteMe { struct Location { // Creates an invalid location Location() : line_number_( 0 ), column_number_( 0 ), filename_( "" ) {} Location( const std::string &filename, uint line, uint column ) : line_number_( line ), column_number_( column ), filename_( filename ) {} Location( const CXSourceLocation &location ) { CXFile file; uint unused_offset; clang_getExpansionLocation( location, &file, &line_number_, &column_number_, &unused_offset ); filename_ = CXFileToFilepath( file ); } bool operator== ( const Location &other ) const { return line_number_ == other.line_number_ && column_number_ == other.column_number_ && filename_ == other.filename_; } bool IsValid() { return !filename_.empty(); } uint line_number_; uint column_number_; // The full, absolute path std::string filename_; }; } // namespace YouCompleteMe #endif /* end of include guard: LOCATION_H_6TLFQH4I */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/TranslationUnit.cpp0000644000175000017500000003563313026170313024304 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "TranslationUnit.h" #include "CompletionData.h" #include "standard.h" #include "exceptions.h" #include "ClangUtils.h" #include "ClangHelpers.h" #include #include using boost::unique_lock; using boost::mutex; using boost::try_to_lock_t; using boost::shared_ptr; using boost::remove_pointer; namespace YouCompleteMe { namespace { unsigned EditingOptions() { // See cpp/llvm/include/clang-c/Index.h file for detail on these options. return CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_Incomplete | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion | CXTranslationUnit_CreatePreambleOnFirstParse | CXTranslationUnit_KeepGoing | clang_defaultEditingTranslationUnitOptions(); } unsigned ReparseOptions( CXTranslationUnit translationUnit ) { return clang_defaultReparseOptions( translationUnit ); } unsigned CompletionOptions() { return clang_defaultCodeCompleteOptions() | CXCodeComplete_IncludeBriefComments; } void EnsureCompilerNamePresent( std::vector< const char * > &flags ) { bool no_compiler_name_set = !flags.empty() && flags.front()[ 0 ] == '-'; if ( flags.empty() || no_compiler_name_set ) flags.insert( flags.begin(), "clang" ); } } // unnamed namespace typedef shared_ptr < remove_pointer< CXCodeCompleteResults >::type > CodeCompleteResultsWrap; TranslationUnit::TranslationUnit() : filename_( "" ), clang_translation_unit_( NULL ) { } TranslationUnit::TranslationUnit( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, CXIndex clang_index ) : filename_( filename ), clang_translation_unit_( NULL ) { std::vector< const char * > pointer_flags; pointer_flags.reserve( flags.size() ); foreach ( const std::string & flag, flags ) { pointer_flags.push_back( flag.c_str() ); } EnsureCompilerNamePresent( pointer_flags ); std::vector< CXUnsavedFile > cxunsaved_files = ToCXUnsavedFiles( unsaved_files ); const CXUnsavedFile *unsaved = cxunsaved_files.size() > 0 ? &cxunsaved_files[ 0 ] : NULL; // Actually parse the translation unit. CXErrorCode result = clang_parseTranslationUnit2FullArgv( clang_index, filename.c_str(), &pointer_flags[ 0 ], pointer_flags.size(), const_cast( unsaved ), cxunsaved_files.size(), EditingOptions(), &clang_translation_unit_ ); if ( result != CXError_Success ) boost_throw( ClangParseError() ); } TranslationUnit::~TranslationUnit() { Destroy(); } void TranslationUnit::Destroy() { unique_lock< mutex > lock( clang_access_mutex_ ); if ( clang_translation_unit_ ) { clang_disposeTranslationUnit( clang_translation_unit_ ); clang_translation_unit_ = NULL; } } bool TranslationUnit::IsCurrentlyUpdating() const { // We return true when the TU is invalid; an invalid TU also acts a sentinel, // preventing other threads from trying to use it. if ( !clang_translation_unit_ ) return true; unique_lock< mutex > lock( clang_access_mutex_, try_to_lock_t() ); return !lock.owns_lock(); } std::vector< Diagnostic > TranslationUnit::Reparse( const std::vector< UnsavedFile > &unsaved_files ) { std::vector< CXUnsavedFile > cxunsaved_files = ToCXUnsavedFiles( unsaved_files ); Reparse( cxunsaved_files ); unique_lock< mutex > lock( diagnostics_mutex_ ); return latest_diagnostics_; } std::vector< CompletionData > TranslationUnit::CandidatesForLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files ) { unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return std::vector< CompletionData >(); std::vector< CXUnsavedFile > cxunsaved_files = ToCXUnsavedFiles( unsaved_files ); const CXUnsavedFile *unsaved = cxunsaved_files.size() > 0 ? &cxunsaved_files[ 0 ] : NULL; // codeCompleteAt reparses the TU if the underlying source file has changed on // disk since the last time the TU was updated and there are no unsaved files. // If there are unsaved files, then codeCompleteAt will parse the in-memory // file contents we are giving it. In short, it is NEVER a good idea to call // clang_reparseTranslationUnit right before a call to clang_codeCompleteAt. // This only makes clang reparse the whole file TWICE, which has a huge impact // on latency. At the time of writing, it seems that most users of libclang // in the open-source world don't realize this (I checked). Some don't even // call reparse*, but parse* which is even less efficient. CodeCompleteResultsWrap results( clang_codeCompleteAt( clang_translation_unit_, filename_.c_str(), line, column, const_cast( unsaved ), cxunsaved_files.size(), CompletionOptions() ), clang_disposeCodeCompleteResults ); std::vector< CompletionData > candidates = ToCompletionDataVector( results.get() ); return candidates; } Location TranslationUnit::GetDeclarationLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return Location(); CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return Location(); CXCursor referenced_cursor = clang_getCursorReferenced( cursor ); if ( !CursorIsValid( referenced_cursor ) ) return Location(); CXCursor canonical_cursor = clang_getCanonicalCursor( referenced_cursor ); if ( !CursorIsValid( canonical_cursor ) ) return Location( clang_getCursorLocation( referenced_cursor ) ); return Location( clang_getCursorLocation( canonical_cursor ) ); } Location TranslationUnit::GetDefinitionLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return Location(); CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return Location(); CXCursor definition_cursor = clang_getCursorDefinition( cursor ); if ( !CursorIsValid( definition_cursor ) ) return Location(); return Location( clang_getCursorLocation( definition_cursor ) ); } std::string TranslationUnit::GetTypeAtLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return "Internal error: no translation unit"; CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return "Internal error: cursor not valid"; CXType type = clang_getCursorType( cursor ); std::string type_description = CXStringToString( clang_getTypeSpelling( type ) ); if ( type_description.empty() ) return "Unknown type"; // We have a choice here; libClang provides clang_getCanonicalType which will // return the "underlying" type for the type returned by clang_getCursorType // e.g. for a typedef // type = clang_getCanonicalType( type ); // // Without the above, something like the following would return "MyType" // rather than int: // typedef int MyType; // MyType i = 100; <-- type = MyType, canonical type = int // // There is probably more semantic value in calling it MyType. Indeed, if we // opt for the more specific type, we can get very long or // confusing STL types even for simple usage. e.g. the following: // std::string test = "test"; <-- type = std::string; // canonical type = std::basic_string // // So as a compromise, we return both if and only if the types differ, like // std::string => std::basic_string CXType canonical_type = clang_getCanonicalType( type ); if ( !clang_equalTypes( type, canonical_type ) ) { type_description += " => "; type_description += CXStringToString( clang_getTypeSpelling( canonical_type ) ); } return type_description; } std::string TranslationUnit::GetEnclosingFunctionAtLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return "Internal error: no translation unit"; CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return "Internal error: cursor not valid"; CXCursor parent = clang_getCursorSemanticParent( cursor ); std::string parent_str = CXStringToString( clang_getCursorDisplayName( parent ) ); if ( parent_str.empty() ) return "Unknown semantic parent"; return parent_str; } // Argument taken as non-const ref because we need to be able to pass a // non-const pointer to clang. This function (and clang too) will not modify the // param though. void TranslationUnit::Reparse( std::vector< CXUnsavedFile > &unsaved_files ) { unsigned options = ( clang_translation_unit_ ? ReparseOptions( clang_translation_unit_ ) : static_cast( CXReparse_None ) ); Reparse( unsaved_files, options ); } // Argument taken as non-const ref because we need to be able to pass a // non-const pointer to clang. This function (and clang too) will not modify the // param though. void TranslationUnit::Reparse( std::vector< CXUnsavedFile > &unsaved_files, uint parse_options ) { int failure = 0; { unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return; CXUnsavedFile *unsaved = unsaved_files.size() > 0 ? &unsaved_files[ 0 ] : NULL; failure = clang_reparseTranslationUnit( clang_translation_unit_, unsaved_files.size(), unsaved, parse_options ); } if ( failure ) { Destroy(); boost_throw( ClangParseError() ); } UpdateLatestDiagnostics(); } void TranslationUnit::UpdateLatestDiagnostics() { unique_lock< mutex > lock1( clang_access_mutex_ ); unique_lock< mutex > lock2( diagnostics_mutex_ ); latest_diagnostics_.clear(); uint num_diagnostics = clang_getNumDiagnostics( clang_translation_unit_ ); latest_diagnostics_.reserve( num_diagnostics ); for ( uint i = 0; i < num_diagnostics; ++i ) { Diagnostic diagnostic = BuildDiagnostic( DiagnosticWrap( clang_getDiagnostic( clang_translation_unit_, i ), clang_disposeDiagnostic ), clang_translation_unit_ ); if ( diagnostic.kind_ != INFORMATION ) latest_diagnostics_.push_back( diagnostic ); } } namespace { /// Sort a FixIt container by its location's distance from a given column /// (such as the cursor location). /// /// PreCondition: All FixIts in the container are on the same line. struct sort_by_location { sort_by_location( int column ) : column_( column ) { } bool operator()( const FixIt &a, const FixIt &b ) { int a_distance = a.location.column_number_ - column_; int b_distance = b.location.column_number_ - column_; return std::abs( a_distance ) < std::abs( b_distance ); } private: int column_; }; } std::vector< FixIt > TranslationUnit::GetFixItsForLocationInFile( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); std::vector< FixIt > fixits; { unique_lock< mutex > lock( diagnostics_mutex_ ); foreach( const Diagnostic& diagnostic, latest_diagnostics_ ) { // Find all diagnostics for the supplied line which have FixIts attached if ( diagnostic.location_.line_number_ == static_cast< uint >( line ) ) { fixits.insert( fixits.end(), diagnostic.fixits_.begin(), diagnostic.fixits_.end() ); } } } // Sort them by the distance to the supplied column std::sort( fixits.begin(), fixits.end(), sort_by_location( column ) ); return fixits; } DocumentationData TranslationUnit::GetDocsForLocationInFile( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) Reparse( unsaved_files ); unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) return DocumentationData(); CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return DocumentationData(); // If the original cursor is a reference, then we return the documentation // for the type/method/etc. that is referenced CXCursor referenced_cursor = clang_getCursorReferenced( cursor ); if ( CursorIsValid( referenced_cursor ) ) cursor = referenced_cursor; // We always want the documentation associated with the canonical declaration CXCursor canonical_cursor = clang_getCanonicalCursor( cursor ); if ( !CursorIsValid( canonical_cursor ) ) return DocumentationData(); return DocumentationData( canonical_cursor ); } CXCursor TranslationUnit::GetCursor( int line, int column ) { // ASSUMES A LOCK IS ALREADY HELD ON clang_access_mutex_! if ( !clang_translation_unit_ ) return clang_getNullCursor(); CXFile file = clang_getFile( clang_translation_unit_, filename_.c_str() ); CXSourceLocation source_location = clang_getLocation( clang_translation_unit_, file, line, column ); return clang_getCursor( clang_translation_unit_, source_location ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/ClangUtils.h0000644000175000017500000000247013026170313022651 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef CLANGUTILS_H_9MVHQLJS #define CLANGUTILS_H_9MVHQLJS #include #include namespace YouCompleteMe { /** * Return a std::string from the supplied CXString. * * Takes ownership of, and destroys, the supplied CXString which must not be used * subsequently. */ std::string CXStringToString( CXString text ); bool CursorIsValid( CXCursor cursor ); bool CursorIsReference( CXCursor cursor ); bool CursorIsDeclaration( CXCursor cursor ); std::string CXFileToFilepath( CXFile file ); std::string ClangVersion(); } // namespace YouCompleteMe #endif /* end of include guard: CLANGUTILS_H_9MVHQLJS */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/Documentation.cpp0000644000175000017500000000316713026170313023754 0ustar onuronur// Copyright (C) 2015 YouCompleteMe Contributors // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "Documentation.h" #include "ClangHelpers.h" #include namespace YouCompleteMe { namespace { bool CXCommentValid( const CXComment &comment ) { return clang_Comment_getKind( comment ) != CXComment_Null; } } DocumentationData::DocumentationData( const CXCursor &cursor ) : raw_comment( CXStringToString( clang_Cursor_getRawCommentText( cursor ) ) ) , brief_comment( CXStringToString( clang_Cursor_getBriefCommentText( cursor ) ) ) , canonical_type( CXStringToString( clang_getTypeSpelling( clang_getCursorType( cursor ) ) ) ) , display_name( CXStringToString( clang_getCursorSpelling( cursor ) ) ) { CXComment parsed_comment = clang_Cursor_getParsedComment( cursor ); if ( CXCommentValid( parsed_comment ) ) { comment_xml = CXStringToString( clang_FullComment_getAsXML( parsed_comment ) ); } } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/CompletionData.h0000644000175000017500000001000213026170313023475 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef COMPLETIONDATA_H_2JCTF1NU #define COMPLETIONDATA_H_2JCTF1NU #include "standard.h" #include #include namespace YouCompleteMe { enum CompletionKind { STRUCT = 0, CLASS, ENUM, TYPE, MEMBER, FUNCTION, VARIABLE, MACRO, PARAMETER, NAMESPACE, UNKNOWN }; // This class holds pieces of information about a single completion coming from // clang. These pieces are shown in Vim's UI in different ways. // // Normally, the completion menu looks like this (without square brackets): // // [main completion text] [kind] [extra menu info] // [main completion text] [kind] [extra menu info] // [main completion text] [kind] [extra menu info] // ... (etc.) ... // // The user can also enable a "preview" window that will show extra information // about a completion at the top of the buffer. struct CompletionData { CompletionData() {} CompletionData( const CXCompletionResult &completion_result ); // What should actually be inserted into the buffer. For a function like // "int foo(int x)", this is just "foo". Same for a data member like "foo_": // we insert just "foo_". std::string TextToInsertInBuffer() const { return original_string_; } // Currently, here we show the full function signature (without the return // type) if the current completion is a function or just the raw TypedText if // the completion is, say, a data member. So for a function like "int foo(int // x)", this would be "foo(int x)". For a data member like "count_", it would // be just "count_". std::string MainCompletionText() const { return everything_except_return_type_; } // This is extra info shown in the pop-up completion menu, after the // completion text and the kind. Currently we put the return type of the // function here, if any. std::string ExtraMenuInfo() const { return return_type_; } // This is used to show extra information in vim's preview window. This is the // window that vim usually shows at the top of the buffer. This should be used // for extra information about the completion. std::string DetailedInfoForPreviewWindow() const { return detailed_info_; } std::string DocString() const { return doc_string_; } bool operator== ( const CompletionData &other ) const { return kind_ == other.kind_ && everything_except_return_type_ == other.everything_except_return_type_ && return_type_ == other.return_type_ && original_string_ == other.original_string_; // detailed_info_ doesn't matter } std::string detailed_info_; std::string return_type_; CompletionKind kind_; // The original, raw completion string. For a function like "int foo(int x)", // the original string is "foo". For a member data variable like "foo_", this // is just "foo_". This corresponds to clang's TypedText chunk of the // completion string. std::string original_string_; std::string everything_except_return_type_; std::string doc_string_; private: void ExtractDataFromChunk( CXCompletionString completion_string, uint chunk_num, bool &saw_left_paren, bool &saw_function_params, bool &saw_placeholder ); }; } // namespace YouCompleteMe #endif /* end of include guard: COMPLETIONDATA_H_2JCTF1NU */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/TranslationUnitStore.h0000644000175000017500000000537313026170313024764 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef TRANSLATIONUNITSTORE_H_NGN0MCKB #define TRANSLATIONUNITSTORE_H_NGN0MCKB #include "TranslationUnit.h" #include "UnsavedFile.h" #include #include #include #include #include #include typedef void *CXIndex; namespace YouCompleteMe { class TranslationUnitStore : boost::noncopyable { public: TranslationUnitStore( CXIndex clang_index ); ~TranslationUnitStore(); // You can even call this function for the same filename from multiple // threads; the TU store will ensure only one TU is created. boost::shared_ptr< TranslationUnit > GetOrCreate( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ); boost::shared_ptr< TranslationUnit > GetOrCreate( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool &translation_unit_created ); // Careful here! While GetOrCreate makes sure to take into account the flags // for the file before returning a stored TU (if the flags changed, the TU is // not really valid anymore and a new one should be built), this function does // not. You might end up getting a stale TU. boost::shared_ptr< TranslationUnit > Get( const std::string &filename ); bool Remove( const std::string &filename ); void RemoveAll(); private: // WARNING: This accesses filename_to_translation_unit_ without a lock! boost::shared_ptr< TranslationUnit > GetNoLock( const std::string &filename ); typedef boost::unordered_map < std::string, boost::shared_ptr< TranslationUnit > > TranslationUnitForFilename; typedef boost::unordered_map < std::string, std::size_t > FlagsHashForFilename; CXIndex clang_index_; TranslationUnitForFilename filename_to_translation_unit_; FlagsHashForFilename filename_to_flags_hash_; boost::mutex filename_to_translation_unit_and_flags_mutex_; }; } // namespace YouCompleteMe #endif // TRANSLATIONUNITSTORE_H_NGN0MCKB ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/UnsavedFile.h0000644000175000017500000000267013026170313023013 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef UNSAVEDFILE_H_0GIYZQL4 #define UNSAVEDFILE_H_0GIYZQL4 #include struct UnsavedFile { UnsavedFile() : filename_( "" ), contents_( "" ), length_( 0 ) {} std::string filename_; std::string contents_; unsigned long length_; // We need this to be able to export this struct to Python via Boost.Python's // methods. I have no clue why, but it won't compile without it. // TODO: report this problem on the Boost bug tracker, the default equality // operator should be more than adequate here bool operator== ( const UnsavedFile &other ) const { return filename_ == other.filename_ && contents_ == other.contents_ && length_ == other.length_; } }; #endif /* end of include guard: UNSAVEDFILE_H_0GIYZQL4 */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/ClangCompleter.h0000644000175000017500000000673513026170313023513 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef CLANGCOMPLETE_H_WLKDU0ZV #define CLANGCOMPLETE_H_WLKDU0ZV #include "../DLLDefines.h" #include "UnsavedFile.h" #include "Diagnostic.h" #include "TranslationUnitStore.h" #include "Documentation.h" #include #include typedef struct CXTranslationUnitImpl *CXTranslationUnit; namespace YouCompleteMe { class TranslationUnit; struct CompletionData; struct Location; typedef std::vector< CompletionData > CompletionDatas; // All filename parameters must be absolute paths. class ClangCompleter : boost::noncopyable { public: YCM_DLL_EXPORT ClangCompleter(); YCM_DLL_EXPORT ~ClangCompleter(); bool UpdatingTranslationUnit( const std::string &filename ); std::vector< Diagnostic > UpdateTranslationUnit( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ); YCM_DLL_EXPORT std::vector< CompletionData > CandidatesForLocationInFile( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags ); Location GetDeclarationLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse = true ); YCM_DLL_EXPORT Location GetDefinitionLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse = true ); std::string GetTypeAtLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse = true ); std::string GetEnclosingFunctionAtLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse = true ); std::vector< FixIt > GetFixItsForLocationInFile( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse = true ); DocumentationData GetDocsForLocationInFile( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, bool reparse = true ); void DeleteCachesForFile( const std::string &filename ); private: ///////////////////////////// // PRIVATE MEMBER VARIABLES ///////////////////////////// CXIndex clang_index_; TranslationUnitStore translation_unit_store_; }; } // namespace YouCompleteMe #endif /* end of include guard: CLANGCOMPLETE_H_WLKDU0ZV */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/Range.h0000644000175000017500000000240613026170313021637 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef RANGE_H_4MFTIGQK #define RANGE_H_4MFTIGQK #include "standard.h" #include "Location.h" namespace YouCompleteMe { // Half-open, [start, end> struct Range { Range() {} Range( const Location &start_location, const Location &end_location ) : start_( start_location ), end_( end_location ) {} Range( const CXSourceRange &range ); bool operator== ( const Range &other ) const { return start_ == other.start_ && end_ == other.end_; } Location start_; Location end_; }; } // namespace YouCompleteMe #endif /* end of include guard: RANGE_H_4MFTIGQK */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/CompletionData.cpp0000644000175000017500000001677213026170313024054 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "CompletionData.h" #include "ClangUtils.h" #include #include #include namespace YouCompleteMe { namespace { CompletionKind CursorKindToCompletionKind( CXCursorKind kind ) { switch ( kind ) { case CXCursor_StructDecl: return STRUCT; case CXCursor_ClassDecl: case CXCursor_ClassTemplate: case CXCursor_ObjCInterfaceDecl: case CXCursor_ObjCImplementationDecl: return CLASS; case CXCursor_EnumDecl: return ENUM; case CXCursor_UnexposedDecl: case CXCursor_UnionDecl: case CXCursor_TypedefDecl: return TYPE; case CXCursor_FieldDecl: case CXCursor_ObjCIvarDecl: case CXCursor_ObjCPropertyDecl: case CXCursor_EnumConstantDecl: return MEMBER; case CXCursor_FunctionDecl: case CXCursor_CXXMethod: case CXCursor_FunctionTemplate: case CXCursor_ConversionFunction: case CXCursor_Constructor: case CXCursor_Destructor: case CXCursor_ObjCClassMethodDecl: case CXCursor_ObjCInstanceMethodDecl: return FUNCTION; case CXCursor_VarDecl: return VARIABLE; case CXCursor_MacroDefinition: return MACRO; case CXCursor_ParmDecl: return PARAMETER; case CXCursor_Namespace: case CXCursor_NamespaceAlias: return NAMESPACE; default: return UNKNOWN; } } bool IsMainCompletionTextInfo( CXCompletionChunkKind kind ) { return kind == CXCompletionChunk_Optional || kind == CXCompletionChunk_TypedText || kind == CXCompletionChunk_Placeholder || kind == CXCompletionChunk_LeftParen || kind == CXCompletionChunk_RightParen || kind == CXCompletionChunk_RightBracket || kind == CXCompletionChunk_LeftBracket || kind == CXCompletionChunk_LeftBrace || kind == CXCompletionChunk_RightBrace || kind == CXCompletionChunk_RightAngle || kind == CXCompletionChunk_LeftAngle || kind == CXCompletionChunk_Comma || kind == CXCompletionChunk_Colon || kind == CXCompletionChunk_SemiColon || kind == CXCompletionChunk_Equal || kind == CXCompletionChunk_Informative || kind == CXCompletionChunk_HorizontalSpace || kind == CXCompletionChunk_Text; } std::string ChunkToString( CXCompletionString completion_string, uint chunk_num ) { if ( !completion_string ) return std::string(); return YouCompleteMe::CXStringToString( clang_getCompletionChunkText( completion_string, chunk_num ) ); } std::string OptionalChunkToString( CXCompletionString completion_string, uint chunk_num ) { std::string final_string; if ( !completion_string ) return final_string; CXCompletionString optional_completion_string = clang_getCompletionChunkCompletionString( completion_string, chunk_num ); if ( !optional_completion_string ) return final_string; uint optional_num_chunks = clang_getNumCompletionChunks( optional_completion_string ); for ( uint j = 0; j < optional_num_chunks; ++j ) { CXCompletionChunkKind kind = clang_getCompletionChunkKind( optional_completion_string, j ); if ( kind == CXCompletionChunk_Optional ) { final_string.append( OptionalChunkToString( optional_completion_string, j ) ); } else { final_string.append( ChunkToString( optional_completion_string, j ) ); } } return final_string; } // foo( -> foo // foo() -> foo std::string RemoveTrailingParens( std::string text ) { if ( boost::ends_with( text, "(" ) ) { boost::erase_tail( text, 1 ); } else if ( boost::ends_with( text, "()" ) ) { boost::erase_tail( text, 2 ); } return text; } } // unnamed namespace CompletionData::CompletionData( const CXCompletionResult &completion_result ) { CXCompletionString completion_string = completion_result.CompletionString; if ( !completion_string ) return; 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_placeholder ); } original_string_ = RemoveTrailingParens( boost::move( original_string_ ) ); kind_ = CursorKindToCompletionKind( completion_result.CursorKind ); detailed_info_.append( return_type_ ) .append( " " ) .append( everything_except_return_type_ ) .append( "\n" ); doc_string_ = YouCompleteMe::CXStringToString( clang_getCompletionBriefComment( completion_string ) ); } void CompletionData::ExtractDataFromChunk( CXCompletionString completion_string, uint chunk_num, bool &saw_left_paren, bool &saw_function_params, bool &saw_placeholder ) { CXCompletionChunkKind kind = clang_getCompletionChunkKind( completion_string, chunk_num ); if ( IsMainCompletionTextInfo( kind ) ) { if ( kind == CXCompletionChunk_LeftParen ) { saw_left_paren = true; } else if ( saw_left_paren && !saw_function_params && kind != CXCompletionChunk_RightParen && kind != CXCompletionChunk_Informative ) { saw_function_params = true; everything_except_return_type_.append( " " ); } else if ( saw_function_params && kind == CXCompletionChunk_RightParen ) { everything_except_return_type_.append( " " ); } if ( kind == CXCompletionChunk_Optional ) { everything_except_return_type_.append( OptionalChunkToString( completion_string, chunk_num ) ); } else { everything_except_return_type_.append( 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 ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/TranslationUnit.h0000644000175000017500000000672213026170313023746 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef TRANSLATIONUNIT_H_XQ7I6SVA #define TRANSLATIONUNIT_H_XQ7I6SVA #include "../DLLDefines.h" #include "UnsavedFile.h" #include "Diagnostic.h" #include "Location.h" #include "Documentation.h" #include #include #include #include #include namespace YouCompleteMe { struct CompletionData; typedef boost::shared_ptr< std::vector< CompletionData > > AsyncCompletions; class TranslationUnit : boost::noncopyable { public: // This constructor creates an invalid, sentinel TU. All of it's methods // return empty vectors, and IsCurrentlyUpdating always returns true so that // no callers try to rely on the invalid TU. TranslationUnit(); YCM_DLL_EXPORT TranslationUnit( const std::string &filename, const std::vector< UnsavedFile > &unsaved_files, const std::vector< std::string > &flags, CXIndex clang_index ); YCM_DLL_EXPORT ~TranslationUnit(); void Destroy(); bool IsCurrentlyUpdating() const; std::vector< Diagnostic > Reparse( const std::vector< UnsavedFile > &unsaved_files ); std::vector< CompletionData > CandidatesForLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files ); YCM_DLL_EXPORT Location GetDeclarationLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse = true ); YCM_DLL_EXPORT Location GetDefinitionLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse = true ); std::string GetTypeAtLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse = true ); std::string GetEnclosingFunctionAtLocation( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse = true ); std::vector< FixIt > GetFixItsForLocationInFile( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse = true ); DocumentationData GetDocsForLocationInFile( int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse = true ); private: void Reparse( std::vector< CXUnsavedFile > &unsaved_files ); void Reparse( std::vector< CXUnsavedFile > &unsaved_files, uint parse_options ); void UpdateLatestDiagnostics(); CXCursor GetCursor( int line, int column ); ///////////////////////////// // PRIVATE MEMBER VARIABLES ///////////////////////////// std::string filename_; boost::mutex diagnostics_mutex_; std::vector< Diagnostic > latest_diagnostics_; mutable boost::mutex clang_access_mutex_; CXTranslationUnit clang_translation_unit_; }; } // namespace YouCompleteMe #endif /* end of include guard: TRANSLATIONUNIT_H_XQ7I6SVA */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/Range.cpp0000644000175000017500000000166013026170313022173 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "Range.h" #include "ClangUtils.h" namespace YouCompleteMe { Range::Range( const CXSourceRange &range ) { start_ = Location( clang_getRangeStart( range ) ); end_ = Location( clang_getRangeEnd( range ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ClangCompleter/ClangHelpers.cpp0000644000175000017500000002144113026170313023505 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "standard.h" #include "ClangHelpers.h" #include "ClangUtils.h" #include "Utils.h" #include "UnsavedFile.h" #include "Location.h" #include "Range.h" #include "PythonSupport.h" #include #include using boost::unordered_map; namespace YouCompleteMe { namespace { DiagnosticKind DiagnosticSeverityToType( CXDiagnosticSeverity severity ) { switch ( severity ) { case CXDiagnostic_Ignored: case CXDiagnostic_Note: return INFORMATION; case CXDiagnostic_Warning: return WARNING; case CXDiagnostic_Error: case CXDiagnostic_Fatal: default: return ERROR; } } FixIt BuildFixIt( const std::string& text, CXDiagnostic diagnostic ) { FixIt fixit; uint num_chunks = clang_getDiagnosticNumFixIts( diagnostic ); if ( !num_chunks ) return fixit; fixit.chunks.reserve( num_chunks ); fixit.location = Location( clang_getDiagnosticLocation( diagnostic ) ); fixit.text = text; for ( uint idx = 0; idx < num_chunks; ++idx ) { FixItChunk chunk; CXSourceRange sourceRange; chunk.replacement_text = CXStringToString( clang_getDiagnosticFixIt( diagnostic, idx, &sourceRange ) ); chunk.range = sourceRange; fixit.chunks.push_back( chunk ); } return fixit; } /// This method generates a FixIt object for the supplied diagnostic, and any /// child diagnostics (recursively), should a FixIt be available and appends /// them to fixits. /// Similarly it populates full_diagnostic_text with a concatenation of the /// diagnostic text for the supplied diagnostic and each child diagnostic /// (recursively). /// Warning: This method is re-entrant (recursive). void BuildFullDiagnosticDataFromChildren( std::string& full_diagnostic_text, std::vector< FixIt >& fixits, CXDiagnostic diagnostic ) { std::string diag_text = CXStringToString( clang_formatDiagnostic( diagnostic, clang_defaultDiagnosticDisplayOptions() ) ); full_diagnostic_text.append( diag_text ); // Populate any fixit attached to this diagnostic. FixIt fixit = BuildFixIt( diag_text, diagnostic ); if ( fixit.chunks.size() > 0 ) fixits.push_back( fixit ); // Note: clang docs say that a CXDiagnosticSet retrieved with // clang_getChildDiagnostics do NOT need to be released with // clang_diposeDiagnosticSet CXDiagnosticSet diag_set = clang_getChildDiagnostics( diagnostic ); if ( !diag_set ) return; uint num_child_diagnostics = clang_getNumDiagnosticsInSet( diag_set ); if ( !num_child_diagnostics ) return; for ( uint i = 0; i < num_child_diagnostics; ++i ) { CXDiagnostic child_diag = clang_getDiagnosticInSet( diag_set, i ); if( !child_diag ) continue; full_diagnostic_text.append( "\n" ); // recurse BuildFullDiagnosticDataFromChildren( full_diagnostic_text, fixits, child_diag ); } } // Returns true when the provided completion string is available to the user; // unavailable completion strings refer to entities that are private/protected, // deprecated etc. bool CompletionStringAvailable( CXCompletionString completion_string ) { if ( !completion_string ) return false; return clang_getCompletionAvailability( completion_string ) == CXAvailability_Available; } std::vector< Range > GetRanges( const DiagnosticWrap &diagnostic_wrap ) { std::vector< Range > ranges; uint num_ranges = clang_getDiagnosticNumRanges( diagnostic_wrap.get() ); ranges.reserve( num_ranges ); for ( uint i = 0; i < num_ranges; ++i ) { ranges.push_back( Range( clang_getDiagnosticRange( diagnostic_wrap.get(), i ) ) ); } return ranges; } Range GetLocationExtent( CXSourceLocation source_location, CXTranslationUnit translation_unit ) { // If you think the below code is an idiotic way of getting the source range // for an identifier at a specific source location, you are not the only one. // I cannot believe that this is the only way to achieve this with the // libclang API in a robust way. // I've tried many simpler ways of doing this and they all fail in various // situations. CXSourceRange range = clang_getCursorExtent( clang_getCursor( translation_unit, source_location ) ); CXToken *tokens; uint num_tokens; clang_tokenize( translation_unit, range, &tokens, &num_tokens ); Location location( source_location ); Range final_range; for ( uint i = 0; i < num_tokens; ++i ) { Location token_location( clang_getTokenLocation( translation_unit, tokens[ i ] ) ); if ( token_location == location ) { std::string name = CXStringToString( clang_getTokenSpelling( translation_unit, tokens[ i ] ) ); Location end_location = location; end_location.column_number_ += name.length(); final_range = Range( location, end_location ); break; } } clang_disposeTokens( translation_unit, tokens, num_tokens ); return final_range; } } // unnamed namespace std::vector< CXUnsavedFile > ToCXUnsavedFiles( const std::vector< UnsavedFile > &unsaved_files ) { std::vector< CXUnsavedFile > clang_unsaved_files( unsaved_files.size() ); for ( uint i = 0; i < unsaved_files.size(); ++i ) { clang_unsaved_files[ i ].Filename = unsaved_files[ i ].filename_.c_str(); clang_unsaved_files[ i ].Contents = unsaved_files[ i ].contents_.c_str(); clang_unsaved_files[ i ].Length = unsaved_files[ i ].length_; } return clang_unsaved_files; } std::vector< CompletionData > ToCompletionDataVector( CXCodeCompleteResults *results ) { std::vector< CompletionData > completions; if ( !results || !results->Results ) return completions; completions.reserve( results->NumResults ); unordered_map< std::string, uint > seen_data; for ( uint i = 0; i < results->NumResults; ++i ) { CXCompletionResult completion_result = results->Results[ i ]; if ( !CompletionStringAvailable( completion_result.CompletionString ) ) continue; CompletionData data( completion_result ); uint index = GetValueElseInsert( seen_data, data.original_string_, completions.size() ); if ( index == completions.size() ) { completions.push_back( boost::move( data ) ); } else { // If we have already seen this completion, then this is an overload of a // function we have seen. We add the signature of the overload to the // detailed information. completions[ index ].detailed_info_ .append( data.return_type_ ) .append( " " ) .append( data.everything_except_return_type_ ) .append( "\n" ); } } return completions; } Diagnostic BuildDiagnostic( DiagnosticWrap diagnostic_wrap, CXTranslationUnit translation_unit ) { Diagnostic diagnostic; if ( !diagnostic_wrap ) return diagnostic; diagnostic.kind_ = DiagnosticSeverityToType( clang_getDiagnosticSeverity( diagnostic_wrap.get() ) ); // If this is an "ignored" diagnostic, there's no point in continuing since we // won't display those to the user if ( diagnostic.kind_ == INFORMATION ) return diagnostic; CXSourceLocation source_location = clang_getDiagnosticLocation( diagnostic_wrap.get() ); diagnostic.location_ = Location( source_location ); diagnostic.location_extent_ = GetLocationExtent( source_location, translation_unit ); diagnostic.ranges_ = GetRanges( diagnostic_wrap ); diagnostic.text_ = CXStringToString( clang_getDiagnosticSpelling( diagnostic_wrap.get() ) ); BuildFullDiagnosticDataFromChildren( diagnostic.long_formatted_text_, diagnostic.fixits_, diagnostic_wrap.get() ); return diagnostic; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/Candidate.h0000644000175000017500000000412413026170313017557 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef CANDIDATE_H_R5LZH6AC #define CANDIDATE_H_R5LZH6AC #include "DLLDefines.h" #include "LetterNode.h" #include #include #include #include namespace YouCompleteMe { class Result; // Returns true if text contains only printable characters: ASCII characters in // the range 32-126. bool IsPrintable( const std::string &text ); typedef std::bitset< NUM_LETTERS > Bitset; YCM_DLL_EXPORT Bitset LetterBitsetFromString( const std::string &text ); // Public for tests YCM_DLL_EXPORT std::string GetWordBoundaryChars( const std::string &text ); class Candidate : boost::noncopyable { public: YCM_DLL_EXPORT explicit Candidate( const std::string &text ); inline const std::string &Text() const { return text_; } // Returns true if the candidate contains the bits from the query (it may also // contain other bits) inline bool MatchesQueryBitset( const Bitset &query_bitset ) const { return ( letters_present_ & query_bitset ) == query_bitset; } YCM_DLL_EXPORT Result QueryMatchResult( const std::string &query, bool case_sensitive ) const; private: std::string text_; std::string word_boundary_chars_; bool text_is_lowercase_; Bitset letters_present_; boost::scoped_ptr< LetterNode > root_node_; }; } // namespace YouCompleteMe #endif /* end of include guard: CANDIDATE_H_R5LZH6AC */ ycmd-0+20161219+git486b809.orig/cpp/ycm/LetterNodeListMap.h0000644000175000017500000000523313026170313021244 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef LETTERNODELISTMAP_H_BRK2UMC1 #define LETTERNODELISTMAP_H_BRK2UMC1 #include "DLLDefines.h" #include #include #include #include #define NUM_LETTERS 128 namespace YouCompleteMe { class LetterNode; YCM_DLL_EXPORT bool IsUppercase( char letter ); bool IsInAsciiRange( int index ); YCM_DLL_EXPORT int IndexForLetter( char letter ); /* * This struct is used as part of the LetterNodeListMap structure. * Every LetterNode represents 1 position in a string, and contains * one LetterNodeListMap. The LetterNodeListMap records the first * occurrence of all ascii characters after the current LetterNode * in the original string. For each character, the * LetterNodeListMap contains one instance of NearestLetterNodeIndices * * The struct records the position in the original string of the character * after the current LetterNode, both the first occurrence overall and the * first uppercase occurrence. If the letter (or uppercase version) * doesn't occur, it records -1, indicating it isn't present. * * The indices can be used to retrieve the corresponding LetterNode from * the root LetterNode, as it contains a vector of LetterNodes, one per * position in the original string. */ struct NearestLetterNodeIndices { NearestLetterNodeIndices() : indexOfFirstOccurrence( -1 ), indexOfFirstUppercaseOccurrence( -1 ) {} short indexOfFirstOccurrence; short indexOfFirstUppercaseOccurrence; }; class LetterNodeListMap { public: LetterNodeListMap(); LetterNodeListMap( const LetterNodeListMap &other ); NearestLetterNodeIndices &operator[] ( char letter ); YCM_DLL_EXPORT NearestLetterNodeIndices *ListPointerAt( char letter ); private: typedef boost::array NearestLetterNodeArray; boost::movelib::unique_ptr< NearestLetterNodeArray > letters_; }; } // namespace YouCompleteMe #endif /* end of include guard: LETTERNODELISTMAP_H_BRK2UMC1 */ ycmd-0+20161219+git486b809.orig/cpp/ycm/IdentifierDatabase.cpp0000644000175000017500000001201113026170313021737 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "IdentifierDatabase.h" #include "standard.h" #include "Candidate.h" #include "CandidateRepository.h" #include "IdentifierUtils.h" #include "Result.h" #include "Utils.h" #include #include #include #include using boost::algorithm::any_of; using boost::algorithm::is_upper; namespace YouCompleteMe { IdentifierDatabase::IdentifierDatabase() : candidate_repository_( CandidateRepository::Instance() ) { } void IdentifierDatabase::AddIdentifiers( const FiletypeIdentifierMap &filetype_identifier_map ) { boost::lock_guard< boost::mutex > locker( filetype_candidate_map_mutex_ ); foreach ( const FiletypeIdentifierMap::value_type & filetype_and_map, filetype_identifier_map ) { foreach( const FilepathToIdentifiers::value_type & filepath_and_identifiers, filetype_and_map.second ) { AddIdentifiersNoLock( filepath_and_identifiers.second, filetype_and_map.first, filepath_and_identifiers.first ); } } } void IdentifierDatabase::AddIdentifiers( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ) { boost::lock_guard< boost::mutex > locker( filetype_candidate_map_mutex_ ); AddIdentifiersNoLock( new_candidates, filetype, filepath ); } void IdentifierDatabase::ClearCandidatesStoredForFile( const std::string &filetype, const std::string &filepath ) { boost::lock_guard< boost::mutex > locker( filetype_candidate_map_mutex_ ); GetCandidateSet( filetype, filepath ).clear(); } void IdentifierDatabase::ResultsForQueryAndType( const std::string &query, const std::string &filetype, std::vector< Result > &results ) const { FiletypeCandidateMap::const_iterator it; { boost::lock_guard< boost::mutex > locker( filetype_candidate_map_mutex_ ); it = filetype_candidate_map_.find( filetype ); if ( it == filetype_candidate_map_.end() || query.empty() ) return; } Bitset query_bitset = LetterBitsetFromString( query ); bool query_has_uppercase_letters = any_of( query, is_upper() ); boost::unordered_set< const Candidate * > seen_candidates; seen_candidates.reserve( candidate_repository_.NumStoredCandidates() ); { boost::lock_guard< boost::mutex > locker( filetype_candidate_map_mutex_ ); foreach ( const FilepathToCandidates::value_type & path_and_candidates, *it->second ) { foreach ( const Candidate * candidate, *path_and_candidates.second ) { if ( ContainsKey( seen_candidates, candidate ) ) continue; else seen_candidates.insert( candidate ); if ( !candidate->MatchesQueryBitset( query_bitset ) ) continue; Result result = candidate->QueryMatchResult( query, query_has_uppercase_letters ); if ( result.IsSubsequence() ) results.push_back( result ); } } } std::sort( results.begin(), results.end() ); } // WARNING: You need to hold the filetype_candidate_map_mutex_ before calling // this function and while using the returned set. std::set< const Candidate * > &IdentifierDatabase::GetCandidateSet( const std::string &filetype, const std::string &filepath ) { boost::shared_ptr< FilepathToCandidates > &path_to_candidates = filetype_candidate_map_[ filetype ]; if ( !path_to_candidates ) path_to_candidates.reset( new FilepathToCandidates() ); boost::shared_ptr< std::set< const Candidate * > > &candidates = ( *path_to_candidates )[ filepath ]; if ( !candidates ) candidates.reset( new std::set< const Candidate * >() ); return *candidates; } // WARNING: You need to hold the filetype_candidate_map_mutex_ before calling // this function and while using the returned set. void IdentifierDatabase::AddIdentifiersNoLock( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ) { std::set< const Candidate *> &candidates = GetCandidateSet( filetype, filepath ); std::vector< const Candidate * > repository_candidates = candidate_repository_.GetCandidatesForStrings( new_candidates ); candidates.insert( repository_candidates.begin(), repository_candidates.end() ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/IdentifierDatabase.h0000644000175000017500000000631513026170313021416 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef IDENTIFIERDATABASE_H_ZESX3CVR #define IDENTIFIERDATABASE_H_ZESX3CVR #include #include #include #include #include #include #include #include namespace YouCompleteMe { class Candidate; class Result; class CandidateRepository; // filepath -> identifiers typedef std::map< std::string, std::vector< std::string > > FilepathToIdentifiers; // filetype -> (filepath -> identifiers) typedef std::map< std::string, FilepathToIdentifiers > FiletypeIdentifierMap; // This class stores the database of identifiers the identifier completer has // seen. It stores them in a data structure that makes it easy to tell which // identifier came from which file and what files have which filetypes. // // The main point of this class is to isolate the parts of the code that need // access to this internal data structure so that it's easier to confirm that // mutexes are used correctly to protect concurrent access. // // This class is thread-safe. class IdentifierDatabase : boost::noncopyable { public: IdentifierDatabase(); void AddIdentifiers( const FiletypeIdentifierMap &filetype_identifier_map ); void AddIdentifiers( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ); void ClearCandidatesStoredForFile( const std::string &filetype, const std::string &filepath ); void ResultsForQueryAndType( const std::string &query, const std::string &filetype, std::vector< Result > &results ) const; private: std::set< const Candidate * > &GetCandidateSet( const std::string &filetype, const std::string &filepath ); void AddIdentifiersNoLock( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ); // filepath -> *( *candidate ) typedef boost::unordered_map < std::string, boost::shared_ptr< std::set< const Candidate * > > > FilepathToCandidates; // filetype -> *( filepath -> *( *candidate ) ) typedef boost::unordered_map < std::string, boost::shared_ptr< FilepathToCandidates > > FiletypeCandidateMap; CandidateRepository &candidate_repository_; FiletypeCandidateMap filetype_candidate_map_; mutable boost::mutex filetype_candidate_map_mutex_; }; } // namespace YouCompleteMe #endif /* end of include guard: IDENTIFIERDATABASE_H_ZESX3CVR */ ycmd-0+20161219+git486b809.orig/cpp/ycm/Candidate.cpp0000644000175000017500000000677413026170313020127 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "standard.h" #include "Candidate.h" #include "Result.h" #include #include #include using boost::algorithm::all; using boost::algorithm::is_lower; using boost::algorithm::is_print; namespace YouCompleteMe { bool IsPrintable( const std::string &text ) { return all( text, is_print( std::locale::classic() ) ); } std::string GetWordBoundaryChars( const std::string &text ) { std::string result; for ( uint i = 0; i < text.size(); ++i ) { bool is_first_char_but_not_punctuation = i == 0 && !ispunct( text[ i ] ); bool is_good_uppercase = i > 0 && IsUppercase( text[ i ] ) && !IsUppercase( text[ i - 1 ] ); bool is_alpha_after_punctuation = i > 0 && ispunct( text[ i - 1 ] ) && isalpha( text[ i ] ); if ( is_first_char_but_not_punctuation || is_good_uppercase || is_alpha_after_punctuation ) { result.push_back( tolower( text[ i ] ) ); } } return result; } Bitset LetterBitsetFromString( const std::string &text ) { Bitset letter_bitset; foreach ( char letter, text ) { int letter_index = IndexForLetter( letter ); if ( IsInAsciiRange( letter_index ) ) letter_bitset.set( letter_index ); } return letter_bitset; } Candidate::Candidate( const std::string &text ) : text_( text ), word_boundary_chars_( GetWordBoundaryChars( text ) ), text_is_lowercase_( all( text, is_lower() ) ), letters_present_( LetterBitsetFromString( text ) ), root_node_( new LetterNode( text ) ) { } Result Candidate::QueryMatchResult( const std::string &query, bool case_sensitive ) const { LetterNode *node = root_node_.get(); int index_sum = 0; foreach ( char letter, query ) { const NearestLetterNodeIndices *nearest = node->NearestLetterNodesForLetter( letter ); if ( !nearest ) return Result( false ); // When the query letter is uppercase, then we force an uppercase match // but when the query letter is lowercase, then it can match both an // uppercase and a lowercase letter. This is by design and it's much // better than forcing lowercase letter matches. node = NULL; if ( case_sensitive && IsUppercase( letter ) ) { if ( nearest->indexOfFirstUppercaseOccurrence >= 0 ) node = ( *root_node_ )[ nearest->indexOfFirstUppercaseOccurrence ]; } else { if ( nearest->indexOfFirstOccurrence >= 0 ) node = ( *root_node_ )[ nearest->indexOfFirstOccurrence ]; } if ( !node ) return Result( false ); index_sum += node->Index(); } return Result( true, &text_, text_is_lowercase_, index_sum, word_boundary_chars_, query ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/0000755000175000017500000000000013026170316016676 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/ycm/tests/CMakeLists.txt0000644000175000017500000001071613026170313021440 0ustar onuronur# Copyright (C) 2011 Google Inc. # # 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 . project( ycm_core_tests ) cmake_minimum_required( VERSION 2.8 ) # The gtest library triggers these warnings, so we turn them off; it's not up to # us to fix gtest warnings, it's up to upstream. if ( COMPILER_IS_CLANG ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-long-long -Wno-variadic-macros -Wno-missing-field-initializers -Wno-unused-private-field -Wno-c++98-compat" ) endif() option( USE_SYSTEM_GMOCK "Set to ON to use the system gmock/gtest libraries" OFF ) if ( USE_SYSTEM_GMOCK ) set( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}" ) find_package( GTest REQUIRED ) find_package( GMock REQUIRED ) else() if ( WIN32 ) # Override BUILD_SHARED_LIBS option in gmock and gtest CMakeLists set( BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries (DLLs)." ) endif() add_subdirectory( gmock ) set( GTEST_INCLUDE_DIRS ${gtest_SOURCE_DIR} ${gtest_SOURCE_DIR}/include ) set( GMOCK_INCLUDE_DIRS ${gmock_SOURCE_DIR} ${gmock_SOURCE_DIR}/include ) set( GTEST_LIBRARIES "" ) set( GMOCK_LIBRARIES gmock ) endif() include_directories( ${ycm_core_SOURCE_DIR} ) include_directories( SYSTEM ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} ) link_directories( ${Boost_LIBRARY_DIRS} ${PYTHON_LIBRARIES} ) file( GLOB_RECURSE SOURCES *.h *.cpp ) # We don't want gmock sources in this target file( GLOB_RECURSE to_remove gmock/*.h gmock/*.cpp CMakeFiles/*.cpp testdata/*.cpp testdata/*.h ) if( to_remove ) list( REMOVE_ITEM SOURCES ${to_remove} ) endif() if ( NOT USE_CLANG_COMPLETER ) file( GLOB_RECURSE to_remove_clang ClangCompleter/*.h ClangCompleter/*.cpp ) if( to_remove_clang ) list( REMOVE_ITEM SOURCES ${to_remove_clang} ) endif() endif() add_executable( ${PROJECT_NAME} ${SOURCES} ) if ( MSVC ) # This is needed to compile tests with the gtest shared library set_target_properties( ${PROJECT_NAME} PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1" ) # Fix gtest build on MSVC 11. See: http://stackoverflow.com/a/8274747 if ( MSVC_VERSION EQUAL 1700 ) add_definitions( /D _VARIADIC_MAX=10 ) endif() # Build gmock and ycm_core_tests targets in cmake ycm/tests folder foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) set_target_properties( ${GMOCK_LIBRARIES} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_BINARY_DIR} ) set_target_properties( ${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${PROJECT_BINARY_DIR} ) endforeach() endif() # ycm_core must be linked after Boost libraries on Windows. target_link_libraries( ${PROJECT_NAME} ${Boost_LIBRARIES} ycm_core ${GTEST_LIBRARIES} ${GMOCK_LIBRARIES} ) if ( NOT CMAKE_GENERATOR_IS_XCODE ) # The test executable expects a "testdata" dir in its working directory. Why? # Because there's NO reliable, cross-platform way of getting the directory in # which the executable is located. add_custom_target( copy_testdata COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/testdata ${CMAKE_CURRENT_BINARY_DIR}/testdata ) else() add_custom_target( copy_testdata COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/testdata ${CMAKE_CURRENT_BINARY_DIR}/Debug/testdata COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/testdata ${CMAKE_CURRENT_BINARY_DIR}/Release/testdata ) endif() add_dependencies( ${PROJECT_NAME} copy_testdata ) ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/ClangCompleter/0000755000175000017500000000000013026170313021572 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/ycm/tests/ClangCompleter/TranslationUnit_test.cpp0000644000175000017500000001060013026170313026470 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "TranslationUnit.h" #include "exceptions.h" #include "Utils.h" #include #include #include #include namespace fs = boost::filesystem; using ::testing::ElementsAre; using ::testing::WhenSorted; namespace YouCompleteMe { class TranslationUnitTest : public ::testing::Test { protected: virtual void SetUp() { clang_index_ = clang_createIndex( 0, 0 ); } virtual void TearDown() { clang_disposeIndex( clang_index_ ); } CXIndex clang_index_; }; TEST_F( TranslationUnitTest, ExceptionThrownOnParseFailure ) { fs::path test_file = fs::temp_directory_path() / fs::unique_path(); std::string junk = "#&9112(^(^#>@(^@!@(&#@a}}}}{nthoeu\n&&^^&^&!#%%@@!aeu"; WriteUtf8File( test_file, junk ); std::vector< std::string > flags; flags.push_back( junk ); EXPECT_THROW( TranslationUnit( test_file.string(), std::vector< UnsavedFile >(), flags, NULL ), ClangParseError ); } TEST_F( TranslationUnitTest, GoToDefinitionWorks ) { fs::path path_to_testdata = fs::current_path() / fs::path( "testdata" ); fs::path test_file = path_to_testdata / fs::path( "goto.cpp" ); TranslationUnit unit( test_file.string(), std::vector< UnsavedFile >(), std::vector< std::string >(), clang_index_ ); Location location = unit.GetDefinitionLocation( 17, 3, std::vector< UnsavedFile >() ); EXPECT_EQ( 1, location.line_number_ ); EXPECT_EQ( 8, location.column_number_ ); EXPECT_TRUE( !location.filename_.empty() ); } TEST_F( TranslationUnitTest, GoToDefinitionFails ) { fs::path path_to_testdata = fs::current_path() / fs::path( "testdata" ); fs::path test_file = path_to_testdata / fs::path( "goto.cpp" ); TranslationUnit unit( test_file.string(), std::vector< UnsavedFile >(), std::vector< std::string >(), clang_index_ ); Location location = unit.GetDefinitionLocation( 19, 3, std::vector< UnsavedFile >() ); EXPECT_FALSE( location.IsValid() ); } TEST_F( TranslationUnitTest, GoToDeclarationWorks ) { fs::path path_to_testdata = fs::current_path() / fs::path( "testdata" ); fs::path test_file = path_to_testdata / fs::path( "goto.cpp" ); TranslationUnit unit( test_file.string(), std::vector< UnsavedFile >(), std::vector< std::string >(), clang_index_ ); Location location = unit.GetDeclarationLocation( 19, 3, std::vector< UnsavedFile >() ); EXPECT_EQ( 12, location.line_number_ ); EXPECT_EQ( 8, location.column_number_ ); EXPECT_TRUE( !location.filename_.empty() ); } TEST_F( TranslationUnitTest, GoToDeclarationWorksOnDefinition ) { fs::path path_to_testdata = fs::current_path() / fs::path( "testdata" ); fs::path test_file = path_to_testdata / fs::path( "goto.cpp" ); TranslationUnit unit( test_file.string(), std::vector< UnsavedFile >(), std::vector< std::string >(), clang_index_ ); Location location = unit.GetDeclarationLocation( 16, 6, std::vector< UnsavedFile >() ); EXPECT_EQ( 14, location.line_number_ ); EXPECT_EQ( 6, location.column_number_ ); EXPECT_TRUE( !location.filename_.empty() ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp0000644000175000017500000000767413026170313026252 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "ClangCompleter.h" #include "CompletionData.h" #include "../TestUtils.h" #include #include #include namespace YouCompleteMe { using ::testing::ElementsAre; using ::testing::WhenSorted; using ::testing::StrEq; using ::testing::Property; using ::testing::Contains; TEST( ClangCompleterTest, CandidatesForLocationInFile ) { ClangCompleter completer; std::vector< CompletionData > completions = completer.CandidatesForLocationInFile( PathToTestFile( "basic.cpp" ).string(), 15, 7, std::vector< UnsavedFile >(), std::vector< std::string >() ); EXPECT_TRUE( !completions.empty() ); } TEST( ClangCompleterTest, BufferTextNoParens ) { ClangCompleter completer; std::vector< CompletionData > completions = completer.CandidatesForLocationInFile( PathToTestFile( "basic.cpp" ).string(), 15, 7, std::vector< UnsavedFile >(), std::vector< std::string >() ); EXPECT_TRUE( !completions.empty() ); EXPECT_THAT( completions, Contains( Property( &CompletionData::TextToInsertInBuffer, StrEq( "foobar" ) ) ) ); } TEST( ClangCompleterTest, CandidatesObjCForLocationInFile ) { ClangCompleter completer; std::vector< std::string > flags; flags.push_back( "-x" ); flags.push_back( "objective-c" ); std::vector< CompletionData > completions = completer.CandidatesForLocationInFile( PathToTestFile( "SWObject.m" ).string(), 6, 16, std::vector< UnsavedFile >(), flags ); EXPECT_TRUE( !completions.empty() ); EXPECT_THAT( completions[0].TextToInsertInBuffer(), StrEq( "withArg2:" ) ); } TEST( ClangCompleterTest, CandidatesObjCFuncForLocationInFile ) { ClangCompleter completer; std::vector< std::string > flags; flags.push_back( "-x" ); flags.push_back( "objective-c" ); std::vector< CompletionData > completions = completer.CandidatesForLocationInFile( PathToTestFile( "SWObject.m" ).string(), 9, 3, std::vector< UnsavedFile >(), flags ); EXPECT_TRUE( !completions.empty() ); EXPECT_THAT( completions[0].TextToInsertInBuffer(), StrEq( "(void)test:(int)arg1 withArg2:(int)arg2 withArg3:(int)arg3" ) ); } 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, 13, 3, std::vector< UnsavedFile >(), std::vector< std::string >() ); EXPECT_EQ( Location( filename, 1, 8 ), actual_location ); } TEST( ClangCompleterTest, GetDocString ) { ClangCompleter completer; std::vector< CompletionData > completions = completer.CandidatesForLocationInFile( PathToTestFile( "basic.cpp" ).string(), 11, 7, std::vector< UnsavedFile >(), std::vector< std::string >() ); for ( size_t i = 0; i < completions.size(); ++i ) { if ( completions[i].TextToInsertInBuffer() == "x" ) { EXPECT_STREQ( "A docstring.", completions[i].DocString().c_str() ); break; } } } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/TestUtils.cpp0000644000175000017500000000412213026170313021336 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "TestUtils.h" namespace YouCompleteMe { namespace fs = boost::filesystem; std::vector< std::string > StringVector( const std::string &a, const std::string &b, const std::string &c, const std::string &d, const std::string &e, const std::string &f, const std::string &g, const std::string &h, const std::string &i ) { std::vector< std::string > string_vector; string_vector.push_back( a ); if ( !b.empty() ) string_vector.push_back( b ); if ( !c.empty() ) string_vector.push_back( c ); if ( !d.empty() ) string_vector.push_back( d ); if ( !e.empty() ) string_vector.push_back( e ); if ( !f.empty() ) string_vector.push_back( f ); if ( !g.empty() ) string_vector.push_back( g ); if ( !h.empty() ) string_vector.push_back( h ); if ( !i.empty() ) string_vector.push_back( i ); return string_vector; } boost::filesystem::path PathToTestFile( const std::string &filepath ) { fs::path path_to_testdata = fs::current_path() / fs::path( "testdata" ); return path_to_testdata / fs::path( filepath ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/testdata/0000755000175000017500000000000013026170313020504 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/ycm/tests/testdata/basic.tags0000644000175000017500000000116613026170313022451 0ustar onuronur!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ !_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ !_TAG_PROGRAM_NAME Exuberant Ctags // !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ !_TAG_PROGRAM_VERSION 5.8 // i1 foo junky;'junklanguage:C++ i1 bar junky;'junklanguage:C++ foosy foo junky;"'junk language:C++ zanzibar fooaaa bar junky;"'junk language:C++ zanzibar bloa foo junky Floo::goo /foo/zoo language:C !goo /foo/goo maa language:C zoro /foo language:fakelang #bleh /m_oo 123ntoh;;;\"eu language:C# ;\" ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/testdata/goto.cpp0000644000175000017500000000025713026170313022164 0ustar onuronurstruct Foo { int bar; int zoo; }; struct Bar { int foo; int zoo; }; struct Foo; struct Zoo; void func(); void func() { Foo foo; foo.bar = 5; Zoo *zoo = 0; } ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/testdata/SWObject.h0000644000175000017500000000020413026170313022331 0ustar onuronur@interface SWObject /** testFunc * * a detail description */ - (void)test:(int)arg1 withArg2:(int)arg2 withArg3:(int)arg3; @end ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/testdata/SWObject.m0000644000175000017500000000020413026170313022336 0ustar onuronur#import "SWObject.h" @implementation SWObject - (void)test { [self test:0 /*complete at here*/] } - /*complete at here*/ @end ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/testdata/basic.cpp0000644000175000017500000000026613026170313022275 0ustar onuronurstruct Foo { int x; //!< A docstring. int y; char c; int foobar() { return 5; } }; int main() { Foo foo; // The location after the dot is line 15, col 7 foo. } ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/IsUppercase_test.cpp0000644000175000017500000000224613026170313022665 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include "LetterNodeListMap.h" namespace YouCompleteMe { TEST( IsUppercaseTest, Basic ) { EXPECT_TRUE( IsUppercase( 'A' ) ); EXPECT_TRUE( IsUppercase( 'B' ) ); EXPECT_TRUE( IsUppercase( 'Z' ) ); EXPECT_FALSE( IsUppercase( 'a' ) ); EXPECT_FALSE( IsUppercase( 'b' ) ); EXPECT_FALSE( IsUppercase( 'z' ) ); EXPECT_FALSE( IsUppercase( '$' ) ); EXPECT_FALSE( IsUppercase( '@' ) ); EXPECT_FALSE( IsUppercase( '~' ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/IndexForLetter_test.cpp0000644000175000017500000000241613026170313023337 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include "LetterNodeListMap.h" namespace YouCompleteMe { TEST( IndexForLetterTest, Basic ) { EXPECT_EQ( static_cast( 'a' ), IndexForLetter( 'a' ) ); EXPECT_EQ( static_cast( 'a' ), IndexForLetter( 'A' ) ); EXPECT_EQ( static_cast( 'z' ), IndexForLetter( 'z' ) ); EXPECT_EQ( static_cast( 'z' ), IndexForLetter( 'Z' ) ); EXPECT_EQ( static_cast( '[' ), IndexForLetter( '[' ) ); EXPECT_EQ( static_cast( ' ' ), IndexForLetter( ' ' ) ); EXPECT_EQ( static_cast( '~' ), IndexForLetter( '~' ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/IdentifierUtils_test.cpp0000644000175000017500000000367613026170313023555 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "IdentifierUtils.h" #include "TestUtils.h" #include "IdentifierDatabase.h" #include #include #include namespace YouCompleteMe { namespace fs = boost::filesystem; using ::testing::ElementsAre; using ::testing::ContainerEq; using ::testing::WhenSorted; TEST( IdentifierUtilsTest, ExtractIdentifiersFromTagsFileWorks ) { fs::path root = fs::current_path().root_path(); fs::path testfile = PathToTestFile( "basic.tags" ); fs::path testfile_parent = testfile.parent_path(); FiletypeIdentifierMap expected; expected[ "cpp" ][ ( testfile_parent / "foo" ).string() ] .push_back( "i1" ); expected[ "cpp" ][ ( testfile_parent / "bar" ).string() ] .push_back( "i1" ); expected[ "cpp" ][ ( testfile_parent / "foo" ).string() ] .push_back( "foosy" ); expected[ "cpp" ][ ( testfile_parent / "bar" ).string() ] .push_back( "fooaaa" ); expected[ "c" ][ ( root / "foo" / "zoo" ).string() ].push_back( "Floo::goo" ); expected[ "c" ][ ( root / "foo" / "goo maa" ).string() ].push_back( "!goo" ); expected[ "cs" ][ ( root / "m_oo" ).string() ].push_back( "#bleh" ); EXPECT_THAT( ExtractIdentifiersFromTagsFile( testfile ), ContainerEq( expected ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/IdentifierCompleter_test.cpp0000644000175000017500000002405513026170313024401 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include #include "IdentifierCompleter.h" #include "Utils.h" #include "TestUtils.h" using ::testing::ElementsAre; using ::testing::IsEmpty; using ::testing::WhenSorted; namespace YouCompleteMe { // This differs from what we expect from the ClangCompleter. That one should // return results for an empty query. TEST( IdentifierCompleterTest, EmptyQueryNoResults ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar" ) ).CandidatesForQuery( "" ), IsEmpty() ); } TEST( IdentifierCompleterTest, NoDuplicatesReturned ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "foobar", "foobar" ) ).CandidatesForQuery( "foo" ), ElementsAre( "foobar" ) ); } TEST( IdentifierCompleterTest, OneCandidate ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "foobar" ) ); } TEST( IdentifierCompleterTest, ManyCandidateSimple ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "foobartest", "Foobartest" ) ).CandidatesForQuery( "fbr" ), WhenSorted( ElementsAre( "Foobartest", "foobar", "foobartest" ) ) ); } TEST( IdentifierCompleterTest, SmartCaseFiltering ) { EXPECT_THAT( IdentifierCompleter( StringVector( "fooBar", "fooBaR" ) ).CandidatesForQuery( "fBr" ), ElementsAre( "fooBaR", "fooBar" ) ); } TEST( IdentifierCompleterTest, FirstCharSameAsQueryWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "afoobar" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "foobar", "afoobar" ) ); } TEST( IdentifierCompleterTest, CompleteMatchForWordBoundaryCharsWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "FooBarQux", "FBaqux" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "FooBarQux", "FBaqux" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "CompleterTest", "CompleteMatchForWordBoundaryCharsWins" ) ) .CandidatesForQuery( "ct" ), ElementsAre( "CompleterTest", "CompleteMatchForWordBoundaryCharsWins" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "FooBar", "FooBarRux" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "FooBarRux", "FooBar" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "foo-bar", "foo-bar-rux" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "foo-bar-rux", "foo-bar" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "foo.bar", "foo.bar.rux" ) ).CandidatesForQuery( "fbr" ), ElementsAre( "foo.bar.rux", "foo.bar" ) ); } TEST( IdentifierCompleterTest, RatioUtilizationTieBreak ) { EXPECT_THAT( IdentifierCompleter( StringVector( "aGaaFooBarQux", "aBaafbq" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "aGaaFooBarQux", "aBaafbq" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "aFooBarQux", "afbq" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "aFooBarQux", "afbq" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "acaaCaaFooGxx", "aCaafoog" ) ).CandidatesForQuery( "caafoo" ), ElementsAre( "acaaCaaFooGxx", "aCaafoog" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "FooBarQux", "FooBarQuxZaa" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "FooBarQux", "FooBarQuxZaa" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "FooBar", "FooBarRux" ) ).CandidatesForQuery( "fba" ), ElementsAre( "FooBar", "FooBarRux" ) ); } TEST( IdentifierCompleterTest, QueryPrefixOfCandidateWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "fbaroo" ) ).CandidatesForQuery( "foo" ), ElementsAre( "foobar", "fbaroo" ) ); } TEST( IdentifierCompleterTest, LowerMatchCharIndexSumWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "ratio_of_word_boundary_chars_in_query_", "first_char_same_in_query_and_text_" ) ) .CandidatesForQuery( "charinq" ), ElementsAre( "first_char_same_in_query_and_text_", "ratio_of_word_boundary_chars_in_query_" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "barfooq", "barquxfoo" ) ).CandidatesForQuery( "foo" ), ElementsAre( "barfooq", "barquxfoo" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "xxxxxxabc", "xxabcxxxx" ) ).CandidatesForQuery( "abc" ), ElementsAre( "xxabcxxxx", "xxxxxxabc" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "FooBarQux", "FaBarQux" ) ).CandidatesForQuery( "fbq" ), ElementsAre( "FaBarQux", "FooBarQux" ) ); } TEST( IdentifierCompleterTest, ShorterCandidateWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "CompleterT", "CompleterTest" ) ).CandidatesForQuery( "co" ), ElementsAre( "CompleterT", "CompleterTest" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "CompleterT", "CompleterTest" ) ).CandidatesForQuery( "plet" ), ElementsAre( "CompleterT", "CompleterTest" ) ); } TEST( IdentifierCompleterTest, SameLowercaseCandidateWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "foobar", "Foobar" ) ).CandidatesForQuery( "foo" ), ElementsAre( "foobar", "Foobar" ) ); } TEST( IdentifierCompleterTest, PreferLowercaseCandidate ) { EXPECT_THAT( IdentifierCompleter( StringVector( "chatContentExtension", "ChatContentExtension" ) ).CandidatesForQuery( "chatContent" ), ElementsAre( "chatContentExtension", "ChatContentExtension" ) ); EXPECT_THAT( IdentifierCompleter( StringVector( "fooBar", "FooBar" ) ).CandidatesForQuery( "oba" ), ElementsAre( "fooBar", "FooBar" ) ); } TEST( IdentifierCompleterTest, ShorterAndLowercaseWins ) { EXPECT_THAT( IdentifierCompleter( StringVector( "STDIN_FILENO", "stdin" ) ).CandidatesForQuery( "std" ), ElementsAre( "stdin", "STDIN_FILENO" ) ); } TEST( IdentifierCompleterTest, NonAlnumChars ) { EXPECT_THAT( IdentifierCompleter( StringVector( "font-family", "font-face" ) ).CandidatesForQuery( "fo" ), ElementsAre( "font-face", "font-family" ) ); } TEST( IdentifierCompleterTest, NonAlnumStartChar ) { EXPECT_THAT( IdentifierCompleter( StringVector( "-zoo-foo" ) ).CandidatesForQuery( "-z" ), ElementsAre( "-zoo-foo" ) ); } TEST( IdentifierCompleterTest, EmptyCandidatesForUnicode ) { EXPECT_THAT( IdentifierCompleter( StringVector( "uni¢𐍈d€" ) ).CandidatesForQuery( "¢" ), IsEmpty() ); } TEST( IdentifierCompleterTest, EmptyCandidatesForNonPrintable ) { EXPECT_THAT( IdentifierCompleter( StringVector( "\x01\x1f\x7f" ) ).CandidatesForQuery( "\x1f" ), IsEmpty() ); } TEST( IdentifierCompleterTest, TagsEndToEndWorks ) { IdentifierCompleter completer; std::vector< std::string > tag_files; tag_files.push_back( PathToTestFile( "basic.tags" ).string() ); completer.AddIdentifiersToDatabaseFromTagFiles( tag_files ); EXPECT_THAT( completer.CandidatesForQueryAndType( "fo", "cpp" ), ElementsAre( "foosy", "fooaaa" ) ); } // TODO: tests for filepath and filetype candidate storing } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/LetterBitsetFromString_test.cpp0000644000175000017500000000417013026170313025065 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include "Candidate.h" namespace YouCompleteMe { TEST( LetterBitsetFromStringTest, Basic ) { Bitset expected; expected.set( IndexForLetter( 'a' ) ); expected.set( IndexForLetter( 'o' ) ); expected.set( IndexForLetter( 'c' ) ); expected.set( IndexForLetter( 'f' ) ); expected.set( IndexForLetter( 'b' ) ); std::string text = "abcfoof"; EXPECT_EQ( expected, LetterBitsetFromString( text ) ); } TEST( LetterBitsetFromStringTest, Boundaries ) { Bitset expected; // While the null character (0) is the lower bound, we cannot check it // because it is used to terminate a string. expected.set( IndexForLetter( 1 ) ); expected.set( IndexForLetter( 127 ) ); // \x01 is the start of heading character. // \x7f (127) is the delete character. // \x80 (-128) and \xff (-1) are out of ASCII characters range and are // ignored. std::string text = "\x01\x7f\x80\xff"; EXPECT_EQ( expected, LetterBitsetFromString( text ) ); } TEST( LetterBitsetFromStringTest, IgnoreNonAsciiCharacters ) { Bitset expected; expected.set( IndexForLetter( 'u' ) ); expected.set( IndexForLetter( 'n' ) ); expected.set( IndexForLetter( 'i' ) ); expected.set( IndexForLetter( 'd' ) ); // UTF-8 characters representation: // ¢: \xc2\xa2 // €: \xe2\x82\xac // 𐍈: \xf0\x90\x8d\x88 std::string text = "uni¢𐍈d€"; EXPECT_EQ( expected, LetterBitsetFromString( text ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/TestUtils.h0000644000175000017500000000326013026170313021005 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef TESTUTILS_H_G4RKMGUD #define TESTUTILS_H_G4RKMGUD #include #include #include namespace YouCompleteMe { std::vector< std::string > StringVector( const std::string &a, const std::string &b = std::string(), const std::string &c = std::string(), const std::string &d = std::string(), const std::string &e = std::string(), const std::string &f = std::string(), const std::string &g = std::string(), const std::string &h = std::string(), const std::string &i = std::string() ); boost::filesystem::path PathToTestFile( const std::string &filepath ); } // namespace YouCompleteMe #endif /* end of include guard: TESTUTILS_H_G4RKMGUD */ ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/main.cpp0000644000175000017500000000043613026170313020326 0ustar onuronur#include "gtest/gtest.h" #include "gmock/gmock.h" #include int main( int argc, char **argv ) { Py_Initialize(); // Necessary because of usage of the ReleaseGil class PyEval_InitThreads(); testing::InitGoogleMock( &argc, argv ); return RUN_ALL_TESTS(); } ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/LetterNode_test.cpp0000644000175000017500000000617213026170313022511 0ustar onuronur// Copyright (C) 2016 ycmd contributors // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include #include "LetterNode.h" namespace YouCompleteMe { using ::testing::AllOf; using ::testing::ElementsAre; using ::testing::IsNull; using ::testing::Property; using ::testing::StrEq; TEST( LetterNodeTest, AsciiText ) { LetterNode root_node( "ascIi_texT" ); EXPECT_THAT( root_node, AllOf( Property( &LetterNode::Index, -1 ), Property( &LetterNode::LetterIsUppercase, false ) ) ); const NearestLetterNodeIndices *nearest_nodes = root_node.NearestLetterNodesForLetter( 'i' ); EXPECT_THAT( root_node[ nearest_nodes->indexOfFirstOccurrence ], AllOf( Property( &LetterNode::Index, 3 ), Property( &LetterNode::LetterIsUppercase, true ) ) ); EXPECT_THAT( root_node[ nearest_nodes->indexOfFirstUppercaseOccurrence ], AllOf( Property( &LetterNode::Index, 3 ), Property( &LetterNode::LetterIsUppercase, true ) ) ); LetterNode *node = root_node[ nearest_nodes->indexOfFirstOccurrence ]; nearest_nodes = node->NearestLetterNodesForLetter( 'i' ); EXPECT_THAT( root_node[ nearest_nodes->indexOfFirstOccurrence ], AllOf( Property( &LetterNode::Index, 4 ), Property( &LetterNode::LetterIsUppercase, false ) ) ); EXPECT_EQ( nearest_nodes->indexOfFirstUppercaseOccurrence, -1 ); nearest_nodes = node->NearestLetterNodesForLetter( 't' ); EXPECT_THAT( root_node[ nearest_nodes->indexOfFirstOccurrence ], AllOf( Property( &LetterNode::Index, 6 ), Property( &LetterNode::LetterIsUppercase, false ) ) ); EXPECT_THAT( root_node[ nearest_nodes->indexOfFirstUppercaseOccurrence ], AllOf( Property( &LetterNode::Index, 9 ), Property( &LetterNode::LetterIsUppercase, true ) ) ); nearest_nodes = node->NearestLetterNodesForLetter( 'c' ); EXPECT_EQ( nearest_nodes->indexOfFirstOccurrence, -1 ); EXPECT_EQ( nearest_nodes->indexOfFirstUppercaseOccurrence, -1 ); } TEST( LetterNodeTest, ThrowOnNonAsciiCharacters ) { // UTF-8 characters representation: // ¢: \xc2\xa2 // €: \xe2\x82\xac // 𐍈: \xf0\x90\x8d\x88 ASSERT_THROW( LetterNode root_node( "uni¢𐍈d€" ), std::out_of_range ); try { LetterNode root_node( "uni¢𐍈d€" ); } catch ( std::out_of_range error ) { EXPECT_THAT( error.what(), StrEq( "array<>: index out of range" ) ); } } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/cmake/0000755000175000017500000000000013026170313017753 5ustar onuronurycmd-0+20161219+git486b809.orig/cpp/ycm/tests/cmake/FindGMock.cmake0000644000175000017500000001077713026170313022572 0ustar onuronur# Locate the Google C++ Mocking Framework. # (This file is almost an identical copy of the original FindGTest.cmake file, # feel free to use it as it is or modify it for your own needs.) # # # Defines the following variables: # # GMOCK_FOUND - Found the Google Testing framework # GMOCK_INCLUDE_DIRS - Include directories # # Also defines the library variables below as normal # variables. These contain debug/optimized keywords when # a debugging library is found. # # GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock-main # GMOCK_LIBRARIES - libgmock # GMOCK_MAIN_LIBRARIES - libgmock-main # # Accepts the following variables as input: # # GMOCK_ROOT - (as a CMake or environment variable) # The root directory of the gmock install prefix # # GMOCK_MSVC_SEARCH - If compiling with MSVC, this variable can be set to # "MD" or "MT" to enable searching a gmock build tree # (defaults: "MD") # #----------------------- # Example Usage: # # find_package(GMock REQUIRED) # include_directories(${GMOCK_INCLUDE_DIRS}) # # add_executable(foo foo.cc) # target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES}) # #============================================================================= # This file is released under the MIT licence: # # Copyright (c) 2011 Matej Svec # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. #============================================================================= function( _gmock_append_debugs _endvar _library ) if( ${_library} AND ${_library}_DEBUG ) set( _output optimized ${${_library}} debug ${${_library}_DEBUG} ) else() set( _output ${${_library}} ) endif() set( ${_endvar} ${_output} PARENT_SCOPE ) endfunction() function( _gmock_find_library _name ) find_library( ${_name} NAMES ${ARGN} HINTS $ENV{GMOCK_ROOT} ${GMOCK_ROOT} PATH_SUFFIXES ${_gmock_libpath_suffixes} ) mark_as_advanced( ${_name} ) endfunction() if( NOT DEFINED GMOCK_MSVC_SEARCH ) set( GMOCK_MSVC_SEARCH MD ) endif() set( _gmock_libpath_suffixes lib ) if( MSVC ) if( GMOCK_MSVC_SEARCH STREQUAL "MD" ) list( APPEND _gmock_libpath_suffixes msvc/gmock-md/Debug msvc/gmock-md/Release ) elseif( GMOCK_MSVC_SEARCH STREQUAL "MT" ) list( APPEND _gmock_libpath_suffixes msvc/gmock/Debug msvc/gmock/Release ) endif() endif() find_path( GMOCK_INCLUDE_DIR gmock/gmock.h HINTS $ENV{GMOCK_ROOT}/include ${GMOCK_ROOT}/include ) mark_as_advanced( GMOCK_INCLUDE_DIR ) if( MSVC AND GMOCK_MSVC_SEARCH STREQUAL "MD" ) # The provided /MD project files for Google Mock add -md suffixes to the # library names. _gmock_find_library( GMOCK_LIBRARY gmock-md gmock ) _gmock_find_library( GMOCK_LIBRARY_DEBUG gmock-mdd gmockd ) _gmock_find_library( GMOCK_MAIN_LIBRARY gmock_main-md gmock_main ) _gmock_find_library( GMOCK_MAIN_LIBRARY_DEBUG gmock_main-mdd gmock_maind ) else() _gmock_find_library( GMOCK_LIBRARY gmock ) _gmock_find_library( GMOCK_LIBRARY_DEBUG gmockd ) _gmock_find_library( GMOCK_MAIN_LIBRARY gmock_main ) _gmock_find_library( GMOCK_MAIN_LIBRARY_DEBUG gmock_maind ) endif() FIND_PACKAGE_HANDLE_STANDARD_ARGS( GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR GMOCK_MAIN_LIBRARY ) if( GMOCK_FOUND ) set( GMOCK_INCLUDE_DIRS ${GMOCK_INCLUDE_DIR} ) _gmock_append_debugs( GMOCK_LIBRARIES GMOCK_LIBRARY ) _gmock_append_debugs( GMOCK_MAIN_LIBRARIES GMOCK_MAIN_LIBRARY ) set( GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARIES} ${GMOCK_MAIN_LIBRARIES} ) endif() ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/Candidate_test.cpp0000644000175000017500000002556613026170313022330 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include "Candidate.h" #include "Result.h" namespace YouCompleteMe { TEST( GetWordBoundaryCharsTest, SimpleOneWord ) { EXPECT_EQ( "s", GetWordBoundaryChars( "simple" ) ); } TEST( GetWordBoundaryCharsTest, PunctuationInMiddle ) { EXPECT_EQ( "sf", GetWordBoundaryChars( "simple_foo" ) ); } TEST( GetWordBoundaryCharsTest, PunctuationStart ) { EXPECT_EQ( "s", GetWordBoundaryChars( "_simple" ) ); EXPECT_EQ( "s", GetWordBoundaryChars( ".simple" ) ); EXPECT_EQ( "s", GetWordBoundaryChars( "/simple" ) ); EXPECT_EQ( "s", GetWordBoundaryChars( ":simple" ) ); EXPECT_EQ( "s", GetWordBoundaryChars( "-simple" ) ); } TEST( GetWordBoundaryCharsTest, PunctuationStartButFirstDigit ) { EXPECT_EQ( "", GetWordBoundaryChars( "_1simple" ) ); EXPECT_EQ( "p", GetWordBoundaryChars( "_1simPle" ) ); } TEST( GetWordBoundaryCharsTest, ManyPunctuationStart ) { EXPECT_EQ( "s", GetWordBoundaryChars( "___simple" ) ); EXPECT_EQ( "s", GetWordBoundaryChars( ".;/simple" ) ); } TEST( GetWordBoundaryCharsTest, PunctuationStartAndInMiddle ) { EXPECT_EQ( "sf", GetWordBoundaryChars( "_simple_foo" ) ); EXPECT_EQ( "sf", GetWordBoundaryChars( "/simple.foo" ) ); } TEST( GetWordBoundaryCharsTest, ManyPunctuationStartAndInMiddle ) { EXPECT_EQ( "sf", GetWordBoundaryChars( "___simple__foo" ) ); EXPECT_EQ( "sf", GetWordBoundaryChars( "./;:simple..foo" ) ); } TEST( GetWordBoundaryCharsTest, SimpleCapitalStart ) { EXPECT_EQ( "s", GetWordBoundaryChars( "Simple" ) ); } TEST( GetWordBoundaryCharsTest, SimpleCapitalTwoWord ) { EXPECT_EQ( "ss", GetWordBoundaryChars( "SimpleStuff" ) ); } TEST( GetWordBoundaryCharsTest, SimpleCapitalTwoWordPunctuationMiddle ) { EXPECT_EQ( "ss", GetWordBoundaryChars( "Simple_Stuff" ) ); } TEST( GetWordBoundaryCharsTest, JavaCase ) { EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleStuffFoo" ) ); } TEST( GetWordBoundaryCharsTest, UppercaseSequence ) { EXPECT_EQ( "ss", GetWordBoundaryChars( "simpleSTUFF" ) ); } TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddle ) { EXPECT_EQ( "ss", GetWordBoundaryChars( "simpleSTUFFfoo" ) ); } TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddlePunctuation ) { EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF_Foo" ) ); } TEST( GetWordBoundaryCharsTest, UppercaseSequenceInMiddlePunctuationLowercase ) { EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF_foo" ) ); EXPECT_EQ( "ssf", GetWordBoundaryChars( "simpleSTUFF.foo" ) ); } TEST( GetWordBoundaryCharsTest, AllCapsSimple ) { EXPECT_EQ( "s", GetWordBoundaryChars( "SIMPLE" ) ); } TEST( GetWordBoundaryCharsTest, AllCapsPunctuationStart ) { EXPECT_EQ( "s", GetWordBoundaryChars( "_SIMPLE" ) ); EXPECT_EQ( "s", GetWordBoundaryChars( ".SIMPLE" ) ); } TEST( GetWordBoundaryCharsTest, AllCapsPunctuationMiddle ) { EXPECT_EQ( "ss", GetWordBoundaryChars( "SIMPLE_STUFF" ) ); EXPECT_EQ( "ss", GetWordBoundaryChars( "SIMPLE/STUFF" ) ); } TEST( GetWordBoundaryCharsTest, AllCapsPunctuationMiddleAndStart ) { EXPECT_EQ( "ss", GetWordBoundaryChars( "_SIMPLE_STUFF" ) ); EXPECT_EQ( "ss", GetWordBoundaryChars( ":SIMPLE.STUFF" ) ); } TEST( CandidateTest, TextValid ) { std::string text = "foo"; Candidate candidate( text ); EXPECT_EQ( text, candidate.Text() ); } TEST( CandidateTest, MatchesQueryBitsetWhenMatch ) { Candidate candidate( "foobaaar" ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "foobaaar" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "fobar" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "rabof" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "bfroa" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "fbr" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "r" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "bbb" ) ) ); EXPECT_TRUE( candidate.MatchesQueryBitset( LetterBitsetFromString( "" ) ) ); } TEST( CandidateTest, DoesntMatchQueryBitset ) { Candidate candidate( "foobar" ); EXPECT_FALSE( candidate.MatchesQueryBitset( LetterBitsetFromString( "foobare" ) ) ); EXPECT_FALSE( candidate.MatchesQueryBitset( LetterBitsetFromString( "gggg" ) ) ); EXPECT_FALSE( candidate.MatchesQueryBitset( LetterBitsetFromString( "x" ) ) ); EXPECT_FALSE( candidate.MatchesQueryBitset( LetterBitsetFromString( "nfoobar" ) ) ); EXPECT_FALSE( candidate.MatchesQueryBitset( LetterBitsetFromString( "fbrmmm" ) ) ); } TEST( CandidateTest, QueryMatchResultCaseInsensitiveIsSubsequence ) { Candidate candidate( "foobaaar" ); EXPECT_TRUE( candidate.QueryMatchResult( "foobaaar", false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "foOBAaar", false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "FOOBAAAR", false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "fobar" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "fbr" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "f" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "F" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "o" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "O" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "a" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "r" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "b" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "bar" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "oa" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "obr" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "oar" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "oo" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "aaa" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "AAA" , false ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "" , false ).IsSubsequence() ); } TEST( CandidateTest, QueryMatchResultCaseInsensitiveIsntSubsequence ) { Candidate candidate( "foobaaar" ); EXPECT_FALSE( candidate.QueryMatchResult( "foobra" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "frb" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "brf" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "x" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "9" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "-" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "~" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( " " , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "rabof" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "oabfr" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "ooo" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "baaara" , false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "ffoobaaar", false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "xfoobaaar", false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( " foobaaar", false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "foobaaar ", false ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "ff" , false ).IsSubsequence() ); } TEST( CandidateTest, QueryMatchResultCaseSensitiveIsSubsequence ) { Candidate candidate( "FooBaAAr" ); EXPECT_TRUE( candidate.QueryMatchResult( "FooBaAAr", true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "FBAA" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "F" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "AA" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "A" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "B" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "foobaaar", true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "foobaAAr", true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "fbAA" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "fbaa" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "b" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "f" , true ).IsSubsequence() ); EXPECT_TRUE( candidate.QueryMatchResult( "fbar" , true ).IsSubsequence() ); } TEST( CandidateTest, QueryMatchResultCaseSensitiveIsntSubsequence ) { Candidate candidate( "FooBaAAr" ); EXPECT_FALSE( candidate.QueryMatchResult( "goo" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "R" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "O" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "OO" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "OBA" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "FBAR" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "FBAAR" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "Oar" , true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "FooBAAAr", true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "FOoBaAAr", true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "FOobaaar", true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "fOobaaar", true ).IsSubsequence() ); EXPECT_FALSE( candidate.QueryMatchResult( "foobaaaR", true ).IsSubsequence() ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/tests/CandidateRepository_test.cpp0000644000175000017500000000464113026170313024417 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include #include "CandidateRepository.h" #include "Candidate.h" #include "Result.h" namespace YouCompleteMe { TEST( CandidateRepositoryTest, Basic ) { std::vector< std::string > inputs; inputs.push_back( "foobar" ); CandidateRepository &repo = CandidateRepository::Instance(); std::vector< const Candidate * > candidates = repo.GetCandidatesForStrings( inputs ); EXPECT_EQ( "foobar", candidates[ 0 ]->Text() ); } TEST( CandidateRepositoryTest, TooLongCandidateSkipped ) { std::vector< std::string > inputs; inputs.push_back( std::string( 81, 'a' ) ); // this one is too long inputs.push_back( std::string( 80, 'b' ) ); // this one is *just* right CandidateRepository &repo = CandidateRepository::Instance(); std::vector< const Candidate * > candidates = repo.GetCandidatesForStrings( inputs ); EXPECT_EQ( "", candidates[ 0 ]->Text() ); EXPECT_EQ( 'b', candidates[ 1 ]->Text()[ 0 ] ); } TEST( CandidateRepositoryTest, EmptyCandidatesForUnicode ) { std::vector< std::string > inputs; inputs.push_back( "fooδιακριτικός" ); inputs.push_back( "fooδιακός" ); CandidateRepository &repo = CandidateRepository::Instance(); std::vector< const Candidate * > candidates = repo.GetCandidatesForStrings( inputs ); EXPECT_EQ( "", candidates[ 0 ]->Text() ); EXPECT_EQ( "", candidates[ 1 ]->Text() ); } TEST( CandidateRepositoryTest, EmptyCandidatesForNonPrintable ) { std::vector< std::string > inputs; inputs.push_back( "\x01\x05\x0a\x15" ); CandidateRepository &repo = CandidateRepository::Instance(); std::vector< const Candidate * > candidates = repo.GetCandidatesForStrings( inputs ); EXPECT_EQ( "", candidates[ 0 ]->Text() ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/IdentifierUtils.h0000644000175000017500000000217113026170313021006 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef IDENTIFIERUTILS_CPP_WFFUZNET #define IDENTIFIERUTILS_CPP_WFFUZNET #include "DLLDefines.h" #include "IdentifierDatabase.h" #include #include #include namespace YouCompleteMe { YCM_DLL_EXPORT FiletypeIdentifierMap ExtractIdentifiersFromTagsFile( const boost::filesystem::path &path_to_tag_file ); } // namespace YouCompleteMe #endif /* end of include guard: IDENTIFIERUTILS_CPP_WFFUZNET */ ycmd-0+20161219+git486b809.orig/cpp/ycm/versioning.cpp0000644000175000017500000000147513026170313020427 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "versioning.h" namespace YouCompleteMe { int YcmCoreVersion() { return YCMD_CORE_VERSION; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/DLLDefines.h0000644000175000017500000000212413026170313017612 0ustar onuronur// Copyright (C) 2015 ycmd contributors // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef DLLDEFINES_H_0IYA3AQ3 #define DLLDEFINES_H_0IYA3AQ3 // We need to export symbols for gmock tests on Windows. The preprocessor // symbol ycm_core_EXPORTS is defined by CMake when building a shared library. #if defined( _WIN32 ) && defined( ycm_core_EXPORTS ) #define YCM_DLL_EXPORT __declspec( dllexport ) #else #define YCM_DLL_EXPORT #endif #endif /* end of include guard: DLLDEFINES_H_0IYA3AQ3 */ ycmd-0+20161219+git486b809.orig/cpp/ycm/LetterNode.cpp0000644000175000017500000000367513026170313020315 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "LetterNode.h" #include "standard.h" namespace YouCompleteMe { LetterNode::LetterNode( char letter, int index ) : index_( index ), is_uppercase_( IsUppercase( letter ) ) { } LetterNode::LetterNode( const std::string &text ) : index_( -1 ), is_uppercase_( false ) { letternode_per_text_index_.reserve( text.size() ); for ( uint i = 0; i < text.size(); ++i ) { letternode_per_text_index_.push_back( LetterNode( text[ i ], i ) ); SetNodeIndexForLetterIfNearest( text[ i ], i ); } for ( size_t i = 0; i < text.size(); ++i ) { for ( size_t j = i + 1; j < text.size(); ++j ) { letternode_per_text_index_[ i ].SetNodeIndexForLetterIfNearest( text[ j ], j ); } } } void LetterNode::SetNodeIndexForLetterIfNearest( char letter, short index ) { NearestLetterNodeIndices& currentLetterNodeIndices = letters_[ letter ]; if ( IsUppercase( letter ) ) { if ( currentLetterNodeIndices.indexOfFirstUppercaseOccurrence == -1 ) currentLetterNodeIndices.indexOfFirstUppercaseOccurrence = index; } if ( currentLetterNodeIndices.indexOfFirstOccurrence == -1 ) currentLetterNodeIndices.indexOfFirstOccurrence = index; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/ReleaseGil.h0000644000175000017500000000211313026170313017713 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef RELEASEGIL_H_RDIEBSQ1 #define RELEASEGIL_H_RDIEBSQ1 #include namespace YouCompleteMe { class ReleaseGil { public: ReleaseGil() { thread_state_ = PyEval_SaveThread(); } ~ReleaseGil() { PyEval_RestoreThread( thread_state_ ); } private: PyThreadState *thread_state_; }; } // namespace YouCompleteMe #endif /* end of include guard: RELEASEGIL_H_RDIEBSQ1 */ ycmd-0+20161219+git486b809.orig/cpp/ycm/PythonSupport.h0000644000175000017500000000312413026170313020560 0ustar onuronur// Copyright (C) 2011, 2012, 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef PYTHONSUPPORT_H_KWGFEX0V #define PYTHONSUPPORT_H_KWGFEX0V #include namespace YouCompleteMe { /// Given a list of python objects (that represent completion candidates) in a /// python list |candidates|, a |candidate_property| on which to filter and sort /// the candidates and a user query, returns a new sorted python list with the /// original objects that survived the filtering. boost::python::list FilterAndSortCandidates( const boost::python::list &candidates, const std::string &candidate_property, const std::string &query ); /// Given a Python object that's supposed to be "string-like", returns a UTF-8 /// encoded std::string. If the object can't be converted to a string, returns an /// empty one. std::string GetUtf8String( const boost::python::object &string_or_unicode ); } // namespace YouCompleteMe #endif /* end of include guard: PYTHONSUPPORT_H_KWGFEX0V */ ycmd-0+20161219+git486b809.orig/cpp/ycm/.ycm_extra_conf.py0000644000175000017500000001430413026170313021163 0ustar onuronur# This file is NOT licensed under the GPLv3, which is the license for the rest # of YouCompleteMe. # # Here's the license text for this file: # # This is free and unencumbered software released into the public domain. # # Anyone is free to copy, modify, publish, use, compile, sell, or # distribute this software, either in source code form or as a compiled # binary, for any purpose, commercial or non-commercial, and by any # means. # # In jurisdictions that recognize copyright laws, the author or authors # of this software dedicate any and all copyright interest in the # software to the public domain. We make this dedication for the benefit # of the public at large and to the detriment of our heirs and # successors. We intend this dedication to be an overt act of # relinquishment in perpetuity of all present and future rights to this # software under copyright law. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # # For more information, please refer to import os import ycm_core # These are the compilation flags that will be used in case there's no # compilation database set (by default, one is not set). # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. flags = [ '-Wall', '-Wextra', '-Werror', '-Wc++98-compat', '-Wno-long-long', '-Wno-variadic-macros', '-fexceptions', '-DNDEBUG', # You 100% do NOT need -DUSE_CLANG_COMPLETER in your flags; only the YCM # source code needs it. '-DUSE_CLANG_COMPLETER', # THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which # language to use when compiling headers. So it will guess. Badly. So C++ # headers will be compiled as C headers. You don't want that so ALWAYS specify # a "-std=". # For a C project, you would set this to something like 'c99' instead of # 'c++11'. '-std=c++11', # ...and the same thing goes for the magic -x option which specifies the # language that the files to be compiled are written in. This is mostly # relevant for c++ headers. # For a C project, you would set this to 'c' instead of 'c++'. '-x', 'c++', '-isystem', '../BoostParts', '-isystem', # This path will only work on OS X, but extra paths that don't exist are not # harmful '/System/Library/Frameworks/Python.framework/Headers', '-isystem', '../llvm/include', '-isystem', '../llvm/tools/clang/include', '-I', '.', '-I', './ClangCompleter', '-isystem', './tests/gmock/gtest', '-isystem', './tests/gmock/gtest/include', '-isystem', './tests/gmock', '-isystem', './tests/gmock/include', ] # Set this to the absolute path to the folder (NOT the file!) containing the # compile_commands.json file to use that instead of 'flags'. See here for # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html # # You can get CMake to generate this file for you by adding: # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) # to your CMakeLists.txt file. # # Most projects will NOT need to set this to anything; you can just change the # 'flags' list of compilation flags. Notice that YCM itself uses that approach. compilation_database_folder = '' if os.path.exists( compilation_database_folder ): database = ycm_core.CompilationDatabase( compilation_database_folder ) else: database = None SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] def DirectoryOfThisScript(): return os.path.dirname( os.path.abspath( __file__ ) ) def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): if not working_directory: return list( flags ) new_flags = [] make_next_absolute = False path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] for flag in flags: new_flag = flag if make_next_absolute: make_next_absolute = False if not flag.startswith( '/' ): new_flag = os.path.join( working_directory, flag ) for path_flag in path_flags: if flag == path_flag: make_next_absolute = True break if flag.startswith( path_flag ): path = flag[ len( path_flag ): ] new_flag = path_flag + os.path.join( working_directory, path ) break if new_flag: new_flags.append( new_flag ) return new_flags def IsHeaderFile( filename ): extension = os.path.splitext( filename )[ 1 ] return extension in [ '.h', '.hxx', '.hpp', '.hh' ] def GetCompilationInfoForFile( filename ): # The compilation_commands.json file generated by CMake does not have entries # for header files. So we do our best by asking the db for flags for a # corresponding source file, if any. If one exists, the flags for that file # should be good enough. if IsHeaderFile( filename ): basename = os.path.splitext( filename )[ 0 ] for extension in SOURCE_EXTENSIONS: replacement_file = basename + extension if os.path.exists( replacement_file ): compilation_info = database.GetCompilationInfoForFile( replacement_file ) if compilation_info.compiler_flags_: return compilation_info return None return database.GetCompilationInfoForFile( filename ) def FlagsForFile( filename, **kwargs ): if database: # Bear in mind that compilation_info.compiler_flags_ does NOT return a # python list, but a "list-like" StringVec object compilation_info = GetCompilationInfoForFile( filename ) if not compilation_info: return None final_flags = MakeRelativePathsInFlagsAbsolute( compilation_info.compiler_flags_, compilation_info.compiler_working_dir_ ) # NOTE: This is just for YouCompleteMe; it's highly likely that your project # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. try: final_flags.remove( '-stdlib=libc++' ) except ValueError: pass else: relative_to = DirectoryOfThisScript() final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) return { 'flags': final_flags } ycmd-0+20161219+git486b809.orig/cpp/ycm/PythonSupport.cpp0000644000175000017500000000725213026170313021121 0ustar onuronur// Copyright (C) 2011, 2012, 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "PythonSupport.h" #include "standard.h" #include "Result.h" #include "Candidate.h" #include "CandidateRepository.h" #include "ReleaseGil.h" #include #include #include using boost::algorithm::any_of; using boost::algorithm::is_upper; using boost::python::len; using boost::python::str; using boost::python::extract; using boost::python::object; typedef boost::python::list pylist; namespace YouCompleteMe { namespace { std::vector< const Candidate * > CandidatesFromObjectList( const pylist &candidates, const std::string &candidate_property ) { int num_candidates = len( candidates ); std::vector< std::string > candidate_strings; candidate_strings.reserve( num_candidates ); for ( int i = 0; i < num_candidates; ++i ) { if ( candidate_property.empty() ) { candidate_strings.push_back( GetUtf8String( candidates[ i ] ) ); } else { object holder = extract< object >( candidates[ i ] ); candidate_strings.push_back( GetUtf8String( holder[ candidate_property.c_str() ] ) ); } } return CandidateRepository::Instance().GetCandidatesForStrings( candidate_strings ); } } // unnamed namespace boost::python::list FilterAndSortCandidates( const boost::python::list &candidates, const std::string &candidate_property, const std::string &query ) { pylist filtered_candidates; if ( query.empty() ) return candidates; if ( !IsPrintable( query ) ) return boost::python::list(); int num_candidates = len( candidates ); std::vector< const Candidate * > repository_candidates = CandidatesFromObjectList( candidates, candidate_property ); std::vector< ResultAnd< int > > result_and_objects; { ReleaseGil unlock; Bitset query_bitset = LetterBitsetFromString( query ); bool query_has_uppercase_letters = any_of( query, is_upper() ); for ( int i = 0; i < num_candidates; ++i ) { const Candidate *candidate = repository_candidates[ i ]; if ( !candidate->MatchesQueryBitset( query_bitset ) ) continue; Result result = candidate->QueryMatchResult( query, query_has_uppercase_letters ); if ( result.IsSubsequence() ) { ResultAnd< int > result_and_object( result, i ); result_and_objects.push_back( boost::move( result_and_object ) ); } } std::sort( result_and_objects.begin(), result_and_objects.end() ); } foreach ( const ResultAnd< int > &result_and_object, result_and_objects ) { filtered_candidates.append( candidates[ result_and_object.extra_object_ ] ); } return filtered_candidates; } std::string GetUtf8String( const boost::python::object &string_or_unicode ) { extract< std::string > to_string( string_or_unicode ); if ( to_string.check() ) return to_string(); return extract< std::string >( str( string_or_unicode ).encode( "utf8" ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/LetterNodeListMap.cpp0000644000175000017500000000331013026170313021571 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "LetterNodeListMap.h" #include "standard.h" #include namespace YouCompleteMe { bool IsUppercase( char letter ) { return 'A' <= letter && letter <= 'Z'; } bool IsInAsciiRange( int index ) { return 0 <= index && index < NUM_LETTERS; } int IndexForLetter( char letter ) { if ( IsUppercase( letter ) ) return letter + ( 'a' - 'A' ); return letter; } LetterNodeListMap::LetterNodeListMap() { } LetterNodeListMap::LetterNodeListMap( const LetterNodeListMap &other ) { if ( other.letters_ ) letters_.reset( new NearestLetterNodeArray( *other.letters_ ) ); } NearestLetterNodeIndices &LetterNodeListMap::operator[] ( char letter ) { if ( !letters_ ) letters_.reset( new NearestLetterNodeArray() ); int letter_index = IndexForLetter( letter ); return letters_->at( letter_index ); } NearestLetterNodeIndices *LetterNodeListMap::ListPointerAt( char letter ) { if ( !letters_ ) return NULL; return &letters_->at( IndexForLetter( letter ) ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/Utils.h0000644000175000017500000000466313026170313017013 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef UTILS_H_KEPMRPBH #define UTILS_H_KEPMRPBH #include "DLLDefines.h" #include #include #include namespace fs = boost::filesystem; namespace YouCompleteMe { bool AlmostEqual( double a, double b ); // Reads the entire contents of the specified file. If the file does not exist, // an exception is thrown. std::string ReadUtf8File( const fs::path &filepath ); // Writes the entire contents of the specified file. If the file does not exist, // an exception is thrown. YCM_DLL_EXPORT void WriteUtf8File( const fs::path &filepath, const std::string &contents ); template typename Container::mapped_type & GetValueElseInsert( Container &container, const Key &key, const typename Container::mapped_type &value ) { return container.insert( typename Container::value_type( key, value ) ) .first->second; } template bool ContainsKey( Container &container, const Key &key ) { return container.find( key ) != container.end(); } template typename Container::mapped_type FindWithDefault( Container &container, const Key &key, const typename Container::mapped_type &value ) { typename Container::const_iterator it = container.find( key ); return it != container.end() ? it->second : value; } template bool Erase( Container &container, const Key &key ) { typename Container::iterator it = container.find( key ); if ( it != container.end() ) { container.erase( it ); return true; } return false; } } // namespace YouCompleteMe #endif /* end of include guard: UTILS_H_KEPMRPBH */ ycmd-0+20161219+git486b809.orig/cpp/ycm/exceptions.h0000644000175000017500000000256413026170313020072 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef EXCEPTIONS_H_3PHJ9YOB #define EXCEPTIONS_H_3PHJ9YOB #include namespace YouCompleteMe { #define boost_throw(x) BOOST_THROW_EXCEPTION(x) // YouCompleteMe uses the "Exception types as semantic tags" idiom. // For more information, see this link: // http://www.boost.org/doc/libs/1_50_0/libs/exception/doc/exception_types_as_simple_semantic_tags.html /** * The common base for all exceptions. */ struct ExceptionBase: virtual std::exception, virtual boost::exception {}; /** * Thrown when a file does not exist. */ struct ClangParseError : virtual ExceptionBase {}; } // namespace YouCompleteMe #endif /* end of include guard: EXCEPTIONS_H_3PHJ9YOB */ ycmd-0+20161219+git486b809.orig/cpp/ycm/CandidateRepository.h0000644000175000017500000000444413026170313021664 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef CANDIDATEREPOSITORY_H_K9OVCMHG #define CANDIDATEREPOSITORY_H_K9OVCMHG #include "DLLDefines.h" #include #include #include #include #include namespace YouCompleteMe { class Candidate; struct CompletionData; typedef boost::unordered_map< std::string, const Candidate * > CandidateHolder; // This singleton stores already built Candidate objects for candidate strings // that were already seen. If Candidates are requested for previously unseen // strings, new Candidate objects are built. // // This is shared by the identifier completer and the clang completer so that // work is not repeated. // // This class is thread-safe. class CandidateRepository : boost::noncopyable { public: YCM_DLL_EXPORT static CandidateRepository &Instance(); int NumStoredCandidates(); YCM_DLL_EXPORT std::vector< const Candidate * > GetCandidatesForStrings( const std::vector< std::string > &strings ); #ifdef USE_CLANG_COMPLETER std::vector< const Candidate * > GetCandidatesForStrings( const std::vector< CompletionData > &datas ); #endif // USE_CLANG_COMPLETER private: CandidateRepository() {}; ~CandidateRepository(); const std::string &ValidatedCandidateText( const std::string &text ); boost::mutex holder_mutex_; static boost::mutex singleton_mutex_; static CandidateRepository *instance_; const std::string empty_; // This data structure owns all the Candidate pointers CandidateHolder candidate_holder_; }; } // namespace YouCompleteMe #endif /* end of include guard: CANDIDATEREPOSITORY_H_K9OVCMHG */ ycmd-0+20161219+git486b809.orig/cpp/ycm/Utils.cpp0000644000175000017500000000316513026170313017342 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "Utils.h" #include #include #include #include namespace fs = boost::filesystem; namespace YouCompleteMe { bool AlmostEqual( double a, double b ) { return std::abs( a - b ) <= ( std::numeric_limits< double >::epsilon() * std::max( std::abs( a ), std::abs( b ) ) ); } std::string ReadUtf8File( const fs::path &filepath ) { fs::ifstream file( filepath, std::ios::in | std::ios::binary ); std::vector< char > contents( ( std::istreambuf_iterator< char >( file ) ), std::istreambuf_iterator< char >() ); if ( contents.size() == 0 ) return std::string(); return std::string( contents.begin(), contents.end() ); } void WriteUtf8File( const fs::path &filepath, const std::string &contents ) { fs::ofstream file; file.open( filepath ); file << contents; file.close(); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/IdentifierUtils.cpp0000644000175000017500000001257713026170313021354 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "IdentifierUtils.h" #include "Utils.h" #include "standard.h" #include #include #include #include namespace YouCompleteMe { namespace fs = boost::filesystem; namespace { // For details on the tag format supported, see here for details: // http://ctags.sourceforge.net/FORMAT // TL;DR: The only supported format is the one Exuberant Ctags emits. const char *const TAG_REGEX = "^([^\\t\\n\\r]+)" // The first field is the identifier "\\t" // A TAB char is the field separator // The second field is the path to the file that has the identifier; either // absolute or relative to the tags file. "([^\\t\\n\\r]+)" "\\t.*?" // Non-greedy everything "language:([^\\t\\n\\r]+)" // We want to capture the language of the file ".*?$"; // Only used as the equality comparer for the below unordered_map which stores // const char* pointers and not std::string but needs to hash based on string // values and not pointer values. // When passed a const char* this will create a temporary std::string for // comparison, but it's fast enough for our use case. struct StringEqualityComparer : std::binary_function< std::string, std::string, bool > { bool operator()( const std::string &a, const std::string &b ) const { return a == b; } }; // List of languages Exuberant Ctags supports: // ctags --list-languages // To map a language name to a filetype, see this file: // :e $VIMRUNTIME/filetype.vim // This is a map of const char* and not std::string to prevent issues with // static initialization. const boost::unordered_map < const char *, const char *, boost::hash< std::string >, StringEqualityComparer > LANG_TO_FILETYPE = boost::assign::map_list_of ( "Ant" , "ant" ) ( "Asm" , "asm" ) ( "Awk" , "awk" ) ( "Basic" , "basic" ) ( "C++" , "cpp" ) ( "C#" , "cs" ) ( "C" , "c" ) ( "COBOL" , "cobol" ) ( "DosBatch" , "dosbatch" ) ( "Eiffel" , "eiffel" ) ( "Elixir" , "elixir" ) ( "Erlang" , "erlang" ) ( "Fortran" , "fortran" ) ( "Go" , "go" ) ( "HTML" , "html" ) ( "Java" , "java" ) ( "JavaScript" , "javascript" ) ( "Lisp" , "lisp" ) ( "Lua" , "lua" ) ( "Make" , "make" ) ( "MatLab" , "matlab" ) ( "OCaml" , "ocaml" ) ( "Pascal" , "pascal" ) ( "Perl" , "perl" ) ( "PHP" , "php" ) ( "Python" , "python" ) ( "REXX" , "rexx" ) ( "Ruby" , "ruby" ) ( "Scheme" , "scheme" ) ( "Sh" , "sh" ) ( "SLang" , "slang" ) ( "SML" , "sml" ) ( "SQL" , "sql" ) ( "Tcl" , "tcl" ) ( "Tex" , "tex" ) ( "Vera" , "vera" ) ( "Verilog" , "verilog" ) ( "VHDL" , "vhdl" ) ( "Vim" , "vim" ) ( "YACC" , "yacc" ); const char *const NOT_FOUND = "YCMFOOBAR_NOT_FOUND"; } // unnamed namespace FiletypeIdentifierMap ExtractIdentifiersFromTagsFile( const fs::path &path_to_tag_file ) { FiletypeIdentifierMap filetype_identifier_map; std::string tags_file_contents; try { tags_file_contents = ReadUtf8File( path_to_tag_file ); } catch ( ... ) { return filetype_identifier_map; } std::string::const_iterator start = tags_file_contents.begin(); std::string::const_iterator end = tags_file_contents.end(); boost::smatch matches; const boost::regex expression( TAG_REGEX ); const boost::match_flag_type options = boost::match_not_dot_newline; while ( boost::regex_search( start, end, matches, expression, options ) ) { start = matches[ 0 ].second; std::string language( matches[ 3 ] ); std::string filetype = FindWithDefault( LANG_TO_FILETYPE, language.c_str(), NOT_FOUND ); if ( filetype == NOT_FOUND ) continue; std::string identifier( matches[ 1 ] ); fs::path path( matches[ 2 ].str() ); path = fs::absolute( path, path_to_tag_file.parent_path() ) .make_preferred(); filetype_identifier_map[ filetype ][ path.string() ].push_back( identifier ); } return filetype_identifier_map; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/standard.h0000644000175000017500000000152513026170313017505 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include // We're most definitely not going to use // it as BOOST_FOREACH. #define foreach BOOST_FOREACH typedef unsigned int uint; ycmd-0+20161219+git486b809.orig/cpp/ycm/versioning.h0000644000175000017500000000211513026170313020064 0ustar onuronur// Copyright (C) 2013 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef VERSIONING_H_EEJUU0AH #define VERSIONING_H_EEJUU0AH // The true value of this preprocessor definition is set in a compiler // command-line flag. This is done in the main CMakeLists.txt file. #if !defined( YCMD_CORE_VERSION ) #define YCMD_CORE_VERSION 0 #endif namespace YouCompleteMe { int YcmCoreVersion(); } // namespace YouCompleteMe #endif /* end of include guard: VERSIONING_H_EEJUU0AH */ ycmd-0+20161219+git486b809.orig/cpp/ycm/ycm_core.cpp0000644000175000017500000002062513026170313020042 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "IdentifierCompleter.h" #include "PythonSupport.h" #include "versioning.h" #ifdef USE_CLANG_COMPLETER # include "ClangCompleter.h" # include "ClangUtils.h" # include "CompletionData.h" # include "Diagnostic.h" # include "Location.h" # include "Range.h" # include "UnsavedFile.h" # include "CompilationDatabase.h" # include "Documentation.h" #endif // USE_CLANG_COMPLETER #include #include #include bool HasClangSupport() { #ifdef USE_CLANG_COMPLETER return true; #else return false; #endif // USE_CLANG_COMPLETER } BOOST_PYTHON_MODULE(ycm_core) { using namespace boost::python; using namespace YouCompleteMe; // Necessary because of usage of the ReleaseGil class PyEval_InitThreads(); def( "HasClangSupport", HasClangSupport ); def( "FilterAndSortCandidates", FilterAndSortCandidates ); def( "YcmCoreVersion", YcmCoreVersion ); // This is exposed so that we can test it. def( "GetUtf8String", GetUtf8String ); class_< IdentifierCompleter, boost::noncopyable >( "IdentifierCompleter" ) .def( "AddIdentifiersToDatabase", &IdentifierCompleter::AddIdentifiersToDatabase ) .def( "ClearForFileAndAddIdentifiersToDatabase", &IdentifierCompleter::ClearForFileAndAddIdentifiersToDatabase ) .def( "AddIdentifiersToDatabaseFromTagFiles", &IdentifierCompleter::AddIdentifiersToDatabaseFromTagFiles ) .def( "CandidatesForQueryAndType", &IdentifierCompleter::CandidatesForQueryAndType ); class_< std::vector< std::string >, boost::shared_ptr< std::vector< std::string > > >( "StringVector" ) .def( vector_indexing_suite< std::vector< std::string > >() ); #ifdef USE_CLANG_COMPLETER def( "ClangVersion", ClangVersion ); // CAREFUL HERE! For filename and contents we are referring directly to // Python-allocated and -managed memory since we are accepting pointers to // data members of python objects. We need to ensure that those objects // outlive our UnsavedFile objects. class_< UnsavedFile >( "UnsavedFile" ) .add_property( "filename_", make_getter( &UnsavedFile::filename_ ), make_setter( &UnsavedFile::filename_, return_value_policy< reference_existing_object >() ) ) .add_property( "contents_", make_getter( &UnsavedFile::contents_ ), make_setter( &UnsavedFile::contents_, return_value_policy< reference_existing_object >() ) ) .def_readwrite( "length_", &UnsavedFile::length_ ); class_< std::vector< UnsavedFile > >( "UnsavedFileVector" ) .def( vector_indexing_suite< std::vector< UnsavedFile > >() ); class_< ClangCompleter, boost::noncopyable >( "ClangCompleter" ) .def( "GetDeclarationLocation", &ClangCompleter::GetDeclarationLocation ) .def( "GetDefinitionLocation", &ClangCompleter::GetDefinitionLocation ) .def( "DeleteCachesForFile", &ClangCompleter::DeleteCachesForFile ) .def( "UpdatingTranslationUnit", &ClangCompleter::UpdatingTranslationUnit ) .def( "UpdateTranslationUnit", &ClangCompleter::UpdateTranslationUnit ) .def( "CandidatesForLocationInFile", &ClangCompleter::CandidatesForLocationInFile ) .def( "GetTypeAtLocation", &ClangCompleter::GetTypeAtLocation ) .def( "GetEnclosingFunctionAtLocation", &ClangCompleter::GetEnclosingFunctionAtLocation ) .def( "GetFixItsForLocationInFile", &ClangCompleter::GetFixItsForLocationInFile ) .def( "GetDocsForLocationInFile", &ClangCompleter::GetDocsForLocationInFile ); enum_< CompletionKind >( "CompletionKind" ) .value( "STRUCT", STRUCT ) .value( "CLASS", CLASS ) .value( "ENUM", ENUM ) .value( "TYPE", TYPE ) .value( "MEMBER", MEMBER ) .value( "FUNCTION", FUNCTION ) .value( "VARIABLE", VARIABLE ) .value( "MACRO", MACRO ) .value( "PARAMETER", PARAMETER ) .value( "NAMESPACE", NAMESPACE ) .value( "UNKNOWN", UNKNOWN ) .export_values(); class_< CompletionData >( "CompletionData" ) .def( "TextToInsertInBuffer", &CompletionData::TextToInsertInBuffer ) .def( "MainCompletionText", &CompletionData::MainCompletionText ) .def( "ExtraMenuInfo", &CompletionData::ExtraMenuInfo ) .def( "DetailedInfoForPreviewWindow", &CompletionData::DetailedInfoForPreviewWindow ) .def( "DocString", &CompletionData::DocString ) .def_readonly( "kind_", &CompletionData::kind_ ); class_< std::vector< CompletionData >, boost::shared_ptr< std::vector< CompletionData > > >( "CompletionVector" ) .def( vector_indexing_suite< std::vector< CompletionData > >() ); class_< Location >( "Location" ) .def_readonly( "line_number_", &Location::line_number_ ) .def_readonly( "column_number_", &Location::column_number_ ) .def_readonly( "filename_", &Location::filename_ ) .def( "IsValid", &Location::IsValid ); class_< Range >( "Range" ) .def_readonly( "start_", &Range::start_ ) .def_readonly( "end_", &Range::end_ ); class_< std::vector< Range > >( "RangeVector" ) .def( vector_indexing_suite< std::vector< Range > >() ); class_< FixItChunk >( "FixItChunk" ) .def_readonly( "replacement_text", &FixItChunk::replacement_text ) .def_readonly( "range", &FixItChunk::range ); class_< std::vector< FixItChunk > >( "FixItChunkVector" ) .def( vector_indexing_suite< std::vector< FixItChunk > >() ); class_< FixIt >( "FixIt" ) .def_readonly( "chunks", &FixIt::chunks ) .def_readonly( "location", &FixIt::location ) .def_readonly( "text", &FixIt::text ); class_< std::vector< FixIt > >( "FixItVector" ) .def( vector_indexing_suite< std::vector< FixIt > >() ); enum_< DiagnosticKind >( "DiagnosticKind" ) .value( "ERROR", ERROR ) .value( "WARNING", WARNING ) .value( "INFORMATION", INFORMATION ) .export_values(); class_< Diagnostic >( "Diagnostic" ) .def_readonly( "ranges_", &Diagnostic::ranges_ ) .def_readonly( "location_", &Diagnostic::location_ ) .def_readonly( "location_extent_", &Diagnostic::location_extent_ ) .def_readonly( "kind_", &Diagnostic::kind_ ) .def_readonly( "text_", &Diagnostic::text_ ) .def_readonly( "long_formatted_text_", &Diagnostic::long_formatted_text_ ) .def_readonly( "fixits_", &Diagnostic::fixits_ ); class_< std::vector< Diagnostic > >( "DiagnosticVector" ) .def( vector_indexing_suite< std::vector< Diagnostic > >() ); class_< DocumentationData >( "DocumentationData" ) .def_readonly( "comment_xml", &DocumentationData::comment_xml ) .def_readonly( "raw_comment", &DocumentationData::raw_comment ) .def_readonly( "brief_comment", &DocumentationData::brief_comment ) .def_readonly( "canonical_type", &DocumentationData::canonical_type ) .def_readonly( "display_name", &DocumentationData::display_name ); class_< CompilationDatabase, boost::noncopyable >( "CompilationDatabase", init< boost::python::object >() ) .def( "DatabaseSuccessfullyLoaded", &CompilationDatabase::DatabaseSuccessfullyLoaded ) .def( "AlreadyGettingFlags", &CompilationDatabase::AlreadyGettingFlags ) .def( "GetCompilationInfoForFile", &CompilationDatabase::GetCompilationInfoForFile ); class_< CompilationInfoForFile, boost::shared_ptr< CompilationInfoForFile > >( "CompilationInfoForFile", no_init ) .def_readonly( "compiler_working_dir_", &CompilationInfoForFile::compiler_working_dir_ ) .def_readonly( "compiler_flags_", &CompilationInfoForFile::compiler_flags_ ); #endif // USE_CLANG_COMPLETER } // Boost.Thread forces us to implement this. // We don't use any thread-specific (local) storage so it's fine to implement // this as an empty function. namespace boost { void tss_cleanup_implemented() {} }; ycmd-0+20161219+git486b809.orig/cpp/ycm/Result.cpp0000644000175000017500000001606313026170313017521 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "Result.h" #include "standard.h" #include "Utils.h" #include #include #include #include using boost::algorithm::istarts_with; namespace YouCompleteMe { namespace { char ChangeCharCase( char c ) { if ( std::isupper( c, std::locale() ) ) return std::tolower( c, std::locale() ); return std::toupper( c, std::locale() ); } bool CharLessThanWithLowercasePriority( const char &first, const char &second ) { char swap_first = ChangeCharCase( first ); char swap_second = ChangeCharCase( second ); return swap_first < swap_second; } bool StringLessThanWithLowercasePriority( const std::string &first, const std::string &second ) { return std::lexicographical_compare( first.begin(), first.end(), second.begin(), second.end(), boost::function< bool( const char &, const char & ) >( &CharLessThanWithLowercasePriority ) ); } int LongestCommonSubsequenceLength( const std::string &first, const std::string &second ) { const std::string &longer = first.size() > second.size() ? first : second; const std::string &shorter = first.size() > second.size() ? second : first; int longer_len = longer.size(); int shorter_len = shorter.size(); std::vector previous( shorter_len + 1, 0 ); std::vector current( shorter_len + 1, 0 ); for ( int i = 0; i < longer_len; ++i ) { for ( int j = 0; j < shorter_len; ++j ) { if ( toupper( longer[ i ] ) == toupper( shorter[ j ] ) ) current[ j + 1 ] = previous[ j ] + 1; else current[ j + 1 ] = std::max( current[ j ], previous[ j + 1 ] ); } for ( int j = 0; j < shorter_len; ++j ) { previous[ j + 1 ] = current[ j + 1 ]; } } return current[ shorter_len ]; } int NumWordBoundaryCharMatches( const std::string &query, const std::string &word_boundary_chars ) { return LongestCommonSubsequenceLength( query, word_boundary_chars ); } } // unnamed namespace Result::Result() : query_is_empty_( true ), is_subsequence_( false ), first_char_same_in_query_and_text_( false ), ratio_of_word_boundary_chars_in_query_( 0 ), word_boundary_char_utilization_( 0 ), query_is_candidate_prefix_( false ), text_is_lowercase_( false ), char_match_index_sum_( 0 ), text_( NULL ) { } Result::Result( bool is_subsequence ) : query_is_empty_( true ), is_subsequence_( is_subsequence ), first_char_same_in_query_and_text_( false ), ratio_of_word_boundary_chars_in_query_( 0 ), word_boundary_char_utilization_( 0 ), query_is_candidate_prefix_( false ), text_is_lowercase_( false ), char_match_index_sum_( 0 ), text_( NULL ) { } Result::Result( bool is_subsequence, const std::string *text, bool text_is_lowercase, int char_match_index_sum, const std::string &word_boundary_chars, const std::string &query ) : query_is_empty_( true ), is_subsequence_( is_subsequence ), first_char_same_in_query_and_text_( false ), ratio_of_word_boundary_chars_in_query_( 0 ), word_boundary_char_utilization_( 0 ), query_is_candidate_prefix_( false ), text_is_lowercase_( text_is_lowercase ), char_match_index_sum_( char_match_index_sum ), text_( text ) { if ( is_subsequence ) SetResultFeaturesFromQuery( word_boundary_chars, query ); } bool Result::operator< ( const Result &other ) const { // Yes, this is ugly but it also needs to be fast. Since this is called a // bazillion times, we have to make sure only the required comparisons are // made, and no more. if ( !query_is_empty_ ) { if ( first_char_same_in_query_and_text_ != other.first_char_same_in_query_and_text_ ) { return first_char_same_in_query_and_text_; } bool equal_wb_ratios = AlmostEqual( ratio_of_word_boundary_chars_in_query_, other.ratio_of_word_boundary_chars_in_query_ ); bool equal_wb_utilization = AlmostEqual( word_boundary_char_utilization_, other.word_boundary_char_utilization_ ); if ( AlmostEqual( ratio_of_word_boundary_chars_in_query_, 1.0 ) || AlmostEqual( other.ratio_of_word_boundary_chars_in_query_, 1.0 ) ) { if ( !equal_wb_ratios ) { return ratio_of_word_boundary_chars_in_query_ > other.ratio_of_word_boundary_chars_in_query_; } else { if ( !equal_wb_utilization ) return word_boundary_char_utilization_ > other.word_boundary_char_utilization_; } } if ( query_is_candidate_prefix_ != other.query_is_candidate_prefix_ ) return query_is_candidate_prefix_; if ( !equal_wb_ratios ) { return ratio_of_word_boundary_chars_in_query_ > other.ratio_of_word_boundary_chars_in_query_; } else { if ( !equal_wb_utilization ) return word_boundary_char_utilization_ > other.word_boundary_char_utilization_; } if ( char_match_index_sum_ != other.char_match_index_sum_ ) return char_match_index_sum_ < other.char_match_index_sum_; if ( text_->length() != other.text_->length() ) return text_->length() < other.text_->length(); if ( text_is_lowercase_ != other.text_is_lowercase_ ) return text_is_lowercase_; } // Lexicographic comparison, but we prioritize lowercase letters over // uppercase ones. So "foo" < "Foo". return StringLessThanWithLowercasePriority( *text_, *other.text_ ); } void Result::SetResultFeaturesFromQuery( const std::string &word_boundary_chars, const std::string &query ) { query_is_empty_ = query.empty(); if ( query.empty() || text_->empty() ) return; first_char_same_in_query_and_text_ = toupper( query[ 0 ] ) == toupper( ( *text_ )[ 0 ] ); int num_wb_matches = NumWordBoundaryCharMatches( query, word_boundary_chars ); ratio_of_word_boundary_chars_in_query_ = num_wb_matches / static_cast< double >( query.length() ); word_boundary_char_utilization_ = num_wb_matches / static_cast< double >( word_boundary_chars.length() ); query_is_candidate_prefix_ = istarts_with( *text_, query ); } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/CandidateRepository.cpp0000644000175000017500000000754713026170313022226 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "CandidateRepository.h" #include "Candidate.h" #include "standard.h" #include "Utils.h" #include #include #ifdef USE_CLANG_COMPLETER # include "ClangCompleter/CompletionData.h" #endif // USE_CLANG_COMPLETER namespace YouCompleteMe { namespace { // We set a reasonable max limit to prevent issues with huge candidate strings // entering the database. Such large candidates are almost never desirable. const int MAX_CANDIDATE_SIZE = 80; } // unnamed namespace boost::mutex CandidateRepository::singleton_mutex_; CandidateRepository *CandidateRepository::instance_ = NULL; CandidateRepository &CandidateRepository::Instance() { boost::lock_guard< boost::mutex > locker( singleton_mutex_ ); if ( !instance_ ) { static CandidateRepository repo; instance_ = &repo; } return *instance_; } int CandidateRepository::NumStoredCandidates() { boost::lock_guard< boost::mutex > locker( holder_mutex_ ); return candidate_holder_.size(); } std::vector< const Candidate * > CandidateRepository::GetCandidatesForStrings( const std::vector< std::string > &strings ) { std::vector< const Candidate * > candidates; candidates.reserve( strings.size() ); { boost::lock_guard< boost::mutex > locker( holder_mutex_ ); foreach ( const std::string & candidate_text, strings ) { const std::string &validated_candidate_text = ValidatedCandidateText( candidate_text ); const Candidate *&candidate = GetValueElseInsert( candidate_holder_, validated_candidate_text, NULL ); if ( !candidate ) candidate = new Candidate( validated_candidate_text ); candidates.push_back( candidate ); } } return candidates; } #ifdef USE_CLANG_COMPLETER std::vector< const Candidate * > CandidateRepository::GetCandidatesForStrings( const std::vector< CompletionData > &datas ) { std::vector< const Candidate * > candidates; candidates.reserve( datas.size() ); { boost::lock_guard< boost::mutex > locker( holder_mutex_ ); foreach ( const CompletionData & data, datas ) { const std::string &validated_candidate_text = ValidatedCandidateText( data.original_string_ ); const Candidate *&candidate = GetValueElseInsert( candidate_holder_, validated_candidate_text, NULL ); if ( !candidate ) candidate = new Candidate( validated_candidate_text ); candidates.push_back( candidate ); } } return candidates; } #endif // USE_CLANG_COMPLETER CandidateRepository::~CandidateRepository() { foreach ( const CandidateHolder::value_type & pair, candidate_holder_ ) { delete pair.second; } } // Returns a ref to empty_ if candidate not valid. const std::string &CandidateRepository::ValidatedCandidateText( const std::string &candidate_text ) { if ( candidate_text.size() <= MAX_CANDIDATE_SIZE && IsPrintable( candidate_text ) ) return candidate_text; return empty_; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/cpp/ycm/Result.h0000644000175000017500000000674713026170313017176 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef RESULT_H_CZYD2SGN #define RESULT_H_CZYD2SGN #include namespace YouCompleteMe { class Result { public: Result(); explicit Result( bool is_subsequence ); Result( bool is_subsequence, const std::string *text, bool text_is_lowercase, int char_match_index_sum, const std::string &word_boundary_chars, const std::string &query ); bool operator< ( const Result &other ) const; inline bool IsSubsequence() const { return is_subsequence_; } inline const std::string *Text() const { return text_; } private: void SetResultFeaturesFromQuery( const std::string &query, const std::string &word_boundary_chars ); // true when the query for which the result was created was an empty string; // in these cases we just use a lexicographic comparison bool query_is_empty_; // true when the characters of the query are a subsequence of the characters // in the candidate text, e.g. the characters "abc" are a subsequence for // "xxaygbefc" but not for "axxcb" since they occur in the correct order ('a' // then 'b' then 'c') in the first string but not in the second. bool is_subsequence_; // true when the first character of the query and the candidate match bool first_char_same_in_query_and_text_; // number of word boundary matches / number of chars in query double ratio_of_word_boundary_chars_in_query_; // number of word boundary matches / number of all word boundary chars double word_boundary_char_utilization_; // true when the query is a prefix of the candidate string, e.g. "foo" query // for "foobar" candidate. bool query_is_candidate_prefix_; // true when the candidate text is all lowercase, e.g. "foo" candidate. bool text_is_lowercase_; // The sum of the indexes of all the letters the query "hit" in the candidate // text. For instance, the result for the query "abc" in the candidate // "012a45bc8" has char_match_index_sum of 3 + 6 + 7 = 16 because those are // the char indexes of those letters in the candidate string. int char_match_index_sum_; // points to the full candidate text const std::string *text_; }; template< class T > struct ResultAnd { ResultAnd( const Result &result, T extra_object ) : extra_object_( extra_object ), result_( result ) {} bool operator< ( const ResultAnd &other ) const { return result_ < other.result_; } T extra_object_; Result result_; }; template< class T > struct ResultAnd { ResultAnd( const Result &result, const T *extra_object ) : extra_object_( extra_object ), result_( result ) {} bool operator< ( const ResultAnd &other ) const { return result_ < other.result_; } const T *extra_object_; Result result_; }; } // namespace YouCompleteMe #endif /* end of include guard: RESULT_H_CZYD2SGN */ ycmd-0+20161219+git486b809.orig/cpp/ycm/IdentifierCompleter.h0000644000175000017500000000514513026170313021644 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #ifndef COMPLETER_H_7AR4UGXE #define COMPLETER_H_7AR4UGXE #include "DLLDefines.h" #include "IdentifierDatabase.h" #include #include #include #include #include #include namespace YouCompleteMe { class Candidate; class IdentifierCompleter : boost::noncopyable { public: YCM_DLL_EXPORT IdentifierCompleter(); YCM_DLL_EXPORT IdentifierCompleter( const std::vector< std::string > &candidates ); IdentifierCompleter( const std::vector< std::string > &candidates, const std::string &filetype, const std::string &filepath ); void AddIdentifiersToDatabase( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ); // Same as above, but clears all identifiers stored for the file before adding // new identifiers. void ClearForFileAndAddIdentifiersToDatabase( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ); YCM_DLL_EXPORT void AddIdentifiersToDatabaseFromTagFiles( const std::vector< std::string > &absolute_paths_to_tag_files ); void AddIdentifiersToDatabaseFromBuffer( const std::string &buffer_contents, const std::string &filetype, const std::string &filepath, bool collect_from_comments_and_strings ); // Only provided for tests! YCM_DLL_EXPORT std::vector< std::string > CandidatesForQuery( const std::string &query ) const; YCM_DLL_EXPORT std::vector< std::string > CandidatesForQueryAndType( const std::string &query, const std::string &filetype ) const; private: ///////////////////////////// // PRIVATE MEMBER VARIABLES ///////////////////////////// IdentifierDatabase identifier_database_; }; } // namespace YouCompleteMe #endif /* end of include guard: COMPLETER_H_7AR4UGXE */ ycmd-0+20161219+git486b809.orig/cpp/ycm/IdentifierCompleter.cpp0000644000175000017500000000602413026170313022174 0ustar onuronur// Copyright (C) 2011, 2012 Google Inc. // // This file is part of ycmd. // // ycmd 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. // // ycmd 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 ycmd. If not, see . #include "IdentifierCompleter.h" #include "standard.h" #include "Candidate.h" #include "IdentifierUtils.h" #include "Result.h" #include "Utils.h" #include "ReleaseGil.h" #include namespace YouCompleteMe { IdentifierCompleter::IdentifierCompleter() {} IdentifierCompleter::IdentifierCompleter( const std::vector< std::string > &candidates ) { identifier_database_.AddIdentifiers( candidates, "", "" ); } IdentifierCompleter::IdentifierCompleter( const std::vector< std::string > &candidates, const std::string &filetype, const std::string &filepath ) { identifier_database_.AddIdentifiers( candidates, filetype, filepath ); } void IdentifierCompleter::AddIdentifiersToDatabase( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ) { ReleaseGil unlock; identifier_database_.AddIdentifiers( new_candidates, filetype, filepath ); } void IdentifierCompleter::ClearForFileAndAddIdentifiersToDatabase( const std::vector< std::string > &new_candidates, const std::string &filetype, const std::string &filepath ) { identifier_database_.ClearCandidatesStoredForFile( filetype, filepath ); AddIdentifiersToDatabase( new_candidates, filetype, filepath ); } void IdentifierCompleter::AddIdentifiersToDatabaseFromTagFiles( const std::vector< std::string > &absolute_paths_to_tag_files ) { ReleaseGil unlock; foreach( const std::string & path, absolute_paths_to_tag_files ) { identifier_database_.AddIdentifiers( ExtractIdentifiersFromTagsFile( path ) ); } } std::vector< std::string > IdentifierCompleter::CandidatesForQuery( const std::string &query ) const { return CandidatesForQueryAndType( query, "" ); } std::vector< std::string > IdentifierCompleter::CandidatesForQueryAndType( const std::string &query, const std::string &filetype ) const { ReleaseGil unlock; if ( !IsPrintable( query ) ) return std::vector< std::string >(); std::vector< Result > results; identifier_database_.ResultsForQueryAndType( query, filetype, results ); std::vector< std::string > candidates; candidates.reserve( results.size() ); foreach ( const Result & result, results ) { candidates.push_back( *result.Text() ); } return candidates; } } // namespace YouCompleteMe ycmd-0+20161219+git486b809.orig/README.md0000644000175000017500000003341213026170313015441 0ustar onuronurycmd: a code-completion & comprehension server ============================================== [![Build Status](https://travis-ci.org/Valloric/ycmd.svg?branch=master)](https://travis-ci.org/Valloric/ycmd) [![Build status](https://ci.appveyor.com/api/projects/status/6fetp5xwb0kkuv2w/branch/master?svg=true)](https://ci.appveyor.com/project/Valloric/ycmd) [![Coverage Status](https://codecov.io/gh/Valloric/ycmd/branch/master/graph/badge.svg)](https://codecov.io/gh/Valloric/ycmd) ycmd is a server that provides APIs for code-completion and other code-comprehension use-cases like semantic GoTo commands (and others). For certain filetypes, ycmd can also provide diagnostic errors and warnings. ycmd was originally part of [YouCompleteMe][ycm]'s codebase, but has been split out into a separate project so that it can be used in editors other than Vim. The best way to learn how to interact with ycmd is by reading through (and running) the [`example_client.py`][example-client] file. See the [README for the examples][example-readme] folder for details on how to run the example client. Known ycmd clients: ------------------ - [YouCompleteMe][ycm]: Vim client, stable and exposes all ycmd features. - [emacs-ycmd][]: Emacs client. - [you-complete-me][atom-you-complete-me]: Atom client. - [YcmdCompletion][sublime-ycmd]: Sublime client - [kak-ycmd][]: Kakoune client. - [you-complete-me][vscode-you-complete-me]: VSCode client. Feel free to send a pull request adding a link to your client here if you've built one. Building -------- **If you're looking to develop ycmd, see the [instructions for setting up a dev environment][dev-setup] and for [running the tests][test-setup].** This is all for Ubuntu Linux. Details on getting ycmd running on other OS's can be found in [YCM's instructions][ycm-install] (ignore the Vim-specific parts). Note that **ycmd runs on Python 2.6, 2.7 and 3.3+.** First, install the dependencies: ``` sudo apt-get install build-essential cmake python-dev ``` When you first clone the repository you'll need to update the submodules: ``` git submodule update --init --recursive ``` Then run `./build.py --all`. This should get you going. For more detailed instructions on building ycmd, see [YCM's instructions][ycm-install] (ignore the Vim-specific parts). API notes --------- - All strings going into and out of the server are UTF-8 encoded. - All line and column numbers are 1-based, not 0-based. They are also byte offsets, _not_ Unicode codepoint offsets. - All file paths are full, absolute paths. - All requests to the server _must_ include an [HMAC][] in the `x-ycm-hmac` HTTP header. The HMAC is computed from the shared secret passed to the server on startup and the request/response body. The digest algorithm is SHA-256. The server will also include the HMAC in its responses; you _must_ verify it before using the response. See [`example_client.py`][example-client] to see how it's done. How ycmd works -------------- There are several completion engines in ycmd. The most basic one is an identifier-based completer that collects all of the identifiers in the file provided in the completion request, other files of the same filetype that were provided previously and any tags files produced by ctags. This engine is non-semantic. There are also several semantic engines in YCM. There's a libclang-based completer that provides semantic completion for C-family languages. There's also a Jedi-based completer for semantic completion for Python, an OmniSharp-based completer for C#, a [Gocode][gocode]-based completer for Go (using [Godef][godef] for jumping to definitions), and a TSServer-based completer for TypeScript. More will be added with time. There are also other completion engines, like the filepath completer (part of the identifier completer). The server will automatically detect which completion engine would be the best in any situation. On occasion, it queries several of them at once, merges the outputs and presents the results. Semantic engines are triggered only after semantic "triggers" are inserted in the code. If the request received shows that the user's cursor is after the last character in `string foo; foo.` in a C# file, this would trigger the semantic engine to examine members of `foo` because `.` is a [default semantic trigger][trigger-defaults] for C# (triggers can be changed dynamically). If the text were `string foo; foo.zoo`, semantic completion would still be triggered (the trigger is behind the `zoo` word the user is typing) and the results would be filtered with the `zoo` query. Semantic completion can also be forced by setting `force_semantic: true` in the JSON data for the completion request, _but you should only do this if the user explicitly requested semantic completion with a keyboard shortcut_; otherwise, leave it up to ycmd to decide when to use which engine. The reason why semantic completion isn't always used even when available is because the semantic engines can be slow and because most of the time, the user doesn't actually need semantic completion. There are two main use-cases for code-completion: 1. The user knows which name they're looking for, they just don't want to type the whole name. 2. The user either doesn't know the name they need or isn't sure what the name is. This is also known as the "API exploration" use-case. The first use case is the most common one and is trivially addressed with the identifier completion engine (which BTW is blazing fast). The second one needs semantic completion. ### Completion string filtering A critical thing to note is that the completion **filtering is NOT based on the input being a string prefix of the completion** (but that works too). The input needs to be a _[subsequence][] match_ of a completion. This is a fancy way of saying that any input characters need to be present in a completion string in the order in which they appear in the input. So `abc` is a subsequence of `xaybgc`, but not of `xbyxaxxc`. ### Completion string ranking The subsequence filter removes any completions that do not match the input, but then the sorting system kicks in. It's a bit involved, but roughly speaking "word boundary" (WB) subsequence character matches are "worth" more than non-WB matches. In effect, this means given an input of "gua", the completion "getUserAccount" would be ranked higher in the list than the "Fooguxa" completion (both of which are subsequence matches). A word-boundary character are all capital characters, characters preceded by an underscore and the first letter character in the completion string. ### Auto-shutdown if no requests for a while If the server hasn't received any requests for a while (controlled by the `--idle_suicide_seconds` ycmd flag), it will shut itself down. This is useful for cases where the process that started ycmd dies without telling ycmd to die too or if ycmd hangs (this should be extremely rare). If you're implementing a client for ycmd, ensure that you have some sort of keep-alive background thread that periodically pings ycmd (just call the `/healthy` handler, although any handler will do). You can also turn this off by passing `--idle_suicide_seconds=0`, although that isn't recommended. ### Exit codes During startup, ycmd attempts to load the `ycm_core` library and exits with one of the following return codes if unsuccessful: - 3: unexpected error while loading the library; - 4: the `ycm_core` library is missing; - 5: the `ycm_core` library is compiled for Python 3 but loaded in Python 2; - 6: the `ycm_core` library is compiled for Python 2 but loaded in Python 3; - 7: the version of the `ycm_core` library is outdated. User-level customization ----------------------- You can provide settings to ycmd on server startup. There's a [`default_settings.json`][def-settings] file that you can tweak. See the [_Options_ section in YCM's _User Guide_][options] for a description on what each option does. Pass the path to the modified settings file to ycmd as an `--options_file=/path/to/file` flag. Note that you must set the `hmac_secret` setting (encode the value with [base64][]). Because the file you are passing contains a secret token, ensure that you are creating the temporary file in a secure way (the [`mkstemp()`][mkstemp] Linux system call is a good idea; use something similar for other OS's). After it starts up, ycmd will _delete_ the settings file you provided after it reads it. The settings file is something your editor should produce based on values your user has configured. There's also an extra file (`.ycm_extra_conf.py`) your user is supposed to provide to configure certain semantic completers. More information on it can also be found in the [corresponding section of YCM's _User Guide_][extra-conf-doc]. ### `.ycm_extra_conf.py` specification The `.ycm_extra_conf.py` module must define the following methods: #### `FlagsForFile( filename, **kwargs )` Required for c-family language support. This method is called by the c-family completer to get the compiler flags to use when compiling the file with absolute path `filename`. The following additional arguments are optionally supplied depending on user configuration: - `client_data`: any additional data supplied by the client application. See the [YouCompleteMe documentation][extra-conf-vim-data-doc] for an example. The return value must be one of the following: - `None` meaning no flags are known for this file, or - a dictionary containing the following items: - `flags`: (mandatory) a list of compiler flags. - `do_cache`: (optional) a boolean indicating whether or not the result of this call (i.e. the list of flags) should be cached for this file name. Defaults to `True`. If unsure, the default is almost always correct. - `flags_ready`: (optional) a boolean indicating that the flags should be used. Defaults to `True`. If unsure, the default is almost always correct. A minimal example which simply returns a list of flags is: ```python def FlagsForFile( filename, **kwargs ): return { 'flags': [ '-x', 'c++' ] } ``` ### Global extra conf file specification The global extra module must expose the same functions as the `.ycm_extra_conf.py` module with the following additions: #### `YcmCorePreLoad()` Optional. This method, if defined, is called by the server prior to importing the c++ python plugin. It is not usually required and its use is for advanced users only. #### `Shutdown()` Optional. Called prior to the server exiting cleanly. It is not usually required and its use is for advanced users only. Backwards compatibility ----------------------- ycmd's HTTP+JSON interface follows [SemVer][]. While ycmd has seen extensive use over the last several years as part of YCM, the version number is below 1.0 because some parts of the API _might_ change slightly as people discover possible problems integrating ycmd with other editors. In other words, the current API might unintentionally be Vim-specific. We don't want that. Note that ycmd's internal API's (i.e. anything other than HTTP+JSON) are **NOT** covered by SemVer and _will_ randomly change underneath you. **DON'T** interact with the Python/C++/etc code directly! FAQ --- ### Is HMAC auth for requests/responses really necessary? Without the HMAC auth, it's possible for a malicious website to impersonate the user. Don't forget that evil.com can send requests to servers listening on localhost if the user visits evil.com in a browser. **This is not merely a theoretical concern**; a working proof-of-concept remote code execution exploit [was created][exploit] for ycmd running on localhost. The HMAC auth was added to block this attack vector. Contributor Code of Conduct --------------------------- Please note that this project is released with a [Contributor Code of Conduct][ccoc]. By participating in this project you agree to abide by its terms. Contact ------- If you have questions about the plugin or need help, please use the [ycmd-users][] mailing list. The author's homepage is . License ------- This software is licensed under the [GPL v3 license][gpl]. © 2015 ycmd contributors [ycmd-users]: https://groups.google.com/forum/?hl=en#!forum/ycmd-users [ycm]: http://valloric.github.io/YouCompleteMe/ [atom-you-complete-me]: https://atom.io/packages/you-complete-me [sublime-ycmd]: https://packagecontrol.io/packages/YcmdCompletion [semver]: http://semver.org/ [hmac]: http://en.wikipedia.org/wiki/Hash-based_message_authentication_code [exploit]: https://groups.google.com/d/topic/ycm-users/NZAPrvaYgxo/discussion [example-client]: https://github.com/Valloric/ycmd/blob/master/examples/example_client.py [example-readme]: https://github.com/Valloric/ycmd/blob/master/examples/README.md [trigger-defaults]: https://github.com/Valloric/ycmd/blob/master/ycmd/completers/completer_utils.py#L143 [subsequence]: http://en.wikipedia.org/wiki/Subsequence [ycm-install]: https://github.com/Valloric/YouCompleteMe/blob/master/README.md#mac-os-x [def-settings]: https://github.com/Valloric/ycmd/blob/master/ycmd/default_settings.json [base64]: http://en.wikipedia.org/wiki/Base64 [mkstemp]: http://man7.org/linux/man-pages/man3/mkstemp.3.html [options]: https://github.com/Valloric/YouCompleteMe#options [extra-conf-doc]: https://github.com/Valloric/YouCompleteMe#c-family-semantic-completion [emacs-ycmd]: https://github.com/abingham/emacs-ycmd [gpl]: http://www.gnu.org/copyleft/gpl.html [gocode]: https://github.com/nsf/gocode [godef]: https://github.com/Manishearth/godef [kak-ycmd]: https://github.com/mawww/kak-ycmd [ccoc]: https://github.com/Valloric/ycmd/blob/master/CODE_OF_CONDUCT.md [dev-setup]: https://github.com/Valloric/ycmd/blob/master/DEV_SETUP.md [test-setup]: https://github.com/Valloric/ycmd/blob/master/TESTS.md [extra-conf-vim-data-doc]: https://github.com/Valloric/YouCompleteMe#the-gycm_extra_conf_vim_data-option [vscode-you-complete-me]: https://marketplace.visualstudio.com/items?itemName=RichardHe.you-complete-me ycmd-0+20161219+git486b809.orig/TESTS.md0000644000175000017500000001121413026170313015402 0ustar onuronur# Running ycmd tests This readme documents instructions on running the test suite. The easiest way to run the ycmd test suite locally is to [set up your ycmd dev environment using Vagrant][dev-setup] which will have everything installed and ready to go. Reading this file is still useful because you'll learn how to skip the build or parts of the test suite. An alternative (canonical) reference is the scripts used for running the tests on Travis CI. These can be found in `.travis.yml` and `./travis` directory. ## Requirements for running the tests You need to have installed: * nose (pip install nose) * nose-exclude (pip install nose-exclude) * mock (pip install mock) * flake8 (pip install flake8) * webtest (pip install webtest) * hamcrest (pip install PyHamcrest) See `test_requirements.txt` for specific versions. The simplest way to set this up is to use a virtualenv, for example: ```bash $ mkdir ~/YouCompleteMe/tests $ virtualenv ~/YouCompleteMe/tests $ source ~/YouCompleteMe/tests/bin/activate $ pip install -r test_requirements.txt ``` You also need to have all of ycmd's completers' requirements. See the installation guide for details, but typically this involves manually installing: * mono * gocode * typescript * node * npm If you are unwilling or unable to install the requirements for all of the completers, you can exclude certain completers with the `--no-completer` option. ### mono non-standard path Note: if your installation of mono is in a non-standard location, OmniSharpServer will not start. Ensure that it is in a standard location, or change the paths in `OmniSharpServer/OmniSharp/Solution/CSharpProject.cs` ## Running the tests To run the full suite, just run `run_tests.py`. Options are: * `--skip-build`: don't attempt to run the build `build.py`, e.g. if you use a non-standard build environment (e.g. `cmake28`, self-build of clang, etc.) * `--no-completers`: Do not build or test with listed semantic completion engine(s). * `--completers`: Only build and test with listed semantic completion engine(s). * `--msvc`: The Microsoft Visual Studio version to build with. (default: 14). Windows only. * `--arch`: Force architecture to 32 or 64 bits on Windows (default: python interpreter architecture). Windows Only. * `--coverage`: Generate code coverage data Remaining arguments are passed to "nosetests" directly. This means that you can run a specific script or a specific test as follows: * Specific test: `./run_tests.py ycmd/tests/.py:` * Specific script: `./run_tests.py ycmd.tests.` For example: * `./run_tests.py ycmd/tests/subcommands_test.py:RunCompleterCommand_GetType_test` * `./run_tests.py ycmd.tests.subcommands_test` NOTE: you must have UTF8 support in your terminal when you do this, e.g.: > LANG=en_GB.utf8 ./run_tests.py --skip-build ## Coverage testing We can generate coverage data for both the C++ layer and the Python layer. The CI system will pass this coverage data to codecov.io where you can view coverage after pushing a branch. C++ coverage testing is available only on Linux/Mac and uses gcov. Stricly speaking, we use the `-coverage` option to your compiler, which in the case of GNU and LLVM compilers, generate gcov-compatible data. For Python, there's a coverage module which works nicely with `nosetests`. This is very useful for highlighting areas of your code which are not covered by the automated integration tests. Run it like this: ``` $ ./run_tests.py --coverage ``` This will print a summary and generate HTML output in `./cover` More information: https://coverage.readthedocs.org and https://nose.readthedocs.org/en/latest/plugins/cover.html ## Troubleshooting ### All the tests fail with some missing package. Check the list of pip packages to install above. If there is one not listed, install it and add it to the list. ### All the CsCompleter tests fail on unix. Likely to be a problem with the OmniSharpServer. * Check that you have compiled OmniSharpServer in `third-party/OmniSharpServer` * Check that OmniSharpServer starts manually from ycmd/tests/testdata with > mono ../../../third_party/OmniSharpServer/OmniSharp/bin/Debug/OmniSharp.exe -s testy/testy.sln ### You get one or all of the following failures ERROR: ycmd.tests.get_completions_test.GetCompletions_CsCompleter_PathWithSpace_test FAIL: ycmd.completers.general.tests.filename_completer_test.FilenameCompleter_test.QuotedIncludeCompletion_test FAIL: ycmd.completers.general.tests.filename_completer_test.FilenameCompleter_test.SystemPathCompletion_test Ensure that you have UTF-8 support in your environment (see above) [dev-setup]: https://github.com/Valloric/ycmd/blob/master/DEV_SETUP.md ycmd-0+20161219+git486b809.orig/build.py0000755000175000017500000004313313026170313015637 0ustar onuronur#!/usr/bin/env python # Passing an environment variable containing unicode literals to a subprocess # on Windows and Python2 raises a TypeError. Since there is no unicode # string in this script, we don't import unicode_literals to avoid the issue. from __future__ import print_function from __future__ import division from __future__ import absolute_import from distutils import sysconfig from shutil import rmtree from tempfile import mkdtemp import errno import multiprocessing import os import os.path as p import platform import re import shlex import subprocess import sys PY_MAJOR, PY_MINOR = sys.version_info[ 0 : 2 ] if not ( ( PY_MAJOR == 2 and PY_MINOR >= 6 ) or ( PY_MAJOR == 3 and PY_MINOR >= 3 ) or PY_MAJOR > 3 ): sys.exit( 'ycmd requires Python >= 2.6 or >= 3.3; ' 'your version of Python is ' + sys.version ) DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) ) DIR_OF_THIRD_PARTY = p.join( DIR_OF_THIS_SCRIPT, 'third_party' ) for folder in os.listdir( DIR_OF_THIRD_PARTY ): abs_folder_path = p.join( DIR_OF_THIRD_PARTY, folder ) if p.isdir( abs_folder_path ) and not os.listdir( abs_folder_path ): sys.exit( 'ERROR: some folders in {0} are empty; you probably forgot to run:\n' '\tgit submodule update --init --recursive\n'.format( DIR_OF_THIRD_PARTY ) ) sys.path.insert( 1, p.abspath( p.join( DIR_OF_THIRD_PARTY, 'argparse' ) ) ) import argparse NO_DYNAMIC_PYTHON_ERROR = ( 'ERROR: found static Python library ({library}) but a dynamic one is ' 'required. You must use a Python compiled with the {flag} flag. ' 'If using pyenv, you need to run the command:\n' ' export PYTHON_CONFIGURE_OPTS="{flag}"\n' 'before installing a Python version.' ) NO_PYTHON_LIBRARY_ERROR = 'ERROR: unable to find an appropriate Python library.' # Regular expressions used to find static and dynamic Python libraries. # Notes: # - Python 3 library name may have an 'm' suffix on Unix platforms, for # instance libpython3.3m.so; # - the linker name (the soname without the version) does not always # exist so we look for the versioned names too; # - on Windows, the .lib extension is used instead of the .dll one. See # http://xenophilia.org/winvunix.html to understand why. STATIC_PYTHON_LIBRARY_REGEX = '^libpython{major}\.{minor}m?\.a$' DYNAMIC_PYTHON_LIBRARY_REGEX = """ ^(?: # Linux, BSD libpython{major}\.{minor}m?\.so(\.\d+)*| # OS X libpython{major}\.{minor}m?\.dylib| # Windows python{major}{minor}\.lib )$ """ def OnMac(): return platform.system() == 'Darwin' def OnWindows(): return platform.system() == 'Windows' def OnTravisOrAppVeyor(): return 'CI' in os.environ # On Windows, distutils.spawn.find_executable only works for .exe files # but .bat and .cmd files are also executables, so we use our own # implementation. def FindExecutable( executable ): # Executable extensions used on Windows WIN_EXECUTABLE_EXTS = [ '.exe', '.bat', '.cmd' ] paths = os.environ[ 'PATH' ].split( os.pathsep ) base, extension = os.path.splitext( executable ) if OnWindows() and extension.lower() not in WIN_EXECUTABLE_EXTS: extensions = WIN_EXECUTABLE_EXTS else: extensions = [''] for extension in extensions: executable_name = executable + extension if not os.path.isfile( executable_name ): for path in paths: executable_path = os.path.join(path, executable_name ) if os.path.isfile( executable_path ): return executable_path else: return executable_name return None def PathToFirstExistingExecutable( executable_name_list ): for executable_name in executable_name_list: path = FindExecutable( executable_name ) if path: return path return None def NumCores(): ycm_cores = os.environ.get( 'YCM_CORES' ) if ycm_cores: return int( ycm_cores ) try: return multiprocessing.cpu_count() except NotImplementedError: return 1 def CheckDeps(): if not PathToFirstExistingExecutable( [ 'cmake' ] ): sys.exit( 'ERROR: please install CMake and retry.') def CheckCall( args, **kwargs ): exit_message = kwargs.get( 'exit_message', None ) kwargs.pop( 'exit_message', None ) try: subprocess.check_call( args, **kwargs ) except subprocess.CalledProcessError as error: if exit_message: sys.exit( exit_message ) sys.exit( error.returncode ) def GetPossiblePythonLibraryDirectories(): library_dir = p.dirname( sysconfig.get_python_lib( standard_lib = True ) ) if OnWindows(): return [ p.join( library_dir, 'libs' ) ] # On pyenv, there is no Python dynamic library in the directory returned by # the LIBPL variable. Such library is located in the parent folder of the # standard Python library modules. return [ sysconfig.get_config_var( 'LIBPL' ), library_dir ] def FindPythonLibraries(): include_dir = sysconfig.get_python_inc() library_dirs = GetPossiblePythonLibraryDirectories() # Since ycmd is compiled as a dynamic library, we can't link it to a Python # static library. If we try, the following error will occur on Mac: # # Fatal Python error: PyThreadState_Get: no current thread # # while the error happens during linking on Linux and looks something like: # # relocation R_X86_64_32 against `a local symbol' can not be used when # making a shared object; recompile with -fPIC # # On Windows, the Python library is always a dynamic one (an import library to # be exact). To obtain a dynamic library on other platforms, Python must be # compiled with the --enable-shared flag on Linux or the --enable-framework # flag on Mac. # # So we proceed like this: # - look for a dynamic library and return its path; # - if a static library is found instead, raise an error with instructions # on how to build Python as a dynamic library. # - if no libraries are found, raise a generic error. dynamic_name = re.compile( DYNAMIC_PYTHON_LIBRARY_REGEX.format( major = PY_MAJOR, minor = PY_MINOR ), re.X ) static_name = re.compile( STATIC_PYTHON_LIBRARY_REGEX.format( major = PY_MAJOR, minor = PY_MINOR ), re.X ) static_libraries = [] for library_dir in library_dirs: # Files are sorted so that we found the non-versioned Python library before # the versioned one. for filename in sorted( os.listdir( library_dir ) ): if dynamic_name.match( filename ): return p.join( library_dir, filename ), include_dir if static_name.match( filename ): static_libraries.append( p.join( library_dir, filename ) ) if static_libraries and not OnWindows(): dynamic_flag = ( '--enable-framework' if OnMac() else '--enable-shared' ) sys.exit( NO_DYNAMIC_PYTHON_ERROR.format( library = static_libraries[ 0 ], flag = dynamic_flag ) ) sys.exit( NO_PYTHON_LIBRARY_ERROR ) def CustomPythonCmakeArgs(): # The CMake 'FindPythonLibs' Module does not work properly. # So we are forced to do its job for it. print( 'Searching Python {major}.{minor} libraries...'.format( major = PY_MAJOR, minor = PY_MINOR ) ) python_library, python_include = FindPythonLibraries() print( 'Found Python library: {0}'.format( python_library ) ) print( 'Found Python headers folder: {0}'.format( python_include ) ) return [ '-DPYTHON_LIBRARY={0}'.format( python_library ), '-DPYTHON_INCLUDE_DIR={0}'.format( python_include ) ] def GetGenerator( args ): if OnWindows(): if args.msvc == 14: generator = 'Visual Studio 14' elif args.msvc == 12: generator = 'Visual Studio 12' else: generator = 'Visual Studio 11' if platform.architecture()[ 0 ] == '64bit': generator = generator + ' Win64' return generator if PathToFirstExistingExecutable( ['ninja'] ): return 'Ninja' return 'Unix Makefiles' def ParseArguments(): parser = argparse.ArgumentParser() parser.add_argument( '--clang-completer', action = 'store_true', help = 'Build C-family semantic completion engine.' ) parser.add_argument( '--system-libclang', action = 'store_true', help = 'Use system libclang instead of downloading one ' 'from llvm.org. NOT RECOMMENDED OR SUPPORTED!' ) parser.add_argument( '--omnisharp-completer', action = 'store_true', help = 'Build C# semantic completion engine.' ) parser.add_argument( '--gocode-completer', action = 'store_true', help = 'Build Go semantic completion engine.' ) parser.add_argument( '--racer-completer', action = 'store_true', help = 'Build rust semantic completion engine.' ) parser.add_argument( '--system-boost', action = 'store_true', help = 'Use the system boost instead of bundled one. ' 'NOT RECOMMENDED OR SUPPORTED!') parser.add_argument( '--msvc', type = int, choices = [ 11, 12, 14 ], default = 14, help = 'Choose the Microsoft Visual ' 'Studio version (default: %(default)s).' ) parser.add_argument( '--tern-completer', action = 'store_true', help = 'Enable tern javascript completer' ), parser.add_argument( '--all', action = 'store_true', help = 'Enable all supported completers', dest = 'all_completers' ) parser.add_argument( '--enable-coverage', action = 'store_true', help = 'For developers: Enable gcov coverage for the ' 'c++ module' ) parser.add_argument( '--enable-debug', action = 'store_true', help = 'For developers: build ycm_core library with ' 'debug symbols' ) parser.add_argument( '--build-dir', help = 'For developers: perform the build in the ' 'specified directory, and do not delete the ' 'build output. This is useful for incremental ' 'builds, and required for coverage data' ) args = parser.parse_args() if args.enable_coverage: # We always want a debug build when running with coverage enabled args.enable_debug = True if ( args.system_libclang and not args.clang_completer and not args.all_completers ): sys.exit( 'ERROR: you can\'t pass --system-libclang without also passing ' '--clang-completer or --all as well.' ) return args def GetCmakeArgs( parsed_args ): cmake_args = [] if parsed_args.clang_completer or parsed_args.all_completers: cmake_args.append( '-DUSE_CLANG_COMPLETER=ON' ) if parsed_args.system_libclang: cmake_args.append( '-DUSE_SYSTEM_LIBCLANG=ON' ) if parsed_args.system_boost: cmake_args.append( '-DUSE_SYSTEM_BOOST=ON' ) if parsed_args.enable_debug: cmake_args.append( '-DCMAKE_BUILD_TYPE=Debug' ) # coverage is not supported for c++ on MSVC if not OnWindows() and parsed_args.enable_coverage: cmake_args.append( '-DCMAKE_CXX_FLAGS=-coverage' ) use_python2 = 'ON' if PY_MAJOR == 2 else 'OFF' cmake_args.append( '-DUSE_PYTHON2=' + use_python2 ) extra_cmake_args = os.environ.get( 'EXTRA_CMAKE_ARGS', '' ) # We use shlex split to properly parse quoted CMake arguments. cmake_args.extend( shlex.split( extra_cmake_args ) ) return cmake_args def RunYcmdTests( build_dir ): tests_dir = p.join( build_dir, 'ycm', 'tests' ) os.chdir( tests_dir ) new_env = os.environ.copy() if OnWindows(): # We prepend the folder of the ycm_core_tests executable to the PATH # instead of overwriting it so that the executable is able to find the # python35.dll library. new_env[ 'PATH' ] = DIR_OF_THIS_SCRIPT + ';' + new_env[ 'PATH' ] else: new_env[ 'LD_LIBRARY_PATH' ] = DIR_OF_THIS_SCRIPT CheckCall( p.join( tests_dir, 'ycm_core_tests' ), env = new_env ) # On Windows, if the ycmd library is in use while building it, a LNK1104 # fatal error will occur during linking. Exit the script early with an # error message if this is the case. def ExitIfYcmdLibInUseOnWindows(): if not OnWindows(): return ycmd_library = p.join( DIR_OF_THIS_SCRIPT, 'ycm_core.pyd' ) if not p.exists( ycmd_library ): return try: open( p.join( ycmd_library ), 'a' ).close() except IOError as error: if error.errno == errno.EACCES: sys.exit( 'ERROR: ycmd library is currently in use. ' 'Stop all ycmd instances before compilation.' ) def BuildYcmdLib( args ): if args.build_dir: build_dir = os.path.abspath( args.build_dir ) if os.path.exists( build_dir ): print( 'The supplied build directory ' + build_dir + ' exists, ' 'deleting it.' ) rmtree( build_dir, ignore_errors = OnTravisOrAppVeyor() ) os.makedirs( build_dir ) else: build_dir = mkdtemp( prefix = 'ycm_build_' ) try: full_cmake_args = [ '-G', GetGenerator( args ) ] full_cmake_args.extend( CustomPythonCmakeArgs() ) full_cmake_args.extend( GetCmakeArgs( args ) ) full_cmake_args.append( p.join( DIR_OF_THIS_SCRIPT, 'cpp' ) ) os.chdir( build_dir ) exit_message = ( 'ERROR: the build failed.\n\n' 'NOTE: it is *highly* unlikely that this is a bug but rather\n' 'that this is a problem with the configuration of your system\n' 'or a missing dependency. Please carefully read CONTRIBUTING.md\n' 'and if you\'re sure that it is a bug, please raise an issue on the\n' 'issue tracker, including the entire output of this script\n' 'and the invocation line used to run it.' ) CheckCall( [ 'cmake' ] + full_cmake_args, exit_message = exit_message ) build_target = ( 'ycm_core' if 'YCM_TESTRUN' not in os.environ else 'ycm_core_tests' ) build_command = [ 'cmake', '--build', '.', '--target', build_target ] if OnWindows(): config = 'Debug' if args.enable_debug else 'Release' build_command.extend( [ '--config', config ] ) else: build_command.extend( [ '--', '-j', str( NumCores() ) ] ) CheckCall( build_command, exit_message = exit_message ) if 'YCM_TESTRUN' in os.environ: RunYcmdTests( build_dir ) finally: os.chdir( DIR_OF_THIS_SCRIPT ) if args.build_dir: print( 'The build files are in: ' + build_dir ) else: rmtree( build_dir, ignore_errors = OnTravisOrAppVeyor() ) def BuildOmniSharp(): build_command = PathToFirstExistingExecutable( [ 'msbuild', 'msbuild.exe', 'xbuild' ] ) if not build_command: sys.exit( 'ERROR: msbuild or xbuild is required to build Omnisharp.' ) os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'OmniSharpServer' ) ) CheckCall( [ build_command, '/property:Configuration=Release' ] ) def BuildGoCode(): if not FindExecutable( 'go' ): sys.exit( 'ERROR: go is required to build gocode.' ) os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'gocode' ) ) CheckCall( [ 'go', 'build' ] ) os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'godef' ) ) CheckCall( [ 'go', 'build' ] ) def BuildRacerd(): """ Build racerd. This requires a reasonably new version of rustc/cargo. """ if not FindExecutable( 'cargo' ): sys.exit( 'ERROR: cargo is required for the Rust completer.' ) os.chdir( p.join( DIR_OF_THIRD_PARTY, 'racerd' ) ) args = [ 'cargo', 'build' ] # We don't use the --release flag on Travis/AppVeyor because it makes building # racerd 2.5x slower and we don't care about the speed of the produced racerd. if not OnTravisOrAppVeyor(): args.append( '--release' ) CheckCall( args ) def SetUpTern(): paths = {} for exe in [ 'node', 'npm' ]: path = FindExecutable( exe ) if not path: sys.exit( 'ERROR: {0} is required to set up ternjs.'.format( exe ) ) else: paths[ exe ] = path # We install Tern into a runtime directory. This allows us to control # precisely the version (and/or git commit) that is used by ycmd. We use a # separate runtime directory rather than a submodule checkout directory # because we want to allow users to install third party plugins to # node_modules of the Tern runtime. We also want to be able to install our # own plugins to improve the user experience for all users. # # This is not possible if we use a git submodule for Tern and simply run 'npm # install' within the submodule source directory, as subsequent 'npm install # tern-my-plugin' will (heinously) install another (arbitrary) version of Tern # within the Tern source tree (e.g. third_party/tern/node_modules/tern. The # reason for this is that the plugin that gets installed has "tern" as a # dependency, and npm isn't smart enough to know that you're installing # *within* the Tern distribution. Or it isn't intended to work that way. # # So instead, we have a package.json within our "Tern runtime" directory # (third_party/tern_runtime) that defines the packages that we require, # including Tern and any plugins which we require as standard. os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'tern_runtime' ) ) CheckCall( [ paths[ 'npm' ], 'install', '--production' ] ) def WritePythonUsedDuringBuild(): path = p.join( DIR_OF_THIS_SCRIPT, 'PYTHON_USED_DURING_BUILDING' ) with open( path, 'w' ) as f: f.write( sys.executable ) def Main(): CheckDeps() args = ParseArguments() ExitIfYcmdLibInUseOnWindows() BuildYcmdLib( args ) if args.omnisharp_completer or args.all_completers: BuildOmniSharp() if args.gocode_completer or args.all_completers: BuildGoCode() if args.tern_completer or args.all_completers: SetUpTern() if args.racer_completer or args.all_completers: BuildRacerd() WritePythonUsedDuringBuild() if __name__ == '__main__': Main() ycmd-0+20161219+git486b809.orig/ycmd/0000755000175000017500000000000013026170313015113 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/__main__.py0000644000175000017500000001516013026170313017210 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division # Other imports from `future` must be placed after SetUpPythonPath. import sys import os sys.path.insert( 0, os.path.dirname( os.path.abspath( __file__ ) ) ) from server_utils import SetUpPythonPath, CompatibleWithCurrentCore SetUpPythonPath() from future import standard_library standard_library.install_aliases() from builtins import * # noqa import atexit import sys import logging import json import argparse import signal import os import base64 from ycmd import extra_conf_store, user_options_store, utils from ycmd.hmac_plugin import HmacPlugin from ycmd.utils import ToBytes, ReadFile, OpenForStdHandle from ycmd.wsgi_server import StoppableWSGIServer def YcmCoreSanityCheck(): if 'ycm_core' in sys.modules: raise RuntimeError( 'ycm_core already imported, ycmd has a bug!' ) # We manually call sys.exit() on SIGTERM and SIGINT so that atexit handlers are # properly executed. def SetUpSignalHandler(): def SignalHandler( signum, frame ): sys.exit() for sig in [ signal.SIGTERM, signal.SIGINT ]: signal.signal( sig, SignalHandler ) def CleanUpLogfiles( stdout, stderr, keep_logfiles ): # We reset stderr & stdout, just in case something tries to use them if stderr: tmp = sys.stderr sys.stderr = sys.__stderr__ tmp.close() if stdout: tmp = sys.stdout sys.stdout = sys.__stdout__ tmp.close() if not keep_logfiles: if stderr: utils.RemoveIfExists( stderr ) if stdout: utils.RemoveIfExists( stdout ) def PossiblyDetachFromTerminal(): # If not on windows, detach from controlling terminal to prevent # SIGINT from killing us. if not utils.OnWindows(): try: os.setsid() # setsid() can fail if the user started ycmd directly from a shell. except OSError: pass def ParseArguments(): parser = argparse.ArgumentParser() # Not using 'localhost' on purpose; see #987 and #1130 parser.add_argument( '--host', type = str, default = '127.0.0.1', help = 'server hostname') # Default of 0 will make the OS pick a free port for us parser.add_argument( '--port', type = int, default = 0, help = 'server port') parser.add_argument( '--log', type = str, default = 'info', help = 'log level, one of ' '[debug|info|warning|error|critical]' ) parser.add_argument( '--idle_suicide_seconds', type = int, default = 0, help = 'num idle seconds before server shuts down') parser.add_argument( '--check_interval_seconds', type = int, default = 600, help = 'interval in seconds to check server ' 'inactivity and keep subservers alive' ) parser.add_argument( '--options_file', type = str, required = True, help = 'file with user options, in JSON format' ) parser.add_argument( '--stdout', type = str, default = None, help = 'optional file to use for stdout' ) parser.add_argument( '--stderr', type = str, default = None, help = 'optional file to use for stderr' ) parser.add_argument( '--keep_logfiles', action = 'store_true', default = None, help = 'retain logfiles after the server exits' ) return parser.parse_args() def SetupLogging( log_level ): numeric_level = getattr( logging, log_level.upper(), None ) if not isinstance( numeric_level, int ): raise ValueError( 'Invalid log level: %s' % log_level ) # Has to be called before any call to logging.getLogger() logging.basicConfig( format = '%(asctime)s - %(levelname)s - %(message)s', level = numeric_level ) def SetupOptions( options_file ): options = user_options_store.DefaultOptions() user_options = json.loads( ReadFile( options_file ) ) options.update( user_options ) utils.RemoveIfExists( options_file ) hmac_secret = ToBytes( base64.b64decode( options[ 'hmac_secret' ] ) ) del options[ 'hmac_secret' ] user_options_store.SetAll( options ) return options, hmac_secret def CloseStdin(): sys.stdin.close() os.close( 0 ) def Main(): args = ParseArguments() if args.stdout is not None: sys.stdout = OpenForStdHandle( args.stdout ) if args.stderr is not None: sys.stderr = OpenForStdHandle( args.stderr ) SetupLogging( args.log ) options, hmac_secret = SetupOptions( args.options_file ) # This ensures that ycm_core is not loaded before extra conf # preload was run. YcmCoreSanityCheck() extra_conf_store.CallGlobalExtraConfYcmCorePreloadIfExists() code = CompatibleWithCurrentCore() if code: sys.exit( code ) PossiblyDetachFromTerminal() # These can't be top-level imports because they transitively import # ycm_core which we want to be imported ONLY after extra conf # preload has executed. from ycmd import handlers from ycmd.watchdog_plugin import WatchdogPlugin handlers.UpdateUserOptions( options ) handlers.SetHmacSecret( hmac_secret ) handlers.KeepSubserversAlive( args.check_interval_seconds ) SetUpSignalHandler() # Functions registered by the atexit module are called at program termination # in last in, first out order. atexit.register( CleanUpLogfiles, args.stdout, args.stderr, args.keep_logfiles ) atexit.register( handlers.ServerCleanup ) handlers.app.install( WatchdogPlugin( args.idle_suicide_seconds, args.check_interval_seconds ) ) handlers.app.install( HmacPlugin( hmac_secret ) ) CloseStdin() handlers.wsgi_server = StoppableWSGIServer( handlers.app, host = args.host, port = args.port, threads = 30 ) handlers.wsgi_server.Run() if __name__ == "__main__": Main() ycmd-0+20161219+git486b809.orig/ycmd/hmac_utils.py0000644000175000017500000000632613026170313017624 0ustar onuronur# Copyright (C) 2015 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from builtins import bytes import hmac import hashlib def CreateHmac( content, hmac_secret ): # Note that py2's str type passes this check (and that's ok) if not isinstance( content, bytes ): raise TypeError( 'content was not of bytes type; you have a bug!' ) if not isinstance( hmac_secret, bytes ): raise TypeError( 'hmac_secret was not of bytes type; you have a bug!' ) return bytes( hmac.new( hmac_secret, msg = content, digestmod = hashlib.sha256 ).digest() ) def CreateRequestHmac( method, path, body, hmac_secret ): # Note that py2's str type passes this check (and that's ok) if not isinstance( body, bytes ): raise TypeError( 'body was not of bytes type; you have a bug!' ) if not isinstance( hmac_secret, bytes ): raise TypeError( 'hmac_secret was not of bytes type; you have a bug!' ) if not isinstance( method, bytes ): raise TypeError( 'method was not of bytes type; you have a bug!' ) if not isinstance( path, bytes ): raise TypeError( 'path was not of bytes type; you have a bug!' ) method_hmac = CreateHmac( method, hmac_secret ) path_hmac = CreateHmac( path, hmac_secret ) body_hmac = CreateHmac( body, hmac_secret ) joined_hmac_input = bytes().join( ( method_hmac, path_hmac, body_hmac ) ) return CreateHmac( joined_hmac_input, hmac_secret ) # This is the compare_digest function from python 3.4 # http://hg.python.org/cpython/file/460407f35aa9/Lib/hmac.py#l16 def SecureBytesEqual( a, b ): """Returns the equivalent of 'a == b', but avoids content based short circuiting to reduce the vulnerability to timing attacks.""" # Consistent timing matters more here than data type flexibility # We do NOT want to support py2's str type because iterating over them # (below) produces different results. if type( a ) != bytes or type( b ) != bytes: raise TypeError( "inputs must be bytes instances" ) # We assume the length of the expected digest is public knowledge, # thus this early return isn't leaking anything an attacker wouldn't # already know if len( a ) != len( b ): return False # We assume that integers in the bytes range are all cached, # thus timing shouldn't vary much due to integer object creation result = 0 for x, y in zip( a, b ): result |= x ^ y return result == 0 ycmd-0+20161219+git486b809.orig/ycmd/completers/0000755000175000017500000000000013026170313017270 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/javascript/0000755000175000017500000000000013026170313021436 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/javascript/hook.py0000644000175000017500000000221613026170313022751 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.javascript.tern_completer import ( ShouldEnableTernCompleter, TernCompleter ) def GetCompleter( user_options ): if not ShouldEnableTernCompleter(): return None return TernCompleter( user_options ) ycmd-0+20161219+git486b809.orig/ycmd/completers/javascript/__init__.py0000644000175000017500000000000013026170313023535 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/javascript/tern_completer.py0000644000175000017500000005556513026170313025052 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from builtins import * # noqa from future.utils import iterkeys from future import standard_library standard_library.install_aliases() import logging import os import requests import threading from subprocess import PIPE from ycmd import utils, responses from ycmd.completers.completer import Completer from ycmd.completers.completer_utils import GetFileContents _logger = logging.getLogger( __name__ ) PATH_TO_TERN_BINARY = os.path.abspath( os.path.join( os.path.dirname( __file__ ), '..', '..', '..', 'third_party', 'tern_runtime', 'node_modules', 'tern', 'bin', 'tern' ) ) PATH_TO_NODE = utils.PathToFirstExistingExecutable( [ 'node' ] ) # host name/address on which the tern server should listen # note: we use 127.0.0.1 rather than localhost because on some platforms # localhost might not be correctly configured as an alias for the loopback # address. (ahem: Windows) SERVER_HOST = '127.0.0.1' LOGFILE_FORMAT = 'tern_{port}_{std}_' def ShouldEnableTernCompleter(): """Returns whether or not the tern completer is 'installed'. That is whether or not the tern submodule has a 'node_modules' directory. This is pretty much the only way we can know if the user added '--tern-completer' on install or manually ran 'npm install' in the tern submodule directory.""" if not PATH_TO_NODE: _logger.warning( 'Not using Tern completer: unable to find node' ) return False _logger.info( 'Using node binary from: ' + PATH_TO_NODE ) installed = os.path.exists( PATH_TO_TERN_BINARY ) if not installed: _logger.info( 'Not using Tern completer: not installed at ' + PATH_TO_TERN_BINARY ) return False return True def GlobalConfigExists( tern_config ): """Returns whether or not the global config file with the supplied path exists. This method primarily exists to allow testability and simply returns whether the supplied file exists.""" return os.path.exists( tern_config ) def FindTernProjectFile( starting_directory ): """Finds the path to either a Tern project file or the user's global Tern configuration file. If found, a tuple is returned containing the path and a boolean indicating if the path is to a .tern-project file. If not found, returns (None, False).""" for folder in utils.PathsToAllParentFolders( starting_directory ): tern_project = os.path.join( folder, '.tern-project' ) if os.path.exists( tern_project ): return ( tern_project, True ) # As described here: http://ternjs.net/doc/manual.html#server a global # .tern-config file is also supported for the Tern server. This can provide # meaningful defaults (for libs, and possibly also for require paths), so # don't warn if we find one. The point is that if the user has a .tern-config # set up, then she has deliberately done so and a ycmd warning is unlikely # to be anything other than annoying. tern_config = os.path.expanduser( '~/.tern-config' ) if GlobalConfigExists( tern_config ): return ( tern_config, False ) return ( None, False ) class TernCompleter( Completer ): """Completer for JavaScript using tern.js: http://ternjs.net. The protocol is defined here: http://ternjs.net/doc/manual.html#protocol""" def __init__( self, user_options ): super( TernCompleter, self ).__init__( user_options ) self._server_keep_logfiles = user_options[ 'server_keep_logfiles' ] # Used to ensure that starting/stopping of the server is synchronised self._server_state_mutex = threading.RLock() self._do_tern_project_check = False # Used to determine the absolute path of files returned by the tern server. # When a .tern_project file exists, paths are returned relative to it. # Otherwise, they are returned relative to the working directory of the tern # server. self._server_paths_relative_to = None self._server_handle = None self._server_port = None self._server_stdout = None self._server_stderr = None self._StartServer() def _WarnIfMissingTernProject( self ): # The Tern server will operate without a .tern-project file. However, it # does not operate optimally, and will likely lead to issues reported that # JavaScript completion is not working properly. So we raise a warning if we # aren't able to detect some semblance of manual Tern configuration. # We do this check after the server has started because the server does # have nonzero use without a project file, however limited. We only do this # check once, though because the server can only handle one project at a # time. This doesn't catch opening a file which is not part of the project # or any of those things, but we can only do so much. We'd like to enhance # ycmd to handle this better, but that is a FIXME for now. if self._ServerIsRunning() and self._do_tern_project_check: self._do_tern_project_check = False current_dir = utils.GetCurrentDirectory() ( tern_project, is_project ) = FindTernProjectFile( current_dir ) if not tern_project: _logger.warning( 'No .tern-project file detected: ' + current_dir ) raise RuntimeError( 'Warning: Unable to detect a .tern-project file ' 'in the hierarchy before ' + current_dir + ' and no global .tern-config file was found. ' 'This is required for accurate JavaScript ' 'completion. Please see the User Guide for ' 'details.' ) else: _logger.info( 'Detected Tern configuration file at: ' + tern_project ) # Paths are relative to the project file if it exists, otherwise they # are relative to the working directory of Tern server (which is the # same as the working directory of ycmd). self._server_paths_relative_to = ( os.path.dirname( tern_project ) if is_project else current_dir ) _logger.info( 'Tern paths are relative to: ' + self._server_paths_relative_to ) def _GetServerAddress( self ): return 'http://' + SERVER_HOST + ':' + str( self._server_port ) def ComputeCandidatesInner( self, request_data ): query = { 'type': 'completions', 'types': True, 'docs': True, 'filter': False, 'caseInsensitive': True, 'guess': False, 'sort': False, 'includeKeywords': False, 'expandWordForward': False, 'omitObjectPrototype': False } completions = self._GetResponse( query, request_data[ 'start_codepoint' ], request_data ).get( 'completions', [] ) def BuildDoc( completion ): doc = completion.get( 'type', 'Unknown type' ) if 'doc' in completion: doc = doc + '\n' + completion[ 'doc' ] return doc return [ responses.BuildCompletionData( completion[ 'name' ], completion.get( 'type', '?' ), BuildDoc( completion ) ) for completion in completions ] def OnFileReadyToParse( self, request_data ): self._WarnIfMissingTernProject() # Keep tern server up to date with the file data. We do this by sending an # empty request just containing the file data try: self._PostRequest( {}, request_data ) except: # The server might not be ready yet or the server might not be running. # in any case, just ignore this we'll hopefully get another parse request # soon. pass def GetSubcommandsMap( self ): return { 'RestartServer': ( lambda self, request_data, args: self._RestartServer() ), 'StopServer': ( lambda self, request_data, args: self._StopServer() ), 'GoToDefinition': ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoTo': ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToReferences': ( lambda self, request_data, args: self._GoToReferences( request_data ) ), 'GetType': ( lambda self, request_data, args: self._GetType( request_data) ), 'GetDoc': ( lambda self, request_data, args: self._GetDoc( request_data) ), 'RefactorRename': ( lambda self, request_data, args: self._Rename( request_data, args ) ), } def SupportedFiletypes( self ): return [ 'javascript' ] def DebugInfo( self, request_data ): with self._server_state_mutex: if self._ServerIsRunning(): return ( 'JavaScript completer debug information:\n' ' Tern running at: {0}\n' ' Tern process ID: {1}\n' ' Tern executable: {2}\n' ' Tern logfiles:\n' ' {3}\n' ' {4}'.format( self._GetServerAddress(), self._server_handle.pid, PATH_TO_TERN_BINARY, self._server_stdout, self._server_stderr ) ) if self._server_stdout and self._server_stderr: return ( 'JavaScript completer debug information:\n' ' Tern no longer running\n' ' Tern executable: {0}\n' ' Tern logfiles:\n' ' {1}\n' ' {2}\n'.format( PATH_TO_TERN_BINARY, self._server_stdout, self._server_stderr ) ) return ( 'JavaScript completer debug information:\n' ' Tern is not running\n' ' Tern executable: {0}'.format( PATH_TO_TERN_BINARY ) ) def Shutdown( self ): _logger.debug( "Shutting down Tern server" ) self._StopServer() def ServerIsHealthy( self, request_data = {} ): if not self._ServerIsRunning(): return False try: target = self._GetServerAddress() + '/ping' response = requests.get( target ) return response.status_code == requests.codes.ok except requests.ConnectionError: return False def _PostRequest( self, request, request_data ): """Send a raw request with the supplied request block, and return the server's response. If the server is not running, it is started. This method is useful where the query block is not supplied, i.e. where just the files are being updated. The request block should contain the optional query block only. The file data are added automatically.""" if not self._ServerIsRunning(): raise ValueError( 'Not connected to server' ) def MakeIncompleteFile( name, file_data ): return { 'type': 'full', 'name': name, 'text': file_data[ 'contents' ], } file_data = request_data.get( 'file_data', {} ) full_request = { 'files': [ MakeIncompleteFile( x, file_data[ x ] ) for x in iterkeys( file_data ) if 'javascript' in file_data[ x ][ 'filetypes' ] ], } full_request.update( request ) response = requests.post( self._GetServerAddress(), json = full_request ) if response.status_code != requests.codes.ok: raise RuntimeError( response.text ) return response.json() def _GetResponse( self, query, codepoint, request_data ): """Send a standard file/line request with the supplied query block, and return the server's response. If the server is not running, it is started. This method should be used for almost all requests. The exception is when just updating file data in which case _PostRequest should be used directly. The query block should contain the type and any parameters. The files, position, etc. are added automatically. NOTE: the |codepoint| parameter is usually the current cursor position, though it should be the "completion start column" codepoint for completion requests.""" def MakeTernLocation( request_data ): return { 'line': request_data[ 'line_num' ] - 1, 'ch': codepoint - 1 } full_query = { 'file': request_data[ 'filepath' ], 'end': MakeTernLocation( request_data ), 'lineCharPositions': True, } full_query.update( query ) return self._PostRequest( { 'query': full_query }, request_data ) def _ServerPathToAbsolute( self, path ): """Given a path returned from the tern server, return it as an absolute path. In particular, if the path is a relative path, return an absolute path assuming that it is relative to the location of the .tern-project file.""" if os.path.isabs( path ): return path return os.path.join( self._server_paths_relative_to, path ) # TODO: this function is way too long. Consider refactoring it. def _StartServer( self ): with self._server_state_mutex: if self._ServerIsRunning(): return _logger.info( 'Starting Tern server...' ) self._server_port = utils.GetUnusedLocalhostPort() if _logger.isEnabledFor( logging.DEBUG ): extra_args = [ '--verbose' ] else: extra_args = [] command = [ PATH_TO_NODE, PATH_TO_TERN_BINARY, '--port', str( self._server_port ), '--host', SERVER_HOST, '--persistent', '--no-port-file' ] + extra_args _logger.debug( 'Starting tern with the following command: ' + ' '.join( command ) ) try: self._server_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._server_port, std = 'stdout' ) ) self._server_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._server_port, std = 'stderr' ) ) # We need to open a pipe to stdin or the Tern server is killed. # See https://github.com/ternjs/tern/issues/740#issuecomment-203979749 # For unknown reasons, this is only needed on Windows and for Python # 3.4+ on other platforms. with utils.OpenForStdHandle( self._server_stdout ) as stdout: with utils.OpenForStdHandle( self._server_stderr ) as stderr: self._server_handle = utils.SafePopen( command, stdin = PIPE, stdout = stdout, stderr = stderr ) except Exception: _logger.exception( 'Unable to start Tern server' ) self._CleanUp() if self._server_port and self._ServerIsRunning(): _logger.info( 'Tern Server started with pid: ' + str( self._server_handle.pid ) + ' listening on port ' + str( self._server_port ) ) _logger.info( 'Tern Server log files are: ' + self._server_stdout + ' and ' + self._server_stderr ) self._do_tern_project_check = True else: _logger.warning( 'Tern server did not start successfully' ) def _RestartServer( self ): with self._server_state_mutex: self._StopServer() self._StartServer() def _StopServer( self ): with self._server_state_mutex: if self._ServerIsRunning(): _logger.info( 'Stopping Tern server with PID {0}'.format( self._server_handle.pid ) ) self._server_handle.terminate() try: utils.WaitUntilProcessIsTerminated( self._server_handle, timeout = 5 ) _logger.info( 'Tern server stopped' ) except RuntimeError: _logger.exception( 'Error while stopping Tern server' ) self._CleanUp() def _CleanUp( self ): utils.CloseStandardStreams( self._server_handle ) self._server_handle = None self._server_port = None if not self._server_keep_logfiles: utils.RemoveIfExists( self._server_stdout ) self._server_stdout = None utils.RemoveIfExists( self._server_stderr ) self._server_stderr = None def _ServerIsRunning( self ): return utils.ProcessIsRunning( self._server_handle ) def _GetType( self, request_data ): query = { 'type': 'type', } response = self._GetResponse( query, request_data[ 'column_codepoint' ], request_data ) return responses.BuildDisplayMessageResponse( response[ 'type' ] ) def _GetDoc( self, request_data ): # Note: we use the 'type' request because this is the best # way to get the name, type and doc string. The 'documentation' request # doesn't return the 'name' (strangely), wheras the 'type' request returns # the same docs with extra info. query = { 'type': 'type', 'docFormat': 'full', 'types': True } response = self._GetResponse( query, request_data[ 'column_codepoint' ], request_data ) doc_string = 'Name: {name}\nType: {type}\n\n{doc}'.format( name = response.get( 'name', 'Unknown' ), type = response.get( 'type', 'Unknown' ), doc = response.get( 'doc', 'No documentation available' ) ) return responses.BuildDetailedInfoResponse( doc_string ) def _GoToDefinition( self, request_data ): query = { 'type': 'definition', } response = self._GetResponse( query, request_data[ 'column_codepoint' ], request_data ) filepath = self._ServerPathToAbsolute( response[ 'file' ] ) return responses.BuildGoToResponseFromLocation( _BuildLocation( utils.SplitLines( GetFileContents( request_data, filepath ) ), filepath, response[ 'start' ][ 'line' ], response[ 'start' ][ 'ch' ] ) ) def _GoToReferences( self, request_data ): query = { 'type': 'refs', } response = self._GetResponse( query, request_data[ 'column_codepoint' ], request_data ) def BuildRefResponse( ref ): filepath = self._ServerPathToAbsolute( ref[ 'file' ] ) return responses.BuildGoToResponseFromLocation( _BuildLocation( utils.SplitLines( GetFileContents( request_data, filepath ) ), filepath, ref[ 'start' ][ 'line' ], ref[ 'start' ][ 'ch' ] ) ) return [ BuildRefResponse( ref ) for ref in response[ 'refs' ] ] def _Rename( self, request_data, args ): if len( args ) != 1: raise ValueError( 'Please specify a new name to rename it to.\n' 'Usage: RefactorRename ' ) query = { 'type': 'rename', 'newName': args[ 0 ], } response = self._GetResponse( query, request_data[ 'column_codepoint' ], request_data ) # Tern response format: # 'changes': [ # { # 'file' (potentially relative path) # 'start' { # 'line' # 'ch' (codepoint offset) # } # 'end' { # 'line' # 'ch' (codepoint offset) # } # 'text' # } # ] # ycmd response format: # # { # 'fixits': [ # 'chunks': (list) [ # { # 'replacement_text', # 'range' (Range) { # 'start_' (Location): { # 'line_number_', # 'column_number_', (byte offset) # 'filename_' (note: absolute path!) # }, # 'end_' (Location): { # 'line_number_', # 'column_number_', (byte offset) # 'filename_' (note: absolute path!) # } # } # } # ], # 'location' (Location) { # 'line_number_', # 'column_number_', # 'filename_' (note: absolute path!) # } # # ] # } def BuildRange( file_contents, filename, start, end ): return responses.Range( _BuildLocation( file_contents, filename, start[ 'line' ], start[ 'ch' ] ), _BuildLocation( file_contents, filename, end[ 'line' ], end[ 'ch' ] ) ) def BuildFixItChunk( change ): filepath = self._ServerPathToAbsolute( change[ 'file' ] ) file_contents = utils.SplitLines( GetFileContents( request_data, filepath ) ) return responses.FixItChunk( change[ 'text' ], BuildRange( file_contents, filepath, change[ 'start' ], change[ 'end' ] ) ) # From an API perspective, Refactor and FixIt are the same thing - it just # applies a set of changes to a set of files. So we re-use all of the # existing FixIt infrastructure. return responses.BuildFixItResponse( [ responses.FixIt( responses.Location( request_data[ 'line_num' ], request_data[ 'column_num' ], request_data[ 'filepath' ] ), [ BuildFixItChunk( x ) for x in response[ 'changes' ] ] ) ] ) def _BuildLocation( file_contents, filename, line, ch ): # tern returns codepoint offsets, but we need byte offsets, so we must # convert return responses.Location( line = line + 1, column = utils.CodepointOffsetToByteOffset( file_contents[ line ], ch + 1 ), filename = os.path.realpath( filename ) ) ycmd-0+20161219+git486b809.orig/ycmd/completers/general_completer.py0000644000175000017500000000267213026170313023340 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.completer import Completer class GeneralCompleter( Completer ): """ A base class for General completers in YCM. A general completer is used in all filetypes. Because this is a subclass of Completer class, you should refer to the Completer class documentation. Do NOT use this class for semantic completers! Subclass Completer directly. """ def __init__( self, user_options ): super( GeneralCompleter, self ).__init__( user_options ) def SupportedFiletypes( self ): return set() ycmd-0+20161219+git486b809.orig/ycmd/completers/completer.py0000644000175000017500000003652613026170313021650 0ustar onuronur# Copyright (C) 2011, 2012, 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import abc import threading from ycmd.utils import ForceSemanticCompletion from ycmd.completers import completer_utils from ycmd.responses import NoDiagnosticSupport from future.utils import with_metaclass NO_USER_COMMANDS = 'This completer does not define any commands.' class Completer( with_metaclass( abc.ABCMeta, object ) ): """A base class for all Completers in YCM. Here's several important things you need to know if you're writing a custom Completer. The following are functions that the Vim part of YCM will be calling on your Completer: *Important note about unicode and byte offsets* Useful background: http://utf8everywhere.org Internally, all Python strings are unicode string objects, unless otherwise converted to 'bytes' using ToBytes. In particular, the line_value and file_data.contents entries in the request_data are unicode strings. However, offsets in the API (such as column_num and start_column) are *byte* offsets into a utf-8 encoded version of the contents of the line or buffer. Therefore it is *never* safe to perform 'character' arithmetic (such as '-1' to get the previous 'character') using these byte offsets, and they cannot *ever* be used to index into line_value or buffer contents unicode strings. It is therefore important to ensure that you use the right type of offsets for the right type of calculation: - use codepoint offsets and a unicode string for 'character' calculations - use byte offsets and utf-8 encoded bytes for all other manipulations ycmd provides the following ways of accessing the source data and offsets: For working with utf-8 encoded bytes: - request_data[ 'line_bytes' ] - the line as utf-8 encoded bytes. - request_data[ 'start_column' ] and request_data[ 'column_num' ]. For working with 'character' manipulations (unicode strings and codepoint offsets): - request_data[ 'line_value' ] - the line as a unicode string. - request_data[ 'start_codepoint' ] and request_data[ 'column_codepoint' ]. For converting between the two: - utils.ToBytes - utils.ByteOffsetToCodepointOffset - utils.ToUnicode - utils.CodepointOffsetToByteOffset Note: The above use of codepoints for 'character' manipulations is not strictly correct. There are unicode 'characters' which consume multiple codepoints. However, it is currently considered viable to use a single codepoint = a single character until such a time as we improve support for unicode identifiers. The purpose of the above rule is to prevent crashes and random encoding exceptions, not to fully support unicode identifiers. *END: Important note about unicode and byte offsets* ShouldUseNow() is called with the start column of where a potential completion string should start and the current line (string) the cursor is on. For instance, if the user's input is 'foo.bar' and the cursor is on the 'r' in 'bar', start_column will be the 1-based byte index of 'b' in the line. Your implementation of ShouldUseNow() should return True if your semantic completer should be used and False otherwise. This is important to get right. You want to return False if you can't provide completions because then the identifier completer will kick in, and that's better than nothing. Note that it's HIGHLY likely that you want to override the ShouldUseNowInner() function instead of ShouldUseNow() directly (although chances are that you probably won't have any need to override either). ShouldUseNow() will call your *Inner version of the function and will also make sure that the completion cache is taken into account. You'll see this pattern repeated throughout the Completer API; YCM calls the "main" version of the function and that function calls the *Inner version while taking into account the cache. The cache is important and is a nice performance boost. When the user types in "foo.", your completer will return a list of all member functions and variables that can be accessed on the "foo" object. The Completer API caches this list. The user will then continue typing, let's say "foo.ba". On every keystroke after the dot, the Completer API will take the cache into account and will NOT re-query your completer but will in fact provide fuzzy-search on the candidate strings that were stored in the cache. ComputeCandidates() is the main entry point when the user types. For "foo.bar", the user query is "bar" and completions matching this string should be shown. It should return the list of candidates. The format of the result can be a list of strings or a more complicated list of dictionaries. Use ycmd.responses.BuildCompletionData to build the detailed response. See clang_completer.py to see how its used in practice. Again, you probably want to override ComputeCandidatesInner(). You also need to implement the SupportedFiletypes() function which should return a list of strings, where the strings are Vim filetypes your completer supports. clang_completer.py is a good example of a "complicated" completer. A good example of a simple completer is ultisnips_completer.py. The On* functions are provided for your convenience. They are called when their specific events occur. For instance, the identifier completer collects all the identifiers in the file in OnFileReadyToParse() which gets called when the user stops typing for 2 seconds (Vim's CursorHold and CursorHoldI events). One special function is OnUserCommand. It is called when the user uses the command :YcmCompleter and is passed all extra arguments used on command invocation (e.g. OnUserCommand(['first argument', 'second'])). This can be used for completer-specific commands such as reloading external configuration. Do not override this function. Instead, you need to implement the GetSubcommandsMap method. It should return a map between the user commands and the methods of your completer. See the documentation of this method for more informations on how to implement it. Override the Shutdown() member function if your Completer subclass needs to do custom cleanup logic on server shutdown. If your completer uses an external server process, then it can be useful to implement the ServerIsHealthy member function to handle the /healthy request. This is very useful for the test suite.""" def __init__( self, user_options ): self.user_options = user_options self.min_num_chars = user_options[ 'min_num_of_chars_for_completion' ] self.prepared_triggers = ( completer_utils.PreparedTriggers( user_trigger_map = user_options[ 'semantic_triggers' ], filetype_set = set( self.SupportedFiletypes() ) ) if user_options[ 'auto_trigger' ] else None ) self._completions_cache = CompletionsCache() def CompletionType( self, request_data ): return 0 # It's highly likely you DON'T want to override this function but the *Inner # version of it. def ShouldUseNow( self, request_data ): if not self.ShouldUseNowInner( request_data ): self._completions_cache.Invalidate() return False # We have to do the cache valid check and get the completions as part of one # call because we have to ensure a different thread doesn't change the cache # data. cache_completions = self._completions_cache.GetCompletionsIfCacheValid( request_data[ 'line_num' ], request_data[ 'start_column' ], self.CompletionType( request_data ) ) # If None, then the cache isn't valid and we know we should return true if cache_completions is None: return True else: previous_results_were_valid = bool( cache_completions ) return previous_results_were_valid def ShouldUseNowInner( self, request_data ): if not self.prepared_triggers: return False current_line = request_data[ 'line_value' ] start_codepoint = request_data[ 'start_codepoint' ] - 1 column_codepoint = request_data[ 'column_codepoint' ] - 1 filetype = self._CurrentFiletype( request_data[ 'filetypes' ] ) return self.prepared_triggers.MatchesForFiletype( current_line, start_codepoint, column_codepoint, filetype ) def QueryLengthAboveMinThreshold( self, request_data ): # Note: calculation in 'characters' not bytes. query_length = ( request_data[ 'column_codepoint' ] - request_data[ 'start_codepoint' ] ) return query_length >= self.min_num_chars # It's highly likely you DON'T want to override this function but the *Inner # version of it. def ComputeCandidates( self, request_data ): if ( not ForceSemanticCompletion( request_data ) and not self.ShouldUseNow( request_data ) ): return [] candidates = self._GetCandidatesFromSubclass( request_data ) if request_data[ 'query' ]: candidates = self.FilterAndSortCandidates( candidates, request_data[ 'query' ] ) return candidates def _GetCandidatesFromSubclass( self, request_data ): cache_completions = self._completions_cache.GetCompletionsIfCacheValid( request_data[ 'line_num' ], request_data[ 'start_column' ], self.CompletionType( request_data ) ) if cache_completions: return cache_completions else: raw_completions = self.ComputeCandidatesInner( request_data ) self._completions_cache.Update( request_data[ 'line_num' ], request_data[ 'start_column' ], self.CompletionType( request_data ), raw_completions ) return raw_completions def ComputeCandidatesInner( self, request_data ): pass # pragma: no cover def DefinedSubcommands( self ): subcommands = sorted( self.GetSubcommandsMap().keys() ) try: # We don't want expose this subcommand because it is not really needed # for the user but it is useful in tests for tearing down the server subcommands.remove( 'StopServer' ) except ValueError: pass return subcommands def GetSubcommandsMap( self ): """This method should return a dictionary where each key represents the completer command name and its value is a lambda function of this form: ( self, request_data, args ) -> method where "method" is the call to the completer method with corresponding parameters. See the already implemented completers for examples. Arguments: - request_data : the request data supplied by the client - args: any additional command arguments (after the command name). Usually empty. """ return {} def UserCommandsHelpMessage( self ): subcommands = self.DefinedSubcommands() if subcommands: return ( 'Supported commands are:\n' + '\n'.join( subcommands ) + '\nSee the docs for information on what they do.' ) else: return 'This Completer has no supported subcommands.' def FilterAndSortCandidates( self, candidates, query ): if not candidates: return [] # We need to handle both an omni_completer style completer and a server # style completer if isinstance( candidates, dict ) and 'words' in candidates: candidates = candidates[ 'words' ] sort_property = '' if isinstance( candidates[ 0 ], dict ): if 'word' in candidates[ 0 ]: sort_property = 'word' elif 'insertion_text' in candidates[ 0 ]: sort_property = 'insertion_text' return self.FilterAndSortCandidatesInner( candidates, sort_property, query ) def FilterAndSortCandidatesInner( self, candidates, sort_property, query ): return completer_utils.FilterAndSortCandidatesWrap( candidates, sort_property, query ) def OnFileReadyToParse( self, request_data ): pass # pragma: no cover def OnBufferVisit( self, request_data ): pass # pragma: no cover def OnBufferUnload( self, request_data ): pass # pragma: no cover def OnInsertLeave( self, request_data ): pass # pragma: no cover def OnUserCommand( self, arguments, request_data ): if not arguments: raise ValueError( self.UserCommandsHelpMessage() ) command_map = self.GetSubcommandsMap() try: command = command_map[ arguments[ 0 ] ] except KeyError: raise ValueError( self.UserCommandsHelpMessage() ) return command( self, request_data, arguments[ 1: ] ) def OnCurrentIdentifierFinished( self, request_data ): pass # pragma: no cover def GetDiagnosticsForCurrentFile( self, request_data ): raise NoDiagnosticSupport def GetDetailedDiagnostic( self, request_data ): raise NoDiagnosticSupport def _CurrentFiletype( self, filetypes ): supported = self.SupportedFiletypes() for filetype in filetypes: if filetype in supported: return filetype return filetypes[0] @abc.abstractmethod def SupportedFiletypes( self ): return set() def DebugInfo( self, request_data ): return '' def Shutdown( self ): pass # pragma: no cover def ServerIsReady( self ): return self.ServerIsHealthy() def ServerIsHealthy( self ): """Called by the /healthy handler to check if the underlying completion server is started and ready to receive requests. Returns bool.""" return True class CompletionsCache( object ): """Completions for a particular request. Importantly, columns are byte offsets, not unicode codepoints.""" def __init__( self ): self._access_lock = threading.Lock() self.Invalidate() def Invalidate( self ): with self._access_lock: self._line_num = None self._start_column = None self._completion_type = None self._completions = None # start_column is a byte offset. def Update( self, line_num, start_column, completion_type, completions ): with self._access_lock: self._line_num = line_num self._start_column = start_column self._completion_type = completion_type self._completions = completions # start_column is a byte offset. def GetCompletionsIfCacheValid( self, line_num, start_column, completion_type ): with self._access_lock: if not self._CacheValidNoLock( line_num, start_column, completion_type ): return None return self._completions # start_column is a byte offset. def _CacheValidNoLock( self, line_num, start_column, completion_type ): return ( line_num == self._line_num and start_column == self._start_column and completion_type == self._completion_type ) ycmd-0+20161219+git486b809.orig/ycmd/completers/__init__.py0000644000175000017500000000000013026170313021367 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/rust/0000755000175000017500000000000013026170313020265 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/rust/hook.py0000644000175000017500000000206013026170313021575 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.rust.rust_completer import RustCompleter def GetCompleter( user_options ): return RustCompleter( user_options ) ycmd-0+20161219+git486b809.orig/ycmd/completers/rust/rust_completer.py0000644000175000017500000003633113026170313023714 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from builtins import * # noqa from future.utils import native, iteritems from future import standard_library standard_library.install_aliases() from ycmd.utils import ToBytes, SetEnviron, ProcessIsRunning from ycmd.completers.completer import Completer from ycmd import responses, utils, hmac_utils import logging import urllib.parse import requests import json import tempfile import base64 import binascii import threading import os from os import path as p _logger = logging.getLogger( __name__ ) DIR_OF_THIRD_PARTY = p.abspath( p.join( p.dirname( __file__ ), '..', '..', '..', 'third_party' ) ) RACERD_BINARY_NAME = 'racerd' + ( '.exe' if utils.OnWindows() else '' ) RACERD_BINARY_RELEASE = p.join( DIR_OF_THIRD_PARTY, 'racerd', 'target', 'release', RACERD_BINARY_NAME ) RACERD_BINARY_DEBUG = p.join( DIR_OF_THIRD_PARTY, 'racerd', 'target', 'debug', RACERD_BINARY_NAME ) RACERD_HMAC_HEADER = 'x-racerd-hmac' HMAC_SECRET_LENGTH = 16 BINARY_NOT_FOUND_MESSAGE = ( 'racerd binary not found. Did you build it? ' 'You can do so by running "./build.py --racer-completer".' ) NON_EXISTING_RUST_SOURCES_PATH_MESSAGE = ( 'Rust sources path does not exist. Check the value of the rust_src_path ' 'option or the RUST_SRC_PATH environment variable.' ) ERROR_FROM_RACERD_MESSAGE = ( 'Received error from racerd while retrieving completions. You did not ' 'set the rust_src_path option, which is probably causing this issue. ' 'See YCM docs for details.' ) LOGFILE_FORMAT = 'racerd_{port}_{std}_' def FindRacerdBinary( user_options ): """ Find path to racerd binary This function prefers the 'racerd_binary_path' value as provided in user_options if available. It then falls back to ycmd's racerd build. If that's not found, attempts to use racerd from current path. """ racerd_user_binary = user_options.get( 'racerd_binary_path' ) if racerd_user_binary: # The user has explicitly specified a path. if os.path.isfile( racerd_user_binary ): return racerd_user_binary _logger.warning( 'User-provided racerd_binary_path does not exist.' ) if os.path.isfile( RACERD_BINARY_RELEASE ): return RACERD_BINARY_RELEASE # We want to support using the debug binary for the sake of debugging; also, # building the release version on Travis takes too long. if os.path.isfile( RACERD_BINARY_DEBUG ): _logger.warning( 'Using racerd DEBUG binary; performance will suffer!' ) return RACERD_BINARY_DEBUG return utils.PathToFirstExistingExecutable( [ 'racerd' ] ) class RustCompleter( Completer ): """ A completer for the rust programming language backed by racerd. https://github.com/jwilm/racerd """ def __init__( self, user_options ): super( RustCompleter, self ).__init__( user_options ) self._racerd_binary = FindRacerdBinary( user_options ) self._racerd_host = None self._server_state_lock = threading.RLock() self._keep_logfiles = user_options[ 'server_keep_logfiles' ] self._hmac_secret = '' self._rust_source_path = self._GetRustSrcPath() if not self._rust_source_path: _logger.warning( 'No path provided for the rustc source. Please set the ' 'rust_src_path option' ) elif not p.isdir( self._rust_source_path ): _logger.error( NON_EXISTING_RUST_SOURCES_PATH_MESSAGE ) raise RuntimeError( NON_EXISTING_RUST_SOURCES_PATH_MESSAGE ) if not self._racerd_binary: _logger.error( BINARY_NOT_FOUND_MESSAGE ) raise RuntimeError( BINARY_NOT_FOUND_MESSAGE ) self._StartServer() def _GetRustSrcPath( self ): """ Attempt to read user option for rust_src_path. Fallback to environment variable if it's not provided. """ rust_src_path = self.user_options[ 'rust_src_path' ] # Early return if user provided config if rust_src_path: return rust_src_path # Fall back to environment variable env_key = 'RUST_SRC_PATH' if env_key in os.environ: return os.environ[ env_key ] return None def SupportedFiletypes( self ): return [ 'rust' ] def _GetResponse( self, handler, request_data = None, method = 'POST'): """ Query racerd via HTTP racerd returns JSON with 200 OK responses. 204 No Content responses occur when no errors were encountered but no completions, definitions, or errors were found. """ _logger.info( 'RustCompleter._GetResponse' ) handler = ToBytes( handler ) method = ToBytes( method ) url = urllib.parse.urljoin( ToBytes( self._racerd_host ), handler ) parameters = self._ConvertToRacerdRequest( request_data ) body = ToBytes( json.dumps( parameters ) ) if parameters else bytes() extra_headers = self._ExtraHeaders( method, handler, body ) _logger.debug( 'Making racerd request: %s %s %s %s', method, url, extra_headers, body ) # Failing to wrap the method & url bytes objects in `native()` causes HMAC # failures (403 Forbidden from racerd) for unknown reasons. Similar for # request_hmac above. response = requests.request( native( method ), native( url ), data = body, headers = extra_headers ) response.raise_for_status() if response.status_code == requests.codes.no_content: return None return response.json() def _ExtraHeaders( self, method, handler, body ): if not body: body = bytes() hmac = hmac_utils.CreateRequestHmac( method, handler, body, self._hmac_secret ) final_hmac_value = native( ToBytes( binascii.hexlify( hmac ) ) ) extra_headers = { 'content-type': 'application/json' } extra_headers[ RACERD_HMAC_HEADER ] = final_hmac_value return extra_headers def _ConvertToRacerdRequest( self, request_data ): """ Transform ycm request into racerd request """ if not request_data: return None file_path = request_data[ 'filepath' ] buffers = [] for path, obj in iteritems( request_data[ 'file_data' ] ): buffers.append( { 'contents': obj[ 'contents' ], 'file_path': path } ) line = request_data[ 'line_num' ] col = request_data[ 'column_num' ] - 1 return { 'buffers': buffers, 'line': line, 'column': col, 'file_path': file_path } def _GetExtraData( self, completion ): location = {} if completion[ 'file_path' ]: location[ 'filepath' ] = completion[ 'file_path' ] if completion[ 'line' ]: location[ 'line_num' ] = completion[ 'line' ] if completion[ 'column' ]: location[ 'column_num' ] = completion[ 'column' ] + 1 if location: return { 'location': location } return None def ComputeCandidatesInner( self, request_data ): try: completions = self._FetchCompletions( request_data ) except requests.HTTPError: if not self._rust_source_path: raise RuntimeError( ERROR_FROM_RACERD_MESSAGE ) raise if not completions: return [] return [ responses.BuildCompletionData( insertion_text = completion[ 'text' ], kind = completion[ 'kind' ], extra_menu_info = completion[ 'context' ], extra_data = self._GetExtraData( completion ) ) for completion in completions ] def _FetchCompletions( self, request_data ): return self._GetResponse( '/list_completions', request_data ) def _StartServer( self ): with self._server_state_lock: port = utils.GetUnusedLocalhostPort() self._hmac_secret = self._CreateHmacSecret() # racerd will delete the secret_file after it's done reading it with tempfile.NamedTemporaryFile( delete = False ) as secret_file: secret_file.write( self._hmac_secret ) args = [ self._racerd_binary, 'serve', '--port', str( port ), '-l', '--secret-file', secret_file.name ] # Enable logging of crashes env = os.environ.copy() SetEnviron( env, 'RUST_BACKTRACE', '1' ) if self._rust_source_path: args.extend( [ '--rust-src-path', self._rust_source_path ] ) self._server_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format( port = port, std = 'stdout' ) ) self._server_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format( port = port, std = 'stderr' ) ) with utils.OpenForStdHandle( self._server_stderr ) as fstderr: with utils.OpenForStdHandle( self._server_stdout ) as fstdout: self._racerd_phandle = utils.SafePopen( args, stdout = fstdout, stderr = fstderr, env = env ) self._racerd_host = 'http://127.0.0.1:{0}'.format( port ) if not self._ServerIsRunning(): raise RuntimeError( 'Failed to start racerd!' ) _logger.info( 'Racerd started on: ' + self._racerd_host ) def _ServerIsRunning( self ): """ Check if racerd is alive. That doesn't necessarily mean it's ready to serve requests; that's checked by ServerIsHealthy. """ with self._server_state_lock: return ( bool( self._racerd_host ) and ProcessIsRunning( self._racerd_phandle ) ) def ServerIsHealthy( self ): """ Check if racerd is alive AND ready to serve requests. """ if not self._ServerIsRunning(): _logger.debug( 'Racerd not running.' ) return False try: self._GetResponse( '/ping', method = 'GET' ) return True # Do NOT make this except clause more generic! If you need to catch more # exception types, list them all out. Having `Exception` here caused FORTY # HOURS OF DEBUGGING. except requests.exceptions.ConnectionError as e: _logger.exception( e ) return False def _StopServer( self ): with self._server_state_lock: if self._racerd_phandle: _logger.info( 'Stopping Racerd with PID {0}'.format( self._racerd_phandle.pid ) ) self._racerd_phandle.terminate() try: utils.WaitUntilProcessIsTerminated( self._racerd_phandle, timeout = 5 ) _logger.info( 'Racerd stopped' ) except RuntimeError: _logger.exception( 'Error while stopping Racerd' ) self._CleanUp() def _CleanUp( self ): self._racerd_phandle = None self._racerd_host = None if not self._keep_logfiles: if self._server_stdout: utils.RemoveIfExists( self._server_stdout ) self._server_stdout = None if self._server_stderr: utils.RemoveIfExists( self._server_stderr ) self._server_stderr = None def _RestartServer( self ): _logger.debug( 'RustCompleter restarting racerd' ) with self._server_state_lock: if self._ServerIsRunning(): self._StopServer() self._StartServer() _logger.debug( 'RustCompleter has restarted racerd' ) def GetSubcommandsMap( self ): return { 'GoTo' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDefinition' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDeclaration' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'StopServer' : ( lambda self, request_data, args: self._StopServer() ), 'RestartServer' : ( lambda self, request_data, args: self._RestartServer() ), 'GetDoc' : ( lambda self, request_data, args: self._GetDoc( request_data ) ), } def _GoToDefinition( self, request_data ): try: definition = self._GetResponse( '/find_definition', request_data ) return responses.BuildGoToResponse( definition[ 'file_path' ], definition[ 'line' ], definition[ 'column' ] + 1 ) except Exception as e: _logger.exception( e ) raise RuntimeError( 'Can\'t jump to definition.' ) def _GetDoc( self, request_data ): try: definition = self._GetResponse( '/find_definition', request_data ) docs = [ definition[ 'context' ], definition[ 'docs' ] ] return responses.BuildDetailedInfoResponse( '\n---\n'.join( docs ) ) except Exception as e: _logger.exception( e ) raise RuntimeError( 'Can\'t lookup docs.' ) def Shutdown( self ): self._StopServer() def _CreateHmacSecret( self ): return base64.b64encode( os.urandom( HMAC_SECRET_LENGTH ) ) def DebugInfo( self, request_data ): with self._server_state_lock: if self._ServerIsRunning(): return ( 'Rust completer debug information:\n' ' Racerd running at: {0}\n' ' Racerd process ID: {1}\n' ' Racerd executable: {2}\n' ' Racerd logfiles:\n' ' {3}\n' ' {4}\n' ' Rust sources: {5}'.format( self._racerd_host, self._racerd_phandle.pid, self._racerd_binary, self._server_stdout, self._server_stderr, self._rust_source_path ) ) if self._server_stdout and self._server_stderr: return ( 'Rust completer debug information:\n' ' Racerd no longer running\n' ' Racerd executable: {0}\n' ' Racerd logfiles:\n' ' {1}\n' ' {2}\n' ' Rust sources: {3}'.format( self._racerd_binary, self._server_stdout, self._server_stderr, self._rust_source_path ) ) return ( 'Rust completer debug information:\n' ' Racerd is not running\n' ' Racerd executable: {0}\n' ' Rust sources: {1}'.format( self._racerd_binary, self._rust_source_path ) ) ycmd-0+20161219+git486b809.orig/ycmd/completers/rust/__init__.py0000644000175000017500000000000013026170313022364 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/c/0000755000175000017500000000000013026170313017512 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/c/hook.py0000644000175000017500000000217513026170313021031 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import ycm_core from ycmd.completers.cpp.clang_completer import ClangCompleter def GetCompleter( user_options ): if ycm_core.HasClangSupport(): return ClangCompleter( user_options ) else: return None ycmd-0+20161219+git486b809.orig/ycmd/completers/all/0000755000175000017500000000000013026170313020040 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/all/__init__.py0000644000175000017500000000000013026170313022137 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/all/identifier_completer.py0000644000175000017500000002006513026170313024611 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os import logging import ycm_core from collections import defaultdict from ycmd.completers.general_completer import GeneralCompleter from ycmd import identifier_utils from ycmd.utils import ToCppStringCompatible, SplitLines from ycmd import responses SYNTAX_FILENAME = 'YCM_PLACEHOLDER_FOR_SYNTAX' class IdentifierCompleter( GeneralCompleter ): def __init__( self, user_options ): super( IdentifierCompleter, self ).__init__( user_options ) self._completer = ycm_core.IdentifierCompleter() self._tags_file_last_mtime = defaultdict( int ) self._logger = logging.getLogger( __name__ ) self._max_candidates = user_options[ 'max_num_identifier_candidates' ] def ShouldUseNow( self, request_data ): return self.QueryLengthAboveMinThreshold( request_data ) def ComputeCandidates( self, request_data ): if not self.ShouldUseNow( request_data ): return [] completions = self._completer.CandidatesForQueryAndType( ToCppStringCompatible( _SanitizeQuery( request_data[ 'query' ] ) ), ToCppStringCompatible( request_data[ 'first_filetype' ] ) ) completions = completions[ : self._max_candidates ] completions = _RemoveSmallCandidates( completions, self.user_options[ 'min_num_identifier_candidate_chars' ] ) def ConvertCompletionData( x ): return responses.BuildCompletionData( insertion_text = x, extra_menu_info='[ID]' ) return [ ConvertCompletionData( x ) for x in completions ] def _AddIdentifier( self, identifier, request_data ): filetype = request_data[ 'first_filetype' ] filepath = request_data[ 'filepath' ] if not filetype or not filepath or not identifier: return vector = ycm_core.StringVector() vector.append( ToCppStringCompatible( identifier ) ) self._logger.info( 'Adding ONE buffer identifier for file: %s', filepath ) self._completer.AddIdentifiersToDatabase( vector, ToCppStringCompatible( filetype ), ToCppStringCompatible( filepath ) ) def _AddPreviousIdentifier( self, request_data ): self._AddIdentifier( _PreviousIdentifier( self.user_options[ 'min_num_of_chars_for_completion' ], request_data ), request_data ) def _AddIdentifierUnderCursor( self, request_data ): self._AddIdentifier( _GetCursorIdentifier( request_data ), request_data ) def _AddBufferIdentifiers( self, request_data ): filetype = request_data[ 'first_filetype' ] filepath = request_data[ 'filepath' ] if not filetype or not filepath: return collect_from_comments_and_strings = bool( self.user_options[ 'collect_identifiers_from_comments_and_strings' ] ) text = request_data[ 'file_data' ][ filepath ][ 'contents' ] self._logger.info( 'Adding buffer identifiers for file: %s', filepath ) self._completer.ClearForFileAndAddIdentifiersToDatabase( _IdentifiersFromBuffer( text, filetype, collect_from_comments_and_strings ), ToCppStringCompatible( filetype ), ToCppStringCompatible( filepath ) ) def _FilterUnchangedTagFiles( self, tag_files ): for tag_file in tag_files: try: current_mtime = os.path.getmtime( tag_file ) except: continue last_mtime = self._tags_file_last_mtime[ tag_file ] # We don't want to repeatedly process the same file over and over; we only # process if it's changed since the last time we looked at it if current_mtime <= last_mtime: continue self._tags_file_last_mtime[ tag_file ] = current_mtime yield tag_file def _AddIdentifiersFromTagFiles( self, tag_files ): absolute_paths_to_tag_files = ycm_core.StringVector() for tag_file in self._FilterUnchangedTagFiles( tag_files ): absolute_paths_to_tag_files.append( ToCppStringCompatible( tag_file ) ) if not absolute_paths_to_tag_files: return self._completer.AddIdentifiersToDatabaseFromTagFiles( absolute_paths_to_tag_files ) def _AddIdentifiersFromSyntax( self, keyword_list, filetype ): keyword_vector = ycm_core.StringVector() for keyword in keyword_list: keyword_vector.append( ToCppStringCompatible( keyword ) ) filepath = SYNTAX_FILENAME + filetype self._completer.AddIdentifiersToDatabase( keyword_vector, ToCppStringCompatible( filetype ), ToCppStringCompatible( filepath ) ) def OnFileReadyToParse( self, request_data ): self._AddBufferIdentifiers( request_data ) if 'tag_files' in request_data: self._AddIdentifiersFromTagFiles( request_data[ 'tag_files' ] ) if 'syntax_keywords' in request_data: self._AddIdentifiersFromSyntax( request_data[ 'syntax_keywords' ], request_data[ 'first_filetype' ] ) def OnInsertLeave( self, request_data ): self._AddIdentifierUnderCursor( request_data ) def OnCurrentIdentifierFinished( self, request_data ): self._AddPreviousIdentifier( request_data ) # This looks for the previous identifier and returns it; this might mean looking # at last identifier on the previous line if a new line has just been created. def _PreviousIdentifier( min_num_candidate_size_chars, request_data ): def PreviousIdentifierOnLine( line, column, filetype ): nearest_ident = '' for match in identifier_utils.IdentifierRegexForFiletype( filetype ).finditer( line ): if match.end() <= column: nearest_ident = match.group() return nearest_ident line_num = request_data[ 'line_num' ] - 1 column_num = request_data[ 'column_codepoint' ] - 1 filepath = request_data[ 'filepath' ] contents_per_line = ( SplitLines( request_data[ 'file_data' ][ filepath ][ 'contents' ] ) ) filetype = request_data[ 'first_filetype' ] ident = PreviousIdentifierOnLine( contents_per_line[ line_num ], column_num, filetype ) if ident: if len( ident ) < min_num_candidate_size_chars: return '' return ident line_num = line_num - 1 if line_num < 0: return '' prev_line = contents_per_line[ line_num ] ident = PreviousIdentifierOnLine( prev_line, len( prev_line ), filetype ) if len( ident ) < min_num_candidate_size_chars: return '' return ident def _RemoveSmallCandidates( candidates, min_num_candidate_size_chars ): if min_num_candidate_size_chars == 0: return candidates return [ x for x in candidates if len( x ) >= min_num_candidate_size_chars ] def _GetCursorIdentifier( request_data ): return identifier_utils.IdentifierAtIndex( request_data[ 'line_value' ], request_data[ 'column_codepoint' ] - 1, request_data[ 'first_filetype' ] ) def _IdentifiersFromBuffer( text, filetype, collect_from_comments_and_strings ): if not collect_from_comments_and_strings: text = identifier_utils.RemoveIdentifierFreeText( text ) idents = identifier_utils.ExtractIdentifiersFromText( text, filetype ) vector = ycm_core.StringVector() for ident in idents: vector.append( ToCppStringCompatible( ident ) ) return vector def _SanitizeQuery( query ): return query.strip() ycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/0000755000175000017500000000000013026170313020052 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/hook.py0000644000175000017500000000217513026170313021371 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import ycm_core from ycmd.completers.cpp.clang_completer import ClangCompleter def GetCompleter( user_options ): if ycm_core.HasClangSupport(): return ClangCompleter( user_options ) else: return None ycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/clang_helpers.py0000644000175000017500000000204713026170313023235 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa # Provided for backwards compatibility with old ycm_extra_conf files. def PrepareClangFlags( flags, filename ): return flags ycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/ephemeral_values_set.py0000644000175000017500000000445513026170313024630 0ustar onuronur# Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import threading ALREADY_PARSING_MESSAGE = 'File already being parsed.' # Holds a set of values in a python set. Trying to get an exclusive hold on a # provided value results in a context manager that manages the lifetime of the # value. # For the context manager, trying to enter it if the value is already held by a # different caller results in a RuntimeError. Otherwise an exclusive hold is # provided until the context manager is exited. # # Example usage: # paths = EphemeralValuesSet() # ... # with path as paths.GetExclusive('/foo'): # ... class EphemeralValuesSet( object ): def __init__( self ): self._values = set() self._values_lock = threading.Lock() def GetExclusive( self, value ): return EphemeralValue( value, self._values, self._values_lock ) # Implements the Python context manager API. class EphemeralValue( object ): def __init__( self, value, parent_set, parent_lock ): self._value = value self._parent_set = parent_set self._parent_lock = parent_lock def __enter__( self ): with self._parent_lock: if self._value in self._parent_set: # This also prevents execution of __exit__ raise RuntimeError( ALREADY_PARSING_MESSAGE ) self._parent_set.add( self._value ) return self._value def __exit__( self, *unused_args): with self._parent_lock: self._parent_set.remove( self._value ) return False ycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/__init__.py0000644000175000017500000000000013026170313022151 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/clang_completer.py0000644000175000017500000004631213026170313023570 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import iteritems from collections import defaultdict import ycm_core import re import os.path import textwrap from ycmd import responses from ycmd import extra_conf_store from ycmd.utils import ToCppStringCompatible, ToUnicode from ycmd.completers.completer import Completer from ycmd.completers.completer_utils import GetIncludeStatementValue from ycmd.completers.cpp.flags import Flags, PrepareFlagsForClang from ycmd.completers.cpp.ephemeral_values_set import EphemeralValuesSet from ycmd.responses import NoExtraConfDetected, UnknownExtraConf import xml.etree.ElementTree CLANG_FILETYPES = set( [ 'c', 'cpp', 'objc', 'objcpp' ] ) PARSING_FILE_MESSAGE = 'Still parsing file, no completions yet.' NO_COMPILE_FLAGS_MESSAGE = 'Still no compile flags, no completions yet.' INVALID_FILE_MESSAGE = 'File is invalid.' NO_COMPLETIONS_MESSAGE = 'No completions found; errors in the file?' NO_DIAGNOSTIC_MESSAGE = 'No diagnostic for current line!' PRAGMA_DIAG_TEXT_TO_IGNORE = '#pragma once in main file' TOO_MANY_ERRORS_DIAG_TEXT_TO_IGNORE = 'too many errors emitted, stopping now' NO_DOCUMENTATION_MESSAGE = 'No documentation available for current context' class ClangCompleter( Completer ): def __init__( self, user_options ): super( ClangCompleter, self ).__init__( user_options ) self._max_diagnostics_to_display = user_options[ 'max_diagnostics_to_display' ] self._completer = ycm_core.ClangCompleter() self._flags = Flags() self._diagnostic_store = None self._files_being_compiled = EphemeralValuesSet() def SupportedFiletypes( self ): return CLANG_FILETYPES def GetUnsavedFilesVector( self, request_data ): files = ycm_core.UnsavedFileVector() for filename, file_data in iteritems( request_data[ 'file_data' ] ): if not ClangAvailableForFiletypes( file_data[ 'filetypes' ] ): continue contents = file_data[ 'contents' ] if not contents or not filename: continue unsaved_file = ycm_core.UnsavedFile() utf8_contents = ToCppStringCompatible( contents ) unsaved_file.contents_ = utf8_contents unsaved_file.length_ = len( utf8_contents ) unsaved_file.filename_ = ToCppStringCompatible( filename ) files.append( unsaved_file ) return files def ComputeCandidatesInner( self, request_data ): filename = request_data[ 'filepath' ] if not filename: return if self._completer.UpdatingTranslationUnit( ToCppStringCompatible( filename ) ): raise RuntimeError( PARSING_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise RuntimeError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'start_column' ] with self._files_being_compiled.GetExclusive( filename ): results = self._completer.CandidatesForLocationInFile( ToCppStringCompatible( filename ), line, column, files, flags ) if not results: raise RuntimeError( NO_COMPLETIONS_MESSAGE ) return [ ConvertCompletionData( x ) for x in results ] def GetSubcommandsMap( self ): return { 'GoToDefinition' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDeclaration' : ( lambda self, request_data, args: self._GoToDeclaration( request_data ) ), 'GoTo' : ( lambda self, request_data, args: self._GoTo( request_data ) ), 'GoToImprecise' : ( lambda self, request_data, args: self._GoToImprecise( request_data ) ), 'GoToInclude' : ( lambda self, request_data, args: self._GoToInclude( request_data ) ), 'ClearCompilationFlagCache': ( lambda self, request_data, args: self._ClearCompilationFlagCache() ), 'GetType' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, func = 'GetTypeAtLocation' ) ), 'GetTypeImprecise' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, func = 'GetTypeAtLocation', reparse = False ) ), 'GetParent' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, func = 'GetEnclosingFunctionAtLocation' ) ), 'FixIt' : ( lambda self, request_data, args: self._FixIt( request_data ) ), 'GetDoc' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, reparse = True, func = 'GetDocsForLocationInFile', response_builder = _BuildGetDocResponse ) ), 'GetDocImprecise' : ( lambda self, request_data, args: self._GetSemanticInfo( request_data, reparse = False, func = 'GetDocsForLocationInFile', response_builder = _BuildGetDocResponse ) ), } def _LocationForGoTo( self, goto_function, request_data, reparse = True ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] return getattr( self._completer, goto_function )( ToCppStringCompatible( filename ), line, column, files, flags, reparse ) def _GoToDefinition( self, request_data ): location = self._LocationForGoTo( 'GetDefinitionLocation', request_data ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to definition.' ) return _ResponseForLocation( location ) def _GoToDeclaration( self, request_data ): location = self._LocationForGoTo( 'GetDeclarationLocation', request_data ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to declaration.' ) return _ResponseForLocation( location ) def _GoTo( self, request_data ): include_response = self._ResponseForInclude( request_data ) if include_response: return include_response location = self._LocationForGoTo( 'GetDefinitionLocation', request_data ) if not location or not location.IsValid(): location = self._LocationForGoTo( 'GetDeclarationLocation', request_data ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to definition or declaration.' ) return _ResponseForLocation( location ) def _GoToImprecise( self, request_data ): include_response = self._ResponseForInclude( request_data ) if include_response: return include_response location = self._LocationForGoTo( 'GetDefinitionLocation', request_data, reparse = False ) if not location or not location.IsValid(): location = self._LocationForGoTo( 'GetDeclarationLocation', request_data, reparse = False ) if not location or not location.IsValid(): raise RuntimeError( 'Can\'t jump to definition or declaration.' ) return _ResponseForLocation( location ) def _ResponseForInclude( self, request_data ): """Returns response for include file location if cursor is on the include statement, None otherwise. Throws RuntimeError if cursor is on include statement and corresponding include file not found.""" current_line = request_data[ 'line_value' ] include_file_name, quoted_include = GetIncludeStatementValue( current_line ) if not include_file_name: return None current_file_path = request_data[ 'filepath' ] client_data = request_data.get( 'extra_conf_data', None ) quoted_include_paths, include_paths = ( self._flags.UserIncludePaths( current_file_path, client_data ) ) if quoted_include: include_file_path = _GetAbsolutePath( include_file_name, quoted_include_paths ) if include_file_path: return responses.BuildGoToResponse( include_file_path, line_num = 1, column_num = 1 ) include_file_path = _GetAbsolutePath( include_file_name, include_paths ) if include_file_path: return responses.BuildGoToResponse( include_file_path, line_num = 1, column_num = 1 ) raise RuntimeError( 'Include file not found.' ) def _GoToInclude( self, request_data ): include_response = self._ResponseForInclude( request_data ) if not include_response: raise RuntimeError( 'Not an include/import line.' ) return include_response def _GetSemanticInfo( self, request_data, func, response_builder = responses.BuildDisplayMessageResponse, reparse = True ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] message = getattr( self._completer, func )( ToCppStringCompatible( filename ), line, column, files, flags, reparse) if not message: message = "No semantic information available" return response_builder( message ) def _ClearCompilationFlagCache( self ): self._flags.Clear() def _FixIt( self, request_data ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) files = self.GetUnsavedFilesVector( request_data ) line = request_data[ 'line_num' ] column = request_data[ 'column_num' ] fixits = getattr( self._completer, "GetFixItsForLocationInFile" )( ToCppStringCompatible( filename ), line, column, files, flags, True ) # don't raise an error if not fixits: - leave that to the client to respond # in a nice way return responses.BuildFixItResponse( fixits ) def OnFileReadyToParse( self, request_data ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) flags = self._FlagsForRequest( request_data ) if not flags: raise ValueError( NO_COMPILE_FLAGS_MESSAGE ) with self._files_being_compiled.GetExclusive( filename ): diagnostics = self._completer.UpdateTranslationUnit( ToCppStringCompatible( filename ), self.GetUnsavedFilesVector( request_data ), flags ) diagnostics = _FilterDiagnostics( diagnostics ) self._diagnostic_store = DiagnosticsToDiagStructure( diagnostics ) return [ responses.BuildDiagnosticData( x ) for x in diagnostics[ : self._max_diagnostics_to_display ] ] def OnBufferUnload( self, request_data ): self._completer.DeleteCachesForFile( ToCppStringCompatible( request_data[ 'filepath' ] ) ) def GetDetailedDiagnostic( self, request_data ): current_line = request_data[ 'line_num' ] current_column = request_data[ 'column_num' ] current_file = request_data[ 'filepath' ] if not self._diagnostic_store: raise ValueError( NO_DIAGNOSTIC_MESSAGE ) diagnostics = self._diagnostic_store[ current_file ][ current_line ] if not diagnostics: raise ValueError( NO_DIAGNOSTIC_MESSAGE ) closest_diagnostic = None distance_to_closest_diagnostic = 999 # FIXME: all of these calculations are currently working with byte # offsets, which are technically incorrect. We should be working with # codepoint offsets, as we want the nearest character-wise diagnostic for diagnostic in diagnostics: distance = abs( current_column - diagnostic.location_.column_number_ ) if distance < distance_to_closest_diagnostic: distance_to_closest_diagnostic = distance closest_diagnostic = diagnostic return responses.BuildDisplayMessageResponse( closest_diagnostic.long_formatted_text_ ) def DebugInfo( self, request_data ): filename = request_data[ 'filepath' ] try: extra_conf = extra_conf_store.ModuleFileForSourceFile( filename ) flags = self._FlagsForRequest( request_data ) or [] except NoExtraConfDetected: return ( 'C-family completer debug information:\n' ' No configuration file found' ) except UnknownExtraConf as error: return ( 'C-family completer debug information:\n' ' Configuration file found but not loaded\n' ' Configuration path: {0}'.format( error.extra_conf_file ) ) if not extra_conf: return ( 'C-family completer debug information:\n' ' No configuration file found' ) return ( 'C-family completer debug information:\n' ' Configuration file found and loaded\n' ' Configuration path: {0}\n' ' Flags: {1}'.format( extra_conf, list( flags ) ) ) def _FlagsForRequest( self, request_data ): filename = request_data[ 'filepath' ] if 'compilation_flags' in request_data: return PrepareFlagsForClang( request_data[ 'compilation_flags' ], filename ) client_data = request_data.get( 'extra_conf_data', None ) return self._flags.FlagsForFile( filename, client_data = client_data ) def ConvertCompletionData( completion_data ): return responses.BuildCompletionData( insertion_text = completion_data.TextToInsertInBuffer(), menu_text = completion_data.MainCompletionText(), extra_menu_info = completion_data.ExtraMenuInfo(), kind = completion_data.kind_.name, detailed_info = completion_data.DetailedInfoForPreviewWindow(), extra_data = ( { 'doc_string': completion_data.DocString() } if completion_data.DocString() else None ) ) def DiagnosticsToDiagStructure( diagnostics ): structure = defaultdict( lambda : defaultdict( list ) ) for diagnostic in diagnostics: structure[ diagnostic.location_.filename_ ][ diagnostic.location_.line_number_ ].append( diagnostic ) return structure def ClangAvailableForFiletypes( filetypes ): return any( [ filetype in CLANG_FILETYPES for filetype in filetypes ] ) def InCFamilyFile( filetypes ): return ClangAvailableForFiletypes( filetypes ) def _FilterDiagnostics( diagnostics ): # Clang has an annoying warning that shows up when we try to compile header # files if the header has "#pragma once" inside it. The error is not # legitimate because it shows up because libclang thinks we are compiling a # source file instead of a header file. # # See our issue #216 and upstream bug: # http://llvm.org/bugs/show_bug.cgi?id=16686 # # The second thing we want to filter out are those incredibly annoying "too # many errors emitted" diagnostics that are utterly useless. return [ x for x in diagnostics if x.text_ != PRAGMA_DIAG_TEXT_TO_IGNORE and x.text_ != TOO_MANY_ERRORS_DIAG_TEXT_TO_IGNORE ] def _ResponseForLocation( location ): return responses.BuildGoToResponse( location.filename_, location.line_number_, location.column_number_ ) # Strips the following leading strings from the raw comment: # - /// # - ///< # - //< # - //! # - /** # - /*! # - /*< # - /* # - * # - */ # - etc. # That is: # - 2 or 3 '/' followed by '<' or '!' # - '/' then 1 or 2 '*' followed by optional '<' or '!' # - '*' followed by optional '/' STRIP_LEADING_COMMENT = re.compile( '^[ \t]*(/{2,3}[*/ # - STRIP_TRAILING_COMMENT = re.compile( '[ \t]*\*/[ \t]*$|[ \t]*$' ) def _FormatRawComment( comment ): """Strips leading indentation and comment markers from the comment string""" return textwrap.dedent( '\n'.join( [ re.sub( STRIP_TRAILING_COMMENT, '', re.sub( STRIP_LEADING_COMMENT, '', line ) ) for line in ToUnicode( comment ).splitlines() ] ) ) def _BuildGetDocResponse( doc_data ): """Builds a "DetailedInfoResponse" for a GetDoc request. doc_data is a DocumentationData object returned from the ClangCompleter""" # Parse the XML, as this is the only way to get the declaration text out of # libclang. It seems quite wasteful, but while the contents of the XML # provide fully parsed doxygen documentation tree, we actually don't want to # ever lose any information from the comment, so we just want display # the stripped comment. Arguably we could skip all of this XML generation and # parsing, but having the raw declaration text is likely one of the most # useful pieces of documentation available to the developer. Perhaps in # future, we can use this XML for more interesting things. try: root = xml.etree.ElementTree.fromstring( doc_data.comment_xml ) except: raise ValueError( NO_DOCUMENTATION_MESSAGE ) # Note: declaration is False-y if it has no child elements, hence the below # (wordy) if not declaration is None declaration = root.find( "Declaration" ) return responses.BuildDetailedInfoResponse( '{0}\n{1}\nType: {2}\nName: {3}\n---\n{4}'.format( ToUnicode( declaration.text ) if declaration is not None else "", ToUnicode( doc_data.brief_comment ), ToUnicode( doc_data.canonical_type ), ToUnicode( doc_data.display_name ), ToUnicode( _FormatRawComment( doc_data.raw_comment ) ) ) ) def _GetAbsolutePath( include_file_name, include_paths ): for path in include_paths: include_file_path = os.path.join( path, include_file_name ) if os.path.isfile( include_file_path ): return include_file_path return None ycmd-0+20161219+git486b809.orig/ycmd/completers/cpp/flags.py0000644000175000017500000003706013026170313021526 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import ycm_core import os import inspect import re from future.utils import PY2, native from ycmd import extra_conf_store from ycmd.utils import ( ToCppStringCompatible, OnMac, OnWindows, ToUnicode, ToBytes ) from ycmd.responses import NoExtraConfDetected INCLUDE_FLAGS = [ '-isystem', '-I', '-iquote', '-isysroot', '--sysroot', '-gcc-toolchain', '-include', '-include-pch', '-iframework', '-F', '-imacros' ] # We need to remove --fcolor-diagnostics because it will cause shell escape # sequences to show up in editors, which is bad. See Valloric/YouCompleteMe#1421 STATE_FLAGS_TO_SKIP = set( [ '-c', '-MP', '-MD', '-MMD', '--fcolor-diagnostics' ] ) # The -M* flags spec: # https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Preprocessor-Options.html FILE_FLAGS_TO_SKIP = set( [ '-MF', '-MT', '-MQ', '-o', '--serialize-diagnostics' ] ) # Use a regex to correctly detect c++/c language for both versioned and # non-versioned compiler executable names suffixes # (e.g., c++, g++, clang++, g++-4.9, clang++-3.7, c++-10.2 etc). # See Valloric/ycmd#266 CPP_COMPILER_REGEX = re.compile( r'\+\+(-\d+(\.\d+){0,2})?$' ) class Flags( object ): """Keeps track of the flags necessary to compile a file. The flags are loaded from user-created python files (hereafter referred to as 'modules') that contain a method FlagsForFile( filename ).""" def __init__( self ): # It's caches all the way down... self.flags_for_file = {} self.extra_clang_flags = _ExtraClangFlags() self.no_extra_conf_file_warning_posted = False def FlagsForFile( self, filename, add_extra_clang_flags = True, client_data = None ): try: return self.flags_for_file[ filename ] except KeyError: module = extra_conf_store.ModuleForSourceFile( filename ) if not module: if not self.no_extra_conf_file_warning_posted: self.no_extra_conf_file_warning_posted = True raise NoExtraConfDetected return None results = _CallExtraConfFlagsForFile( module, filename, client_data ) if not results or not results.get( 'flags_ready', True ): return None flags = _ExtractFlagsList( results ) if not flags: return None if add_extra_clang_flags: flags += self.extra_clang_flags sanitized_flags = PrepareFlagsForClang( flags, filename, add_extra_clang_flags ) if results.get( 'do_cache', True ): self.flags_for_file[ filename ] = sanitized_flags return sanitized_flags def UserIncludePaths( self, filename, client_data ): flags = [ ToUnicode( x ) for x in self.FlagsForFile( filename, client_data = client_data ) ] quoted_include_paths = [ os.path.dirname( filename ) ] include_paths = [] if flags: quote_flag = '-iquote' path_flags = [ '-isystem', '-I' ] try: it = iter( flags ) for flag in it: flag_len = len( flag ) if flag.startswith( quote_flag ): quote_flag_len = len( quote_flag ) # Add next flag to the include paths if current flag equals to # '-iquote', or add remaining string otherwise. quoted_include_paths.append( next( it ) if flag_len == quote_flag_len else flag[ quote_flag_len: ] ) else: for path_flag in path_flags: if flag.startswith( path_flag ): path_flag_len = len( path_flag ) include_paths.append( next( it ) if flag_len == path_flag_len else flag[ path_flag_len: ] ) break except StopIteration: pass return ( [ x for x in quoted_include_paths if x ], [ x for x in include_paths if x ] ) def Clear( self ): self.flags_for_file.clear() def _ExtractFlagsList( flags_for_file_output ): return [ ToUnicode( x ) for x in flags_for_file_output[ 'flags' ] ] def _CallExtraConfFlagsForFile( module, filename, client_data ): # We want to ensure we pass a native py2 `str` on py2 and a native py3 `str` # (unicode) object on py3. That's the API we provide. # In a vacuum, always passing a unicode object (`unicode` on py2 and `str` on # py3) would be better, but we can't do that because that would break all the # ycm_extra_conf files already out there that expect a py2 `str` object on # py2, and WE DO NOT BREAK BACKWARDS COMPATIBILITY. # Hindsight is 20/20. if PY2: filename = native( ToBytes( filename ) ) else: filename = native( ToUnicode( filename ) ) # For the sake of backwards compatibility, we need to first check whether the # FlagsForFile function in the extra conf module even allows keyword args. if inspect.getargspec( module.FlagsForFile ).keywords: return module.FlagsForFile( filename, client_data = client_data ) else: return module.FlagsForFile( filename ) def PrepareFlagsForClang( flags, filename, add_extra_clang_flags = True ): flags = _AddLanguageFlagWhenAppropriate( flags ) flags = _RemoveXclangFlags( flags ) flags = _RemoveUnusedFlags( flags, filename ) if add_extra_clang_flags: flags = _EnableTypoCorrection( flags ) flags = _SanitizeFlags( flags ) return flags def _RemoveXclangFlags( flags ): """Drops -Xclang flags. These are typically used to pass in options to clang cc1 which are not used in the front-end, so they are not needed for code completion.""" sanitized_flags = [] saw_xclang = False for i, flag in enumerate( flags ): if flag == '-Xclang': saw_xclang = True continue elif saw_xclang: saw_xclang = False continue sanitized_flags.append( flag ) return sanitized_flags def _SanitizeFlags( flags ): """Drops unsafe flags. Currently these are only -arch flags; they tend to crash libclang.""" sanitized_flags = [] saw_arch = False for i, flag in enumerate( flags ): if flag == '-arch': saw_arch = True continue elif flag.startswith( '-arch' ): continue elif saw_arch: saw_arch = False continue sanitized_flags.append( flag ) vector = ycm_core.StringVector() for flag in sanitized_flags: vector.append( ToCppStringCompatible( flag ) ) return vector def _RemoveFlagsPrecedingCompiler( flags ): """Assuming that the flag just before the first flag (which starts with a dash) is the compiler path, removes all flags preceding it.""" for index, flag in enumerate( flags ): if flag.startswith( '-' ): return ( flags[ index - 1: ] if index > 1 else flags ) return flags[ :-1 ] def _AddLanguageFlagWhenAppropriate( flags ): """When flags come from the compile_commands.json file, the flag preceding the first flag starting with a dash is usually the path to the compiler that should be invoked. Since LibClang does not deduce the language from the compiler name, we explicitely set the language to C++ if the compiler is a C++ one (g++, clang++, etc.). Otherwise, we let LibClang guess the language from the file extension. This handles the case where the .h extension is used for C++ headers.""" flags = _RemoveFlagsPrecedingCompiler( flags ) # First flag is now the compiler path or a flag starting with a dash. first_flag = flags[ 0 ] if ( not first_flag.startswith( '-' ) and CPP_COMPILER_REGEX.search( first_flag ) ): return [ first_flag, '-x', 'c++' ] + flags[ 1: ] return flags def _RemoveUnusedFlags( flags, filename ): """Given an iterable object that produces strings (flags for Clang), removes the '-c' and '-o' options that Clang does not like to see when it's producing completions for a file. Same for '-MD' etc. We also try to remove any stray filenames in the flags that aren't include dirs.""" new_flags = [] # When flags come from the compile_commands.json file, the first flag is # usually the path to the compiler that should be invoked. Directly move it to # the new_flags list so it doesn't get stripped of in the loop below. if not flags[ 0 ].startswith( '-' ): new_flags = flags[ :1 ] flags = flags[ 1: ] skip_next = False previous_flag_is_include = False previous_flag_starts_with_dash = False current_flag_starts_with_dash = False for flag in flags: previous_flag_starts_with_dash = current_flag_starts_with_dash current_flag_starts_with_dash = flag.startswith( '-' ) if skip_next: skip_next = False continue if flag in STATE_FLAGS_TO_SKIP: continue if flag in FILE_FLAGS_TO_SKIP: skip_next = True continue if flag == filename or os.path.realpath( flag ) == filename: continue # We want to make sure that we don't have any stray filenames in our flags; # filenames that are part of include flags are ok, but others are not. This # solves the case where we ask the compilation database for flags for # "foo.cpp" when we are compiling "foo.h" because the comp db doesn't have # flags for headers. The returned flags include "foo.cpp" and we need to # remove that. if ( not current_flag_starts_with_dash and ( not previous_flag_starts_with_dash or ( not previous_flag_is_include and '/' in flag ) ) ): continue new_flags.append( flag ) previous_flag_is_include = flag in INCLUDE_FLAGS return new_flags # There are 2 ways to get a development enviornment (as standard) on OS X: # - install XCode.app, or # - install the command-line tools (xcode-select --install) # # Most users have xcode installed, but in order to be as compatible as # possible we consider both possible installation locations MAC_CLANG_TOOLCHAIN_DIRS = [ '/Applications/Xcode.app/Contents/Developer/Toolchains/' 'XcodeDefault.xctoolchain', '/Library/Developer/CommandLineTools' ] # Returns a list containing the supplied path as a suffix of each of the known # Mac toolchains def _PathsForAllMacToolchains( path ): return [ os.path.join( x, path ) for x in MAC_CLANG_TOOLCHAIN_DIRS ] # Ultimately, this method exists only for testability def _GetMacClangVersionList( candidates_dir ): try: return os.listdir( candidates_dir ) except OSError: # Path might not exist, so just ignore return [] # Ultimately, this method exists only for testability def _MacClangIncludeDirExists( candidate_include ): return os.path.exists( candidate_include ) # Add in any clang headers found in the installed toolchains. These are # required for the same reasons as described below, but unfortuantely, these # are in versioned directories and there is no easy way to find the "correct" # version. We simply pick the highest version in the first toolchain that we # find, as this is the most likely to be correct. def _LatestMacClangIncludes(): for path in MAC_CLANG_TOOLCHAIN_DIRS: # we use the first toolchain which actually contains any versions, rather # than trying all of the toolchains and picking the highest. We # favour Xcode over CommandLineTools as using Xcode is more common. # It might be possible to extrace this information from xcode-select, though # xcode-select -p does not point at the toolchain directly candidates_dir = os.path.join( path, 'usr', 'lib', 'clang' ) versions = _GetMacClangVersionList( candidates_dir ) for version in reversed( sorted( versions ) ): candidate_include = os.path.join( candidates_dir, version, 'include' ) if _MacClangIncludeDirExists( candidate_include ): return [ candidate_include ] return [] MAC_INCLUDE_PATHS = [] if OnMac(): # These are the standard header search paths that clang will use on Mac BUT # libclang won't, for unknown reasons. We add these paths when the user is on # a Mac because if we don't, libclang would fail to find etc. This # should be fixed upstream in libclang, but until it does, we need to help # users out. # See the following for details: # - Valloric/YouCompleteMe#303 # - Valloric/YouCompleteMe#2268 MAC_INCLUDE_PATHS = ( _PathsForAllMacToolchains( 'usr/include/c++/v1' ) + [ '/usr/local/include' ] + _PathsForAllMacToolchains( 'usr/include' ) + [ '/usr/include', '/System/Library/Frameworks', '/Library/Frameworks' ] + _LatestMacClangIncludes() + # We include the MacOS platform SDK because some meaningful parts of the # standard library are located there. If users are compiling for (say) # iPhone.platform, etc. they should appear earlier in the include path. [ '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/' 'Developer/SDKs/MacOSX.sdk/usr/include' ] ) def _ExtraClangFlags(): flags = _SpecialClangIncludes() if OnMac(): for path in MAC_INCLUDE_PATHS: flags.extend( [ '-isystem', path ] ) # On Windows, parsing of templates is delayed until instantiation time. # This makes GetType and GetParent commands fail to return the expected # result when the cursor is in a template. # Using the -fno-delayed-template-parsing flag disables this behavior. # See # http://clang.llvm.org/extra/PassByValueTransform.html#note-about-delayed-template-parsing # noqa # for an explanation of the flag and # https://code.google.com/p/include-what-you-use/source/detail?r=566 # for a similar issue. if OnWindows(): flags.append( '-fno-delayed-template-parsing' ) return flags def _EnableTypoCorrection( flags ): """Adds the -fspell-checking flag if the -fno-spell-checking flag is not present""" # "Typo correction" (aka spell checking) in clang allows it to produce # hints (in the form of fix-its) in the case of certain diagnostics. A common # example is "no type named 'strng' in namespace 'std'; Did you mean # 'string'? (FixIt)". This is enabled by default in the clang driver (i.e. the # 'clang' binary), but is not when using libclang (as we do). It's a useful # enough feature that we just always turn it on unless the user explicitly # turned it off in their flags (with -fno-spell-checking). if '-fno-spell-checking' in flags: return flags flags.append( '-fspell-checking' ) return flags def _SpecialClangIncludes(): libclang_dir = os.path.dirname( ycm_core.__file__ ) path_to_includes = os.path.join( libclang_dir, 'clang_includes' ) return [ '-resource-dir=' + path_to_includes ] ycmd-0+20161219+git486b809.orig/ycmd/completers/typescript/0000755000175000017500000000000013026170313021476 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/typescript/hook.py0000644000175000017500000000225013026170313023007 0ustar onuronur# Copyright (C) 2015 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.typescript.typescript_completer import ( ShouldEnableTypescriptCompleter, TypeScriptCompleter ) def GetCompleter( user_options ): if not ShouldEnableTypescriptCompleter(): return None return TypeScriptCompleter( user_options ) ycmd-0+20161219+git486b809.orig/ycmd/completers/typescript/__init__.py0000644000175000017500000000000013026170313023575 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/typescript/typescript_completer.py0000644000175000017500000005323013026170313026333 0ustar onuronur# Copyright (C) 2015 - 2016 Google Inc. # 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import json import logging import os import re import subprocess import itertools import threading from tempfile import NamedTemporaryFile from ycmd import responses from ycmd import utils from ycmd.completers.completer import Completer from ycmd.completers.completer_utils import GetFileContents BINARY_NOT_FOUND_MESSAGE = ( 'TSServer not found. ' 'TypeScript 1.5 or higher is required.' ) SERVER_NOT_RUNNING_MESSAGE = 'TSServer is not running.' MAX_DETAILED_COMPLETIONS = 100 RESPONSE_TIMEOUT_SECONDS = 10 PATH_TO_TSSERVER = utils.FindExecutable( 'tsserver' ) LOGFILE_FORMAT = 'tsserver_' _logger = logging.getLogger( __name__ ) class DeferredResponse( object ): """ A deferred that resolves to a response from TSServer. """ def __init__( self, timeout = RESPONSE_TIMEOUT_SECONDS ): self._event = threading.Event() self._message = None self._timeout = timeout def resolve( self, message ): self._message = message self._event.set() def result( self ): self._event.wait( timeout = self._timeout ) if not self._event.isSet(): raise RuntimeError( 'Response Timeout' ) message = self._message if not message[ 'success' ]: raise RuntimeError( message[ 'message' ] ) if 'body' in message: return self._message[ 'body' ] def ShouldEnableTypescriptCompleter(): if not PATH_TO_TSSERVER: _logger.error( BINARY_NOT_FOUND_MESSAGE ) return False _logger.info( 'Using TSServer located at {0}'.format( PATH_TO_TSSERVER ) ) return True class TypeScriptCompleter( Completer ): """ Completer for TypeScript. It uses TSServer which is bundled with TypeScript 1.5 See the protocol here: https://github.com/Microsoft/TypeScript/blob/2cb0dfd99dc2896958b75e44303d8a7a32e5dc33/src/server/protocol.d.ts """ def __init__( self, user_options ): super( TypeScriptCompleter, self ).__init__( user_options ) self._logfile = None self._tsserver_handle = None # Used to prevent threads from concurrently writing to # the tsserver process' stdin self._write_lock = threading.Lock() # Each request sent to tsserver must have a sequence id. # Responses contain the id sent in the corresponding request. self._sequenceid = itertools.count() # Used to prevent threads from concurrently accessing the sequence counter self._sequenceid_lock = threading.Lock() self._server_lock = threading.RLock() # Used to read response only if TSServer is running. self._tsserver_is_running = threading.Event() # Start a thread to read response from TSServer. self._thread = threading.Thread( target = self._ReaderLoop, args = () ) self._thread.daemon = True self._thread.start() self._StartServer() # Used to map sequence id's to their corresponding DeferredResponse # objects. The reader loop uses this to hand out responses. self._pending = {} # Used to prevent threads from concurrently reading and writing to # the pending response dictionary self._pending_lock = threading.Lock() _logger.info( 'Enabling typescript completion' ) def _StartServer( self ): with self._server_lock: if self._ServerIsRunning(): return self._logfile = utils.CreateLogfile( LOGFILE_FORMAT ) tsserver_log = '-file {path} -level {level}'.format( path = self._logfile, level = _LogLevel() ) # TSServer gets the configuration for the log file through the # environment variable 'TSS_LOG'. This seems to be undocumented but # looking at the source code it seems like this is the way: # https://github.com/Microsoft/TypeScript/blob/8a93b489454fdcbdf544edef05f73a913449be1d/src/server/server.ts#L136 environ = os.environ.copy() utils.SetEnviron( environ, 'TSS_LOG', tsserver_log ) _logger.info( 'TSServer log file: {0}'.format( self._logfile ) ) # We need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen( PATH_TO_TSSERVER, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = environ ) self._tsserver_is_running.set() def _ReaderLoop( self ): """ Read responses from TSServer and use them to resolve the DeferredResponse instances. """ while True: self._tsserver_is_running.wait() try: message = self._ReadMessage() except RuntimeError: _logger.exception( SERVER_NOT_RUNNING_MESSAGE ) self._tsserver_is_running.clear() continue # We ignore events for now since we don't have a use for them. msgtype = message[ 'type' ] if msgtype == 'event': eventname = message[ 'event' ] _logger.info( 'Received {0} event from tsserver'.format( eventname ) ) continue if msgtype != 'response': _logger.error( 'Unsupported message type {0}'.format( msgtype ) ) continue seq = message[ 'request_seq' ] with self._pending_lock: if seq in self._pending: self._pending[ seq ].resolve( message ) del self._pending[ seq ] def _ReadMessage( self ): """Read a response message from TSServer.""" # The headers are pretty similar to HTTP. # At the time of writing, 'Content-Length' is the only supplied header. headers = {} while True: headerline = self._tsserver_handle.stdout.readline().strip() if not headerline: break key, value = utils.ToUnicode( headerline ).split( ':', 1 ) headers[ key.strip() ] = value.strip() # The response message is a JSON object which comes back on one line. # Since this might change in the future, we use the 'Content-Length' # header. if 'Content-Length' not in headers: raise RuntimeError( "Missing 'Content-Length' header" ) contentlength = int( headers[ 'Content-Length' ] ) # TSServer adds a newline at the end of the response message and counts it # as one character (\n) towards the content length. However, newlines are # two characters on Windows (\r\n), so we need to take care of that. See # issue https://github.com/Microsoft/TypeScript/issues/3403 content = self._tsserver_handle.stdout.read( contentlength ) if utils.OnWindows() and content.endswith( b'\r' ): content += self._tsserver_handle.stdout.read( 1 ) return json.loads( utils.ToUnicode( content ) ) def _BuildRequest( self, command, arguments = None ): """Build TSServer request object.""" with self._sequenceid_lock: seq = next( self._sequenceid ) request = { 'seq': seq, 'type': 'request', 'command': command } if arguments: request[ 'arguments' ] = arguments return request def _WriteRequest( self, request ): """Write a request to TSServer stdin.""" serialized_request = utils.ToBytes( json.dumps( request ) + '\n' ) with self._write_lock: try: self._tsserver_handle.stdin.write( serialized_request ) self._tsserver_handle.stdin.flush() # IOError is an alias of OSError in Python 3. except ( AttributeError, IOError ): _logger.exception( SERVER_NOT_RUNNING_MESSAGE ) raise RuntimeError( SERVER_NOT_RUNNING_MESSAGE ) def _SendCommand( self, command, arguments = None ): """ Send a request message to TSServer but don't wait for the response. This function is to be used when we don't care about the response to the message that is sent. """ request = self._BuildRequest( command, arguments ) self._WriteRequest( request ) def _SendRequest( self, command, arguments = None ): """ Send a request message to TSServer and wait for the response. """ request = self._BuildRequest( command, arguments ) deferred = DeferredResponse() with self._pending_lock: seq = request[ 'seq' ] self._pending[ seq ] = deferred self._WriteRequest( request ) return deferred.result() def _Reload( self, request_data ): """ Syncronize TSServer's view of the file to the contents of the unsaved buffer. """ filename = request_data[ 'filepath' ] contents = request_data[ 'file_data' ][ filename ][ 'contents' ] tmpfile = NamedTemporaryFile( delete = False ) tmpfile.write( utils.ToBytes( contents ) ) tmpfile.close() self._SendRequest( 'reload', { 'file': filename, 'tmpfile': tmpfile.name } ) utils.RemoveIfExists( tmpfile.name ) def _ServerIsRunning( self ): with self._server_lock: return utils.ProcessIsRunning( self._tsserver_handle ) def ServerIsHealthy( self ): return self._ServerIsRunning() def SupportedFiletypes( self ): return [ 'typescript' ] def ComputeCandidatesInner( self, request_data ): self._Reload( request_data ) entries = self._SendRequest( 'completions', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'start_codepoint' ] } ) # A less detailed version of the completion data is returned # if there are too many entries. This improves responsiveness. if len( entries ) > MAX_DETAILED_COMPLETIONS: return [ _ConvertCompletionData(e) for e in entries ] names = [] namelength = 0 for e in entries: name = e[ 'name' ] namelength = max( namelength, len( name ) ) names.append( name ) detailed_entries = self._SendRequest( 'completionEntryDetails', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'start_codepoint' ], 'entryNames': names } ) return [ _ConvertDetailedCompletionData( e, namelength ) for e in detailed_entries ] def GetSubcommandsMap( self ): return { 'RestartServer' : ( lambda self, request_data, args: self._RestartServer( request_data ) ), 'StopServer' : ( lambda self, request_data, args: self._StopServer() ), 'GoToDefinition' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToReferences' : ( lambda self, request_data, args: self._GoToReferences( request_data ) ), 'GoToType' : ( lambda self, request_data, args: self._GoToType( request_data ) ), 'GetType' : ( lambda self, request_data, args: self._GetType( request_data ) ), 'GetDoc' : ( lambda self, request_data, args: self._GetDoc( request_data ) ), 'RefactorRename' : ( lambda self, request_data, args: self._RefactorRename( request_data, args ) ), } def OnBufferVisit( self, request_data ): filename = request_data[ 'filepath' ] self._SendCommand( 'open', { 'file': filename } ) def OnBufferUnload( self, request_data ): filename = request_data[ 'filepath' ] self._SendCommand( 'close', { 'file': filename } ) def OnFileReadyToParse( self, request_data ): self._Reload( request_data ) def _GoToDefinition( self, request_data ): self._Reload( request_data ) try: filespans = self._SendRequest( 'definition', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'column_codepoint' ] } ) span = filespans[ 0 ] return responses.BuildGoToResponseFromLocation( _BuildLocation( utils.SplitLines( GetFileContents( request_data, span[ 'file' ] ) ), span[ 'file' ], span[ 'start' ][ 'line' ], span[ 'start' ][ 'offset' ] ) ) except RuntimeError: raise RuntimeError( 'Could not find definition' ) def _GoToReferences( self, request_data ): self._Reload( request_data ) response = self._SendRequest( 'references', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'column_codepoint' ] } ) return [ responses.BuildGoToResponseFromLocation( _BuildLocation( utils.SplitLines( GetFileContents( request_data, ref[ 'file' ] ) ), ref[ 'file' ], ref[ 'start' ][ 'line' ], ref[ 'start' ][ 'offset' ] ), ref[ 'lineText' ] ) for ref in response[ 'refs' ] ] def _GoToType( self, request_data ): self._Reload( request_data ) try: filespans = self._SendRequest( 'typeDefinition', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'column_num' ] } ) span = filespans[ 0 ] return responses.BuildGoToResponse( filepath = span[ 'file' ], line_num = span[ 'start' ][ 'line' ], column_num = span[ 'start' ][ 'offset' ] ) except RuntimeError: raise RuntimeError( 'Could not find type definition' ) def _GetType( self, request_data ): self._Reload( request_data ) info = self._SendRequest( 'quickinfo', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'column_codepoint' ] } ) return responses.BuildDisplayMessageResponse( info[ 'displayString' ] ) def _GetDoc( self, request_data ): self._Reload( request_data ) info = self._SendRequest( 'quickinfo', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'column_codepoint' ] } ) message = '{0}\n\n{1}'.format( info[ 'displayString' ], info[ 'documentation' ] ) return responses.BuildDetailedInfoResponse( message ) def _RefactorRename( self, request_data, args ): if len( args ) != 1: raise ValueError( 'Please specify a new name to rename it to.\n' 'Usage: RefactorRename ' ) self._Reload( request_data ) response = self._SendRequest( 'rename', { 'file': request_data[ 'filepath' ], 'line': request_data[ 'line_num' ], 'offset': request_data[ 'column_codepoint' ], 'findInComments': False, 'findInStrings': False, } ) if not response[ 'info' ][ 'canRename' ]: raise RuntimeError( 'Value cannot be renamed: {0}'.format( response[ 'info' ][ 'localizedErrorMessage' ] ) ) # The format of the response is: # # body { # info { # ... # triggerSpan: { # length: original_length # } # } # # locs [ { # file: file_path # locs: [ # start: { # line: line_num # offset: offset # } # end { # line: line_num # offset: offset # } # ] } # ] # } # new_name = args[ 0 ] location = responses.Location( request_data[ 'line_num' ], request_data[ 'column_num' ], request_data[ 'filepath' ] ) chunks = [] for file_replacement in response[ 'locs' ]: chunks.extend( _BuildFixItChunksForFile( request_data, new_name, file_replacement ) ) return responses.BuildFixItResponse( [ responses.FixIt( location, chunks ) ] ) def _RestartServer( self, request_data ): with self._server_lock: self._StopServer() self._StartServer() # This is needed because after we restart the TSServer it would lose all # the information about the files we were working on. This means that the # newly started TSServer will know nothing about the buffer we're working # on after restarting the server. So if we restart the server and right # after that ask for completion in the buffer, the server will timeout. # So we notify the server that we're working on the current buffer. self.OnBufferVisit( request_data ) def _StopServer( self ): with self._server_lock: if self._ServerIsRunning(): _logger.info( 'Stopping TSServer with PID {0}'.format( self._tsserver_handle.pid ) ) self._SendCommand( 'exit' ) try: utils.WaitUntilProcessIsTerminated( self._tsserver_handle, timeout = 5 ) _logger.info( 'TSServer stopped' ) except RuntimeError: _logger.exception( 'Error while stopping TSServer' ) self._CleanUp() def _CleanUp( self ): utils.CloseStandardStreams( self._tsserver_handle ) self._tsserver_handle = None if not self.user_options[ 'server_keep_logfiles' ]: utils.RemoveIfExists( self._logfile ) self._logfile = None def Shutdown( self ): self._StopServer() def DebugInfo( self, request_data ): with self._server_lock: if self._ServerIsRunning(): return ( 'TypeScript completer debug information:\n' ' TSServer running\n' ' TSServer process ID: {0}\n' ' TSServer executable: {1}\n' ' TSServer logfile: {2}'.format( self._tsserver_handle.pid, PATH_TO_TSSERVER, self._logfile ) ) if self._logfile: return ( 'TypeScript completer debug information:\n' ' TSServer no longer running\n' ' TSServer executable: {0}\n' ' TSServer logfile: {1}'.format( PATH_TO_TSSERVER, self._logfile ) ) return ( 'TypeScript completer debug information:\n' ' TSServer is not running\n' ' TSServer executable: {0}'.format( PATH_TO_TSSERVER ) ) def _LogLevel(): return 'verbose' if _logger.isEnabledFor( logging.DEBUG ) else 'normal' def _ConvertCompletionData( completion_data ): return responses.BuildCompletionData( insertion_text = completion_data[ 'name' ], menu_text = completion_data[ 'name' ], kind = completion_data[ 'kind' ], extra_data = completion_data[ 'kind' ] ) def _ConvertDetailedCompletionData( completion_data, padding = 0 ): name = completion_data[ 'name' ] display_parts = completion_data[ 'displayParts' ] signature = ''.join( [ p[ 'text' ] for p in display_parts ] ) # needed to strip new lines and indentation from the signature signature = re.sub( '\s+', ' ', signature ) menu_text = '{0} {1}'.format( name.ljust( padding ), signature ) return responses.BuildCompletionData( insertion_text = name, menu_text = menu_text, kind = completion_data[ 'kind' ] ) def _BuildFixItChunkForRange( new_name, file_contents, file_name, source_range ): """ returns list FixItChunk for a tsserver source range """ return responses.FixItChunk( new_name, responses.Range( start = _BuildLocation( file_contents, file_name, source_range[ 'start' ][ 'line' ], source_range[ 'start' ][ 'offset' ] ), end = _BuildLocation( file_contents, file_name, source_range[ 'end' ][ 'line' ], source_range[ 'end' ][ 'offset' ] ) ) ) def _BuildFixItChunksForFile( request_data, new_name, file_replacement ): """ returns a list of FixItChunk for each replacement range for the supplied file""" # On windows, tsserver annoyingly returns file path as C:/blah/blah, # whereas all other paths in Python are of the C:\\blah\\blah form. We use # normpath to have python do the conversion for us. file_path = os.path.normpath( file_replacement[ 'file' ] ) file_contents = utils.SplitLines( GetFileContents( request_data, file_path ) ) return [ _BuildFixItChunkForRange( new_name, file_contents, file_path, r ) for r in file_replacement[ 'locs' ] ] def _BuildLocation( file_contents, filename, line, offset ): return responses.Location( line = line, # tsserver returns codepoint offsets, but we need byte offsets, so we must # convert column = utils.CodepointOffsetToByteOffset( file_contents[ line - 1 ], offset ), filename = filename ) ycmd-0+20161219+git486b809.orig/ycmd/completers/objcpp/0000755000175000017500000000000013026170313020545 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/objcpp/hook.py0000644000175000017500000000217513026170313022064 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import ycm_core from ycmd.completers.cpp.clang_completer import ClangCompleter def GetCompleter( user_options ): if ycm_core.HasClangSupport(): return ClangCompleter( user_options ) else: return None ycmd-0+20161219+git486b809.orig/ycmd/completers/completer_utils.py0000644000175000017500000002742413026170313023065 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import iteritems # Must not import ycm_core here! Vim imports completer, which imports this file. # We don't want ycm_core inside Vim. import os import re import copy from collections import defaultdict from ycmd.utils import ToCppStringCompatible, ToUnicode, ReadFile class PreparedTriggers( object ): def __init__( self, user_trigger_map = None, filetype_set = None ): user_prepared_triggers = ( _FiletypeTriggerDictFromSpec( dict( user_trigger_map ) ) if user_trigger_map else defaultdict( set ) ) final_triggers = _FiletypeDictUnion( PREPARED_DEFAULT_FILETYPE_TRIGGERS, user_prepared_triggers ) if filetype_set: final_triggers = dict( ( k, v ) for k, v in iteritems( final_triggers ) if k in filetype_set ) self._filetype_to_prepared_triggers = final_triggers def MatchingTriggerForFiletype( self, current_line, start_codepoint, column_codepoint, filetype ): try: triggers = self._filetype_to_prepared_triggers[ filetype ] except KeyError: return None return _MatchingSemanticTrigger( current_line, start_codepoint, column_codepoint, triggers ) def MatchesForFiletype( self, current_line, start_codepoint, column_codepoint, filetype ): return self.MatchingTriggerForFiletype( current_line, start_codepoint, column_codepoint, filetype ) is not None def _FiletypeTriggerDictFromSpec( trigger_dict_spec ): triggers_for_filetype = defaultdict( set ) for key, triggers in iteritems( trigger_dict_spec ): filetypes = key.split( ',' ) for filetype in filetypes: regexes = [ _PrepareTrigger( x ) for x in triggers ] triggers_for_filetype[ filetype ].update( regexes ) return triggers_for_filetype def _FiletypeDictUnion( dict_one, dict_two ): """Returns a new filetype dict that's a union of the provided two dicts. Dict params are supposed to be type defaultdict(set).""" def UpdateDict( first, second ): for key, value in iteritems( second ): first[ key ].update( value ) final_dict = defaultdict( set ) UpdateDict( final_dict, dict_one ) UpdateDict( final_dict, dict_two ) return final_dict # start_codepoint and column_codepoint are codepoint offsets in the unicode # string line_value. def _RegexTriggerMatches( trigger, line_value, start_codepoint, column_codepoint ): for match in trigger.finditer( line_value ): # By definition of 'start_codepoint', we know that the character just before # 'start_codepoint' is not an identifier character but all characters # between 'start_codepoint' and 'column_codepoint' are. This means that if # our trigger ends with an identifier character, its tail must match between # 'start_codepoint' and 'column_codepoint', 'start_codepoint' excluded. But # if it doesn't, its tail must match exactly at 'start_codepoint'. Both # cases are mutually exclusive hence the following condition. if start_codepoint <= match.end() and match.end() <= column_codepoint: return True return False # start_codepoint and column_codepoint are 0-based and are codepoint offsets # into the unicode string line_value. def _MatchingSemanticTrigger( line_value, start_codepoint, column_codepoint, trigger_list ): if start_codepoint < 0 or column_codepoint < 0: return None line_length = len( line_value ) if not line_length or start_codepoint > line_length: return None # Ignore characters after user's caret column line_value = line_value[ : column_codepoint ] for trigger in trigger_list: if _RegexTriggerMatches( trigger, line_value, start_codepoint, column_codepoint ): return trigger return None def _MatchesSemanticTrigger( line_value, start_codepoint, column_codepoint, trigger_list ): return _MatchingSemanticTrigger( line_value, start_codepoint, column_codepoint, trigger_list ) is not None def _PrepareTrigger( trigger ): trigger = ToUnicode( trigger ) if trigger.startswith( TRIGGER_REGEX_PREFIX ): return re.compile( trigger[ len( TRIGGER_REGEX_PREFIX ) : ], re.UNICODE ) return re.compile( re.escape( trigger ), re.UNICODE ) def _PathToCompletersFolder(): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script ) def PathToFiletypeCompleterPluginLoader( filetype ): return os.path.join( _PathToCompletersFolder(), filetype, 'hook.py' ) def FiletypeCompleterExistsForFiletype( filetype ): return os.path.exists( PathToFiletypeCompleterPluginLoader( filetype ) ) def FilterAndSortCandidatesWrap( candidates, sort_property, query ): from ycm_core import FilterAndSortCandidates # The c++ interface we use only understands the (*native*) 'str' type (i.e. # not the 'str' type from python-future. If we pass it a 'unicode' or # 'bytes' instance then various things blow up, such as converting to # std::string. Therefore all strings passed into the c++ API must pass through # ToCppStringCompatible (or more strictly all strings which the C++ code # needs to use and convert. In this case, just the insertion text property) # FIXME: This is actually quite inefficient in an area which is used # constantly and the key performance critical part of the system. There is # code in the C++ layer (see PythonSupport.cpp:GetUtf8String) which attempts # to work around this limitation. Unfortunately it has issues which cause the # above problems, and we work around it by converting here in the python # layer until we can come up with a better solution in the C++ layer. # Note: we must deep copy candidates because we do not want to clobber the # data that is passed in. It is actually used directly by the cache, so if # we change the data pointed to by the elements of candidates, then this will # be reflected in a subsequent response from the cache. This is particularly # important for those candidates which are *not* returned after the filter, as # they are not converted back to unicode. cpp_compatible_candidates = _ConvertCandidatesToCppCompatible( copy.deepcopy( candidates ), sort_property ) # However, the reset of the python layer expects all the candidates properties # to be some form of unicode string - a python-future str() instance. # So we need to convert the insertion text property back to a unicode string # before returning it. filtered_candidates = FilterAndSortCandidates( cpp_compatible_candidates, ToCppStringCompatible( sort_property ), ToCppStringCompatible( query ) ) return _ConvertCandidatesToPythonCompatible( filtered_candidates, sort_property ) def _ConvertCandidatesToCppCompatible( candidates, sort_property ): """Convert the candidates to the format expected by the C++ layer.""" return _ConvertCandidates( candidates, sort_property, ToCppStringCompatible ) def _ConvertCandidatesToPythonCompatible( candidates, sort_property ): """Convert the candidates to the format expected by the python layer.""" return _ConvertCandidates( candidates, sort_property, ToUnicode ) def _ConvertCandidates( candidates, sort_property, converter ): """Apply the conversion function |converter| to the logical insertion text field within the candidates in the candidate list |candidates|. The |sort_property| is required to determine the format of |candidates|. The conversion function should take a single argument (the string) and return the converted string. It should be one of ycmd.utils.ToUnicode or ycmd.utils.ToCppStringCompatible. Typically this method is not called directly, rather it is used via _ConvertCandidatesToCppCompatible and _ConvertCandidatesToPythonCompatible.""" if sort_property: for candidate in candidates: candidate[ sort_property ] = converter( candidate[ sort_property ] ) return candidates return [ converter( c ) for c in candidates ] TRIGGER_REGEX_PREFIX = 're!' DEFAULT_FILETYPE_TRIGGERS = { 'c' : [ '->', '.' ], 'objc' : [ '->', '.', r're!\[[_a-zA-Z]+\w*\s', # bracketed calls r're!^\s*[^\W\d]\w*\s', # bracketless calls r're!\[.*\]\s', # method composition ], 'ocaml' : [ '.', '#' ], 'cpp,objcpp' : [ '->', '.', '::' ], 'perl' : [ '->' ], 'php' : [ '->', '::' ], 'cs,java,javascript,typescript,d,python,perl6,scala,vb,elixir,go,groovy' : [ '.' ], 'ruby,rust' : [ '.', '::' ], 'lua' : [ '.', ':' ], 'erlang' : [ ':' ], } PREPARED_DEFAULT_FILETYPE_TRIGGERS = _FiletypeTriggerDictFromSpec( DEFAULT_FILETYPE_TRIGGERS ) INCLUDE_REGEX = re.compile( '\s*#\s*(?:include|import)\s*("|<)' ) def AtIncludeStatementStart( line ): match = INCLUDE_REGEX.match( line ) if not match: return False # Check if the whole string matches the regex return match.end() == len( line ) def GetIncludeStatementValue( line, check_closing = True ): """Returns include statement value and boolean indicating whether include statement is quoted. If check_closing is True the string is scanned for statement closing character (" or >) and substring between opening and closing characters is returned. The whole string after opening character is returned otherwise""" match = INCLUDE_REGEX.match( line ) include_value = None quoted_include = False if match: quoted_include = ( match.group( 1 ) == '"' ) if not check_closing: include_value = line[ match.end(): ] else: close_char = '"' if quoted_include else '>' close_char_pos = line.find( close_char, match.end() ) if close_char_pos != -1: include_value = line[ match.end() : close_char_pos ] return include_value, quoted_include def GetFileContents( request_data, filename ): """Returns the contents of the absolute path |filename| as a unicode string. If the file contents exist in |request_data| (i.e. it is open and potentially modified/dirty in the user's editor), then it is returned, otherwise the file is read from disk (assuming a UTF-8 encoding) and its contents returned.""" file_data = request_data[ 'file_data' ] if filename in file_data: return ToUnicode( file_data[ filename ][ 'contents' ] ) return ToUnicode( ReadFile( filename ) ) ycmd-0+20161219+git486b809.orig/ycmd/completers/python/0000755000175000017500000000000013026170313020611 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/python/hook.py0000644000175000017500000000211413026170313022121 0ustar onuronur# Copyright (C) 2011, 2012 Stephen Sugden # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.python.jedi_completer import JediCompleter def GetCompleter( user_options ): return JediCompleter( user_options ) ycmd-0+20161219+git486b809.orig/ycmd/completers/python/__init__.py0000644000175000017500000000000013026170313022710 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/python/jedi_completer.py0000644000175000017500000003570213026170313024157 0ustar onuronur# Copyright (C) 2011, 2012 Stephen Sugden # Google Inc. # Stanislav Golovanov # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from builtins import * # noqa from future import standard_library from future.utils import native standard_library.install_aliases() from ycmd.utils import ToBytes, ToUnicode, ProcessIsRunning from ycmd.completers.completer import Completer from ycmd import responses, utils, hmac_utils from tempfile import NamedTemporaryFile from base64 import b64encode import json import logging import urllib.parse import requests import threading import sys import os HMAC_SECRET_LENGTH = 16 JEDIHTTP_HMAC_HEADER = 'x-jedihttp-hmac' BINARY_NOT_FOUND_MESSAGE = ( 'The specified python interpreter {0} ' + 'was not found. Did you specify it correctly?' ) LOGFILE_FORMAT = 'jedihttp_{port}_{std}_' PATH_TO_JEDIHTTP = os.path.abspath( os.path.join( os.path.dirname( __file__ ), '..', '..', '..', 'third_party', 'JediHTTP', 'jedihttp.py' ) ) class JediCompleter( Completer ): """ A Completer that uses the Jedi engine HTTP wrapper JediHTTP. https://jedi.readthedocs.org/en/latest/ https://github.com/vheon/JediHTTP """ def __init__( self, user_options ): super( JediCompleter, self ).__init__( user_options ) self._server_lock = threading.RLock() self._jedihttp_port = None self._jedihttp_phandle = None self._logger = logging.getLogger( __name__ ) self._logfile_stdout = None self._logfile_stderr = None self._keep_logfiles = user_options[ 'server_keep_logfiles' ] self._hmac_secret = '' self._python_binary_path = sys.executable self._UpdatePythonBinary( user_options.get( 'python_binary_path' ) ) self._StartServer() def _UpdatePythonBinary( self, binary ): if binary: resolved_binary = utils.FindExecutable( binary ) if not resolved_binary: msg = BINARY_NOT_FOUND_MESSAGE.format( binary ) self._logger.error( msg ) raise RuntimeError( msg ) self._python_binary_path = resolved_binary def SupportedFiletypes( self ): """ Just python """ return [ 'python' ] def Shutdown( self ): self._StopServer() def ServerIsHealthy( self ): """ Check if JediHTTP is alive AND ready to serve requests. """ if not self._ServerIsRunning(): self._logger.debug( 'JediHTTP not running.' ) return False try: return bool( self._GetResponse( '/ready' ) ) except requests.exceptions.ConnectionError as e: self._logger.exception( e ) return False def _ServerIsRunning( self ): """ Check if JediHTTP is alive. That doesn't necessarily mean it's ready to serve requests; that's checked by ServerIsHealthy. """ with self._server_lock: return ( bool( self._jedihttp_port ) and ProcessIsRunning( self._jedihttp_phandle ) ) def RestartServer( self, binary = None ): """ Restart the JediHTTP Server. """ with self._server_lock: if binary: self._UpdatePythonBinary( binary ) self._StopServer() self._StartServer() def _StopServer( self ): with self._server_lock: if self._ServerIsRunning(): self._logger.info( 'Stopping JediHTTP server with PID {0}'.format( self._jedihttp_phandle.pid ) ) self._jedihttp_phandle.terminate() try: utils.WaitUntilProcessIsTerminated( self._jedihttp_phandle, timeout = 5 ) self._logger.info( 'JediHTTP server stopped' ) except RuntimeError: self._logger.exception( 'Error while stopping JediHTTP server' ) self._CleanUp() def _CleanUp( self ): self._jedihttp_phandle = None self._jedihttp_port = None if not self._keep_logfiles: utils.RemoveIfExists( self._logfile_stdout ) self._logfile_stdout = None utils.RemoveIfExists( self._logfile_stderr ) self._logfile_stderr = None def _StartServer( self ): with self._server_lock: self._logger.info( 'Starting JediHTTP server' ) self._jedihttp_port = utils.GetUnusedLocalhostPort() self._jedihttp_host = ToBytes( 'http://127.0.0.1:{0}'.format( self._jedihttp_port ) ) self._logger.info( 'using port {0}'.format( self._jedihttp_port ) ) self._hmac_secret = self._GenerateHmacSecret() # JediHTTP will delete the secret_file after it's done reading it with NamedTemporaryFile( delete = False, mode = 'w+' ) as hmac_file: json.dump( { 'hmac_secret': ToUnicode( b64encode( self._hmac_secret ) ) }, hmac_file ) command = [ self._python_binary_path, PATH_TO_JEDIHTTP, '--port', str( self._jedihttp_port ), '--log', self._GetLoggingLevel(), '--hmac-file-secret', hmac_file.name ] self._logfile_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._jedihttp_port, std = 'stdout' ) ) self._logfile_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._jedihttp_port, std = 'stderr' ) ) with utils.OpenForStdHandle( self._logfile_stdout ) as logout: with utils.OpenForStdHandle( self._logfile_stderr ) as logerr: self._jedihttp_phandle = utils.SafePopen( command, stdout = logout, stderr = logerr ) def _GenerateHmacSecret( self ): return os.urandom( HMAC_SECRET_LENGTH ) def _GetLoggingLevel( self ): # Tests are run with the NOTSET logging level but JediHTTP only accepts the # predefined levels above (DEBUG, INFO, WARNING, etc.). log_level = max( self._logger.getEffectiveLevel(), logging.DEBUG ) return logging.getLevelName( log_level ).lower() def _GetResponse( self, handler, request_data = {} ): """POST JSON data to JediHTTP server and return JSON response.""" handler = ToBytes( handler ) url = urllib.parse.urljoin( self._jedihttp_host, handler ) parameters = self._TranslateRequestForJediHTTP( request_data ) body = ToBytes( json.dumps( parameters ) ) if parameters else bytes() extra_headers = self._ExtraHeaders( handler, body ) self._logger.debug( 'Making JediHTTP request: %s %s %s %s', 'POST', url, extra_headers, body ) response = requests.request( native( bytes( b'POST' ) ), native( url ), data = body, headers = extra_headers ) response.raise_for_status() return response.json() def _ExtraHeaders( self, handler, body ): hmac = hmac_utils.CreateRequestHmac( bytes( b'POST' ), handler, body, self._hmac_secret ) extra_headers = { 'content-type': 'application/json' } extra_headers[ JEDIHTTP_HMAC_HEADER ] = b64encode( hmac ) return extra_headers def _TranslateRequestForJediHTTP( self, request_data ): if not request_data: return {} path = request_data[ 'filepath' ] source = request_data[ 'file_data' ][ path ][ 'contents' ] line = request_data[ 'line_num' ] # JediHTTP (as Jedi itself) expects columns to start at 0, not 1, and for # them to be unicode codepoint offsets. col = request_data[ 'start_codepoint' ] - 1 return { 'source': source, 'line': line, 'col': col, 'source_path': path } def _GetExtraData( self, completion ): location = {} if completion[ 'module_path' ]: location[ 'filepath' ] = completion[ 'module_path' ] if completion[ 'line' ]: location[ 'line_num' ] = completion[ 'line' ] if completion[ 'column' ]: location[ 'column_num' ] = completion[ 'column' ] + 1 if location: extra_data = {} extra_data[ 'location' ] = location return extra_data else: return None def ComputeCandidatesInner( self, request_data ): return [ responses.BuildCompletionData( completion[ 'name' ], completion[ 'description' ], completion[ 'docstring' ], extra_data = self._GetExtraData( completion ) ) for completion in self._JediCompletions( request_data ) ] def _JediCompletions( self, request_data ): return self._GetResponse( '/completions', request_data )[ 'completions' ] def GetSubcommandsMap( self ): return { 'GoToDefinition' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDeclaration': ( lambda self, request_data, args: self._GoToDeclaration( request_data ) ), 'GoTo' : ( lambda self, request_data, args: self._GoTo( request_data ) ), 'GetDoc' : ( lambda self, request_data, args: self._GetDoc( request_data ) ), 'GoToReferences' : ( lambda self, request_data, args: self._GoToReferences( request_data ) ), 'StopServer' : ( lambda self, request_data, args: self.Shutdown() ), 'RestartServer' : ( lambda self, request_data, args: self.RestartServer( *args ) ) } def _GoToDefinition( self, request_data ): definitions = self._GetDefinitionsList( '/gotodefinition', request_data ) if not definitions: raise RuntimeError( 'Can\'t jump to definition.' ) return self._BuildGoToResponse( definitions ) def _GoToDeclaration( self, request_data ): definitions = self._GetDefinitionsList( '/gotoassignment', request_data ) if not definitions: raise RuntimeError( 'Can\'t jump to declaration.' ) return self._BuildGoToResponse( definitions ) def _GoTo( self, request_data ): try: return self._GoToDefinition( request_data ) except Exception as e: self._logger.exception( e ) pass try: return self._GoToDeclaration( request_data ) except Exception as e: self._logger.exception( e ) raise RuntimeError( 'Can\'t jump to definition or declaration.' ) def _GetDoc( self, request_data ): try: definitions = self._GetDefinitionsList( '/gotodefinition', request_data ) return self._BuildDetailedInfoResponse( definitions ) except Exception as e: self._logger.exception( e ) raise RuntimeError( 'Can\'t find a definition.' ) def _GoToReferences( self, request_data ): definitions = self._GetDefinitionsList( '/usages', request_data ) if not definitions: raise RuntimeError( 'Can\'t find references.' ) return self._BuildGoToResponse( definitions ) def _GetDefinitionsList( self, handler, request_data ): try: response = self._GetResponse( handler, request_data ) return response[ 'definitions' ] except Exception as e: self._logger.exception( e ) raise RuntimeError( 'Cannot follow nothing. ' 'Put your cursor on a valid name.' ) def _BuildGoToResponse( self, definition_list ): if len( definition_list ) == 1: definition = definition_list[ 0 ] if definition[ 'in_builtin_module' ]: if definition[ 'is_keyword' ]: raise RuntimeError( 'Cannot get the definition of Python keywords.' ) else: raise RuntimeError( 'Builtin modules cannot be displayed.' ) else: return responses.BuildGoToResponse( definition[ 'module_path' ], definition[ 'line' ], definition[ 'column' ] + 1 ) else: # multiple definitions defs = [] for definition in definition_list: if definition[ 'in_builtin_module' ]: defs.append( responses.BuildDescriptionOnlyGoToResponse( 'Builtin ' + definition[ 'description' ] ) ) else: defs.append( responses.BuildGoToResponse( definition[ 'module_path' ], definition[ 'line' ], definition[ 'column' ] + 1, definition[ 'description' ] ) ) return defs def _BuildDetailedInfoResponse( self, definition_list ): docs = [ definition[ 'docstring' ] for definition in definition_list ] return responses.BuildDetailedInfoResponse( '\n---\n'.join( docs ) ) def DebugInfo( self, request_data ): with self._server_lock: if self._ServerIsRunning(): return ( 'Python completer debug information:\n' ' JediHTTP running at: http://127.0.0.1:{0}\n' ' JediHTTP process ID: {1}\n' ' JediHTTP executable: {2}\n' ' JediHTTP logfiles:\n' ' {3}\n' ' {4}\n' ' Python interpreter: {5}'.format( self._jedihttp_port, self._jedihttp_phandle.pid, PATH_TO_JEDIHTTP, self._logfile_stdout, self._logfile_stderr, self._python_binary_path ) ) if self._logfile_stdout and self._logfile_stderr: return ( 'Python completer debug information:\n' ' JediHTTP no longer running\n' ' JediHTTP executable: {0}\n' ' JediHTTP logfiles:\n' ' {1}\n' ' {2}\n' ' Python interpreter: {3}'.format( PATH_TO_JEDIHTTP, self._logfile_stdout, self._logfile_stderr, self._python_binary_path ) ) return ( 'Python completer debug information:\n' ' JediHTTP is not running\n' ' JediHTTP executable: {0}\n' ' Python interpreter: {1}'.format( PATH_TO_JEDIHTTP, self._python_binary_path ) ) ycmd-0+20161219+git486b809.orig/ycmd/completers/general/0000755000175000017500000000000013026170313020705 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/general/filename_completer.py0000644000175000017500000001720313026170313025114 0ustar onuronur# Copyright (C) 2013 Stanislav Golovanov # Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os import re from collections import defaultdict from ycmd.completers.completer import Completer from ycmd.completers.completer_utils import ( AtIncludeStatementStart, GetIncludeStatementValue ) from ycmd.completers.cpp.clang_completer import InCFamilyFile from ycmd.completers.cpp.flags import Flags from ycmd.utils import GetCurrentDirectory, OnWindows, ToUnicode from ycmd import responses EXTRA_INFO_MAP = { 1 : '[File]', 2 : '[Dir]', 3 : '[File&Dir]' } class FilenameCompleter( Completer ): """ General completer that provides filename and filepath completions. """ def __init__( self, user_options ): super( FilenameCompleter, self ).__init__( user_options ) self._flags = Flags() # On Windows, backslashes are also valid path separators. self._triggers = [ '/', '\\' ] if OnWindows() else [ '/' ] self._path_regex = re.compile( """ # Head part (?: # 'D:/'-like token [A-z]+:[%(sep)s]| # '/', './', '../', or '~' \.{0,2}[%(sep)s]|~| # '$var/' \$[A-Za-z0-9{}_]+[%(sep)s] )+ # Tail part (?: # any alphanumeric, symbol or space literal [ %(sep)sa-zA-Z0-9(){}$+_~.\x80-\xff-\[\]]| # skip any special symbols [^\x20-\x7E]| # backslash and 1 char after it \\. )*$ """ % { 'sep': '/\\\\' if OnWindows() else '/' }, re.X ) def ShouldCompleteIncludeStatement( self, request_data ): start_codepoint = request_data[ 'start_codepoint' ] - 1 current_line = request_data[ 'line_value' ] filepath = request_data[ 'filepath' ] filetypes = request_data[ 'file_data' ][ filepath ][ 'filetypes' ] return ( InCFamilyFile( filetypes ) and AtIncludeStatementStart( current_line[ : start_codepoint ] ) ) def ShouldUseNowInner( self, request_data ): current_line = request_data[ 'line_value' ] start_codepoint = request_data[ 'start_codepoint' ] # inspect the previous 'character' from the start column to find the trigger # note: 1-based still. we subtract 1 when indexing into current_line trigger_codepoint = start_codepoint - 1 return ( trigger_codepoint > 0 and ( current_line[ trigger_codepoint - 1 ] in self._triggers or self.ShouldCompleteIncludeStatement( request_data ) ) ) def SupportedFiletypes( self ): return [] def ComputeCandidatesInner( self, request_data ): current_line = request_data[ 'line_value' ] start_codepoint = request_data[ 'start_codepoint' ] - 1 filepath = request_data[ 'filepath' ] filetypes = request_data[ 'file_data' ][ filepath ][ 'filetypes' ] line = current_line[ : start_codepoint ] if InCFamilyFile( filetypes ): path_dir, quoted_include = ( GetIncludeStatementValue( line, check_closing = False ) ) if path_dir is not None: # We do what GCC does for <> versus "": # http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html client_data = request_data.get( 'extra_conf_data', None ) return _GenerateCandidatesForPaths( self.GetPathsIncludeCase( path_dir, quoted_include, filepath, client_data ) ) path_match = self._path_regex.search( line ) path_dir = os.path.expanduser( os.path.expandvars( path_match.group() ) ) if path_match else '' # If the client supplied its working directory, use that instead of the # working directory of ycmd working_dir = request_data.get( 'working_dir' ) return _GenerateCandidatesForPaths( _GetPathsStandardCase( path_dir, self.user_options[ 'filepath_completion_use_working_dir' ], filepath, working_dir) ) def GetPathsIncludeCase( self, path_dir, quoted_include, filepath, client_data ): paths = [] quoted_include_paths, include_paths = ( self._flags.UserIncludePaths( filepath, client_data ) ) if quoted_include: include_paths.extend( quoted_include_paths ) for include_path in include_paths: unicode_path = ToUnicode( os.path.join( include_path, path_dir ) ) try: # We need to pass a unicode string to get unicode strings out of # listdir. relative_paths = os.listdir( unicode_path ) except: relative_paths = [] paths.extend( os.path.join( include_path, path_dir, relative_path ) for relative_path in relative_paths ) return sorted( set( paths ) ) def _GetAbsolutePathForCompletions( path_dir, use_working_dir, filepath, working_dir ): """ Returns the absolute path for which completion suggestions should be returned (in the standard case). """ if os.path.isabs( path_dir ): # This is already an absolute path, return it return path_dir elif use_working_dir: # Return paths relative to the working directory of the client, if # supplied, otherwise relative to the current working directory of this # process if working_dir: return os.path.join( working_dir, path_dir ) else: return os.path.join( GetCurrentDirectory(), path_dir ) else: # Return paths relative to the file return os.path.join( os.path.join( os.path.dirname( filepath ) ), path_dir ) def _GetPathsStandardCase( path_dir, use_working_dir, filepath, working_dir ): absolute_path_dir = _GetAbsolutePathForCompletions( path_dir, use_working_dir, filepath, working_dir ) try: # We need to pass a unicode string to get unicode strings out of # listdir. relative_paths = os.listdir( ToUnicode( absolute_path_dir ) ) except: relative_paths = [] return ( os.path.join( absolute_path_dir, relative_path ) for relative_path in relative_paths ) def _GenerateCandidatesForPaths( absolute_paths ): extra_info = defaultdict( int ) basenames = [] for absolute_path in absolute_paths: basename = os.path.basename( absolute_path ) if extra_info[ basename ] == 0: basenames.append( basename ) is_dir = os.path.isdir( absolute_path ) extra_info[ basename ] |= ( 2 if is_dir else 1 ) completion_dicts = [] # Keep original ordering for basename in basenames: completion_dicts.append( responses.BuildCompletionData( basename, EXTRA_INFO_MAP[ extra_info[ basename ] ] ) ) return completion_dicts ycmd-0+20161219+git486b809.orig/ycmd/completers/general/__init__.py0000644000175000017500000000000013026170313023004 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/general/ultisnips_completer.py0000644000175000017500000000371013026170313025364 0ustar onuronur# Copyright (C) 2013 Stanislav Golovanov # Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.general_completer import GeneralCompleter from ycmd import responses class UltiSnipsCompleter( GeneralCompleter ): """ General completer that provides UltiSnips snippet names in completions. """ def __init__( self, user_options ): super( UltiSnipsCompleter, self ).__init__( user_options ) self._candidates = None self._filtered_candidates = None def ShouldUseNow( self, request_data ): return self.QueryLengthAboveMinThreshold( request_data ) def ComputeCandidates( self, request_data ): if not self.ShouldUseNow( request_data ): return [] return self.FilterAndSortCandidates( self._candidates, request_data[ 'query' ] ) def OnBufferVisit( self, request_data ): raw_candidates = request_data.get( 'ultisnips_snippets', [] ) self._candidates = [ responses.BuildCompletionData( snip[ 'trigger' ], ' ' + snip[ 'description' ] ) for snip in raw_candidates ] ycmd-0+20161219+git486b809.orig/ycmd/completers/general/general_completer_store.py0000644000175000017500000001004113026170313026156 0ustar onuronur# Copyright (C) 2013 Stanislav Golovanov # Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.completer import Completer from ycmd.completers.all.identifier_completer import IdentifierCompleter from ycmd.completers.general.filename_completer import FilenameCompleter from ycmd.completers.general.ultisnips_completer import UltiSnipsCompleter class GeneralCompleterStore( Completer ): """ Holds a list of completers that can be used in all filetypes. It overrides all Competer API methods so that specific calls to GeneralCompleterStore are passed to all general completers. """ def __init__( self, user_options ): super( GeneralCompleterStore, self ).__init__( user_options ) self._identifier_completer = IdentifierCompleter( user_options ) self._filename_completer = FilenameCompleter( user_options ) self._ultisnips_completer = UltiSnipsCompleter( user_options ) self._non_filename_completers = [ self._identifier_completer ] if user_options.get( 'use_ultisnips_completer', True ): self._non_filename_completers.append( self._ultisnips_completer ) self._all_completers = [ self._identifier_completer, self._filename_completer, self._ultisnips_completer ] self._current_query_completers = [] def SupportedFiletypes( self ): return set() def GetIdentifierCompleter( self ): return self._identifier_completer def ShouldUseNow( self, request_data ): self._current_query_completers = [] if self._filename_completer.ShouldUseNow( request_data ): self._current_query_completers = [ self._filename_completer ] return True should_use_now = False for completer in self._non_filename_completers: should_use_this_completer = completer.ShouldUseNow( request_data ) should_use_now = should_use_now or should_use_this_completer if should_use_this_completer: self._current_query_completers.append( completer ) return should_use_now def ComputeCandidates( self, request_data ): if not self.ShouldUseNow( request_data ): return [] candidates = [] for completer in self._current_query_completers: candidates += completer.ComputeCandidates( request_data ) return candidates def OnFileReadyToParse( self, request_data ): for completer in self._all_completers: completer.OnFileReadyToParse( request_data ) def OnBufferVisit( self, request_data ): for completer in self._all_completers: completer.OnBufferVisit( request_data ) def OnBufferUnload( self, request_data ): for completer in self._all_completers: completer.OnBufferUnload( request_data ) def OnInsertLeave( self, request_data ): for completer in self._all_completers: completer.OnInsertLeave( request_data ) def OnCurrentIdentifierFinished( self, request_data ): for completer in self._all_completers: completer.OnCurrentIdentifierFinished( request_data ) def GettingCompletions( self ): for completer in self._all_completers: completer.GettingCompletions() def Shutdown( self ): for completer in self._all_completers: completer.Shutdown() ycmd-0+20161219+git486b809.orig/ycmd/completers/go/0000755000175000017500000000000013026170313017675 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/go/hook.py0000644000175000017500000000217613026170313021215 0ustar onuronur# Copyright (C) 2015 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.go.go_completer import GoCompleter, ShouldEnableGoCompleter def GetCompleter( user_options ): if not ShouldEnableGoCompleter( user_options ): return None return GoCompleter( user_options ) ycmd-0+20161219+git486b809.orig/ycmd/completers/go/go_completer.py0000644000175000017500000003463213026170313022736 0ustar onuronur# Copyright (C) 2015 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import json import logging import os import subprocess import threading from ycmd import responses from ycmd import utils from ycmd.utils import ToBytes, ToUnicode, ExecutableName from ycmd.completers.completer import Completer BINARY_NOT_FOUND_MESSAGE = ( '{0} binary not found. Did you build it? ' 'You can do so by running ' '"./install.py --gocode-completer".' ) SHELL_ERROR_MESSAGE = ( 'Command {command} failed with code {code} and error ' '"{error}".' ) COMPUTE_OFFSET_ERROR_MESSAGE = ( 'Go completer could not compute byte offset ' 'corresponding to line {line} and column ' '{column}.' ) GOCODE_PARSE_ERROR_MESSAGE = 'Gocode returned invalid JSON response.' GOCODE_NO_COMPLETIONS_MESSAGE = 'No completions found.' GOCODE_PANIC_MESSAGE = ( 'Gocode panicked trying to find completions, ' 'you likely have a syntax error.' ) DIR_OF_THIRD_PARTY = os.path.abspath( os.path.join( os.path.dirname( __file__ ), '..', '..', '..', 'third_party' ) ) GO_BINARIES = dict( { 'gocode': os.path.join( DIR_OF_THIRD_PARTY, 'gocode', ExecutableName( 'gocode' ) ), 'godef': os.path.join( DIR_OF_THIRD_PARTY, 'godef', ExecutableName( 'godef' ) ) } ) LOGFILE_FORMAT = 'gocode_{port}_{std}_' _logger = logging.getLogger( __name__ ) def FindBinary( binary, user_options ): """Find the path to the Gocode/Godef binary. If 'gocode_binary_path' or 'godef_binary_path' in the options is blank, use the version installed with YCM, if it exists. If the 'gocode_binary_path' or 'godef_binary_path' is specified, use it as an absolute path. If the resolved binary exists, return the path, otherwise return None.""" def _FindPath(): key = '{0}_binary_path'.format( binary ) if user_options.get( key ): return user_options[ key ] return GO_BINARIES.get( binary ) binary_path = _FindPath() if os.path.isfile( binary_path ): return binary_path return None def ShouldEnableGoCompleter( user_options ): def _HasBinary( binary ): binary_path = FindBinary( binary, user_options ) if not binary_path: _logger.error( BINARY_NOT_FOUND_MESSAGE.format( binary ) ) return binary_path return all( _HasBinary( binary ) for binary in [ 'gocode', 'godef' ] ) class GoCompleter( Completer ): """Completer for Go using the Gocode daemon for completions: https://github.com/nsf/gocode and the Godef binary for jumping to definitions: https://github.com/Manishearth/godef""" def __init__( self, user_options ): super( GoCompleter, self ).__init__( user_options ) self._gocode_binary_path = FindBinary( 'gocode', user_options ) self._gocode_lock = threading.RLock() self._gocode_handle = None self._gocode_port = None self._gocode_address = None self._gocode_stderr = None self._gocode_stdout = None self._godef_binary_path = FindBinary( 'godef', user_options ) self._keep_logfiles = user_options[ 'server_keep_logfiles' ] self._StartServer() def SupportedFiletypes( self ): return [ 'go' ] def ComputeCandidatesInner( self, request_data ): filename = request_data[ 'filepath' ] _logger.info( 'Gocode completion request {0}'.format( filename ) ) contents = utils.ToBytes( request_data[ 'file_data' ][ filename ][ 'contents' ] ) # NOTE: Offsets sent to gocode are byte offsets, so using start_column # with contents (a bytes instance) above is correct. offset = _ComputeOffset( contents, request_data[ 'line_num' ], request_data[ 'start_column' ] ) stdoutdata = self._ExecuteCommand( [ self._gocode_binary_path, '-sock', 'tcp', '-addr', self._gocode_address, '-f=json', 'autocomplete', filename, str( offset ) ], contents = contents ) try: resultdata = json.loads( ToUnicode( stdoutdata ) ) except ValueError: _logger.error( GOCODE_PARSE_ERROR_MESSAGE ) raise RuntimeError( GOCODE_PARSE_ERROR_MESSAGE ) if len( resultdata ) != 2: _logger.error( GOCODE_NO_COMPLETIONS_MESSAGE ) raise RuntimeError( GOCODE_NO_COMPLETIONS_MESSAGE ) for result in resultdata[ 1 ]: if result.get( 'class' ) == 'PANIC': raise RuntimeError( GOCODE_PANIC_MESSAGE ) return [ _ConvertCompletionData( x ) for x in resultdata[ 1 ] ] def GetSubcommandsMap( self ): return { 'StopServer' : ( lambda self, request_data, args: self._StopServer() ), 'RestartServer' : ( lambda self, request_data, args: self._RestartServer() ), 'GoTo' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDefinition' : ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), 'GoToDeclaration': ( lambda self, request_data, args: self._GoToDefinition( request_data ) ), } def _ExecuteCommand( self, command, contents = None ): """Run a command in a subprocess and communicate with it using the contents argument. Return the standard output. It is used to send a command to the Gocode daemon or execute the Godef binary.""" phandle = utils.SafePopen( command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) stdoutdata, stderrdata = phandle.communicate( contents ) if phandle.returncode: message = SHELL_ERROR_MESSAGE.format( command = ' '.join( command ), code = phandle.returncode, error = ToUnicode( stderrdata.strip() ) ) _logger.error( message ) raise RuntimeError( message ) return stdoutdata def _StartServer( self ): """Start the Gocode server.""" with self._gocode_lock: _logger.info( 'Starting Gocode server' ) self._gocode_port = utils.GetUnusedLocalhostPort() self._gocode_address = '127.0.0.1:{0}'.format( self._gocode_port ) command = [ self._gocode_binary_path, '-s', '-sock', 'tcp', '-addr', self._gocode_address ] if _logger.isEnabledFor( logging.DEBUG ): command.append( '-debug' ) self._gocode_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._gocode_port, std = 'stdout' ) ) self._gocode_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._gocode_port, std = 'stderr' ) ) with utils.OpenForStdHandle( self._gocode_stdout ) as stdout: with utils.OpenForStdHandle( self._gocode_stderr ) as stderr: self._gocode_handle = utils.SafePopen( command, stdout = stdout, stderr = stderr ) def _StopServer( self ): """Stop the Gocode server.""" with self._gocode_lock: if self._ServerIsRunning(): _logger.info( 'Stopping Gocode server with PID {0}'.format( self._gocode_handle.pid ) ) self._ExecuteCommand( [ self._gocode_binary_path, '-sock', 'tcp', '-addr', self._gocode_address, 'close' ] ) try: utils.WaitUntilProcessIsTerminated( self._gocode_handle, timeout = 5 ) _logger.info( 'Gocode server stopped' ) except RuntimeError: _logger.exception( 'Error while stopping Gocode server' ) self._CleanUp() def _CleanUp( self ): self._gocode_handle = None self._gocode_port = None self._gocode_address = None if not self._keep_logfiles: if self._gocode_stdout: utils.RemoveIfExists( self._gocode_stdout ) self._gocode_stdout = None if self._gocode_stderr: utils.RemoveIfExists( self._gocode_stderr ) self._gocode_stderr = None def _RestartServer( self ): """Restart the Gocode server.""" with self._gocode_lock: self._StopServer() self._StartServer() def _GoToDefinition( self, request_data ): filename = request_data[ 'filepath' ] _logger.info( 'Godef GoTo request {0}'.format( filename ) ) contents = utils.ToBytes( request_data[ 'file_data' ][ filename ][ 'contents' ] ) offset = _ComputeOffset( contents, request_data[ 'line_num' ], request_data[ 'column_num' ] ) try: stdout = self._ExecuteCommand( [ self._godef_binary_path, '-i', '-f={0}'.format( filename ), '-json', '-o={0}'.format( offset ) ], contents = contents ) # We catch this exception type and not a more specific one because we # raise it in _ExecuteCommand when the command fails. except RuntimeError as error: _logger.exception( error ) raise RuntimeError( 'Can\'t find a definition.' ) return self._ConstructGoToFromResponse( stdout ) def _ConstructGoToFromResponse( self, response_str ): parsed = json.loads( ToUnicode( response_str ) ) if 'filename' in parsed and 'column' in parsed: return responses.BuildGoToResponse( parsed[ 'filename' ], int( parsed[ 'line' ] ), int( parsed[ 'column' ] ) ) raise RuntimeError( 'Can\'t jump to definition.' ) def Shutdown( self ): self._StopServer() def _ServerIsRunning( self ): """Check if the Gocode server is running (process is up).""" return utils.ProcessIsRunning( self._gocode_handle ) def ServerIsHealthy( self ): """Check if the Gocode server is healthy (up and serving).""" if not self._ServerIsRunning(): return False try: self._ExecuteCommand( [ self._gocode_binary_path, '-sock', 'tcp', '-addr', self._gocode_address, 'status' ] ) return True # We catch this exception type and not a more specific one because we # raise it in _ExecuteCommand when the command fails. except RuntimeError as error: _logger.exception( error ) return False def ServerIsReady( self ): """Check if the Gocode server is ready. Same as the healthy status.""" return self.ServerIsHealthy() def DebugInfo( self, request_data ): with self._gocode_lock: if self._ServerIsRunning(): return ( 'Go completer debug information:\n' ' Gocode running at: http://{0}\n' ' Gocode process ID: {1}\n' ' Gocode executable: {2}\n' ' Gocode logfiles:\n' ' {3}\n' ' {4}\n' ' Godef executable: {5}'.format( self._gocode_address, self._gocode_handle.pid, self._gocode_binary_path, self._gocode_stdout, self._gocode_stderr, self._godef_binary_path ) ) if self._gocode_stdout and self._gocode_stderr: return ( 'Go completer debug information:\n' ' Gocode no longer running\n' ' Gocode executable: {0}\n' ' Gocode logfiles:\n' ' {1}\n' ' {2}\n' ' Godef executable: {3}'.format( self._gocode_binary_path, self._gocode_stdout, self._gocode_stderr, self._godef_binary_path ) ) return ( 'Go completer debug information:\n' ' Gocode is not running\n' ' Gocode executable: {0}\n' ' Godef executable: {1}'.format( self._gocode_binary_path, self._godef_binary_path ) ) def _ComputeOffset( contents, line, column ): """Compute the byte offset in the file given the line and column.""" contents = ToBytes( contents ) current_line = 1 current_column = 1 newline = bytes( b'\n' )[ 0 ] for i, byte in enumerate( contents ): if current_line == line and current_column == column: return i current_column += 1 if byte == newline: current_line += 1 current_column = 1 message = COMPUTE_OFFSET_ERROR_MESSAGE.format( line = line, column = column ) _logger.error( message ) raise RuntimeError( message ) def _ConvertCompletionData( completion_data ): return responses.BuildCompletionData( insertion_text = completion_data[ 'name' ], menu_text = completion_data[ 'name' ], extra_menu_info = completion_data[ 'type' ], kind = completion_data[ 'class' ], detailed_info = ' '.join( [ completion_data[ 'name' ], completion_data[ 'type' ], completion_data[ 'class' ] ] ) ) ycmd-0+20161219+git486b809.orig/ycmd/completers/go/__init__.py0000644000175000017500000000000013026170313021774 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/cs/0000755000175000017500000000000013026170313017675 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/cs/hook.py0000644000175000017500000000211413026170313021205 0ustar onuronur# Copyright (C) 2011, 2012 Chiel ten Brinke # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.completers.cs.cs_completer import CsharpCompleter def GetCompleter( user_options ): return CsharpCompleter( user_options ) ycmd-0+20161219+git486b809.orig/ycmd/completers/cs/__init__.py0000644000175000017500000000000013026170313021774 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/cs/solutiondetection.py0000644000175000017500000001173713026170313024033 0ustar onuronur# Copyright (C) 2013 Google Inc. # Copyright (C) 2016 ycmd contributors. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os import glob import logging from inspect import getfile from ycmd import extra_conf_store from ycmd.utils import ToUnicode __logger = logging.getLogger( __name__ ) def FindSolutionPath( filepath ): """Try to find suitable solution file given a source file path using all available information sources""" # try to load ycm_extra_conf # if it needs to be verified, abort here and try again later module = extra_conf_store.ModuleForSourceFile( filepath ) path_to_solutionfile = PollModule( module, filepath ) if not path_to_solutionfile: # ycm_extra_conf not available or did not provide a solution file path_to_solutionfile = GuessFile( filepath ) return path_to_solutionfile def PollModule( module, filepath ): """ Try to use passed module in the selection process by calling CSharpSolutionFile on it """ path_to_solutionfile = None module_hint = None if module: try: module_hint = module.CSharpSolutionFile( filepath ) __logger.info( u'extra_conf_store suggests {0} as solution file'.format( ToUnicode( module_hint ) ) ) if module_hint: # received a full path or one relative to the config's location? candidates = [ module_hint, os.path.join( os.path.dirname( getfile( module ) ), module_hint ) ] # try the assumptions for path in candidates: if os.path.isfile( path ): # path seems to point to a solution path_to_solutionfile = path __logger.info( u'Using solution file {0} selected by extra_conf_store'.format( path_to_solutionfile ) ) break except AttributeError as e: # the config script might not provide solution file locations __logger.error( u'Could not retrieve solution for {0}' 'from extra_conf_store: {1}'.format( filepath, str( e ) ) ) return path_to_solutionfile def GuessFile( filepath ): """ Find solution files by searching upwards in the file tree """ tokens = _PathComponents( filepath ) for i in reversed( range( len( tokens ) - 1 ) ): path = os.path.join( *tokens[ : i + 1 ] ) candidates = glob.glob1( path, '*.sln' ) if len( candidates ) > 0: # do the whole procedure only for the first solution file(s) you find return _SolutionTestCheckHeuristics( candidates, tokens, i ) return None def _SolutionTestCheckHeuristics( candidates, tokens, i ): """ Test if one of the candidate files stands out """ path = os.path.join( *tokens[ : i + 1 ] ) selection = None # if there is just one file here, use that if len( candidates ) == 1 : selection = os.path.join( path, candidates[ 0 ] ) __logger.info( u'Selected solution file {0} as it is the first one found'.format( selection ) ) # there is more than one file, try some hints to decide # 1. is there a solution named just like the subdirectory with the source? if ( not selection and i < len( tokens ) - 1 and u'{0}.sln'.format( tokens[ i + 1 ] ) in candidates ): selection = os.path.join( path, u'{0}.sln'.format( tokens[ i + 1 ] ) ) __logger.info( u'Selected solution file {0} as it matches source subfolder'.format( selection ) ) # 2. is there a solution named just like the directory containing the # solution? if not selection and u'{0}.sln'.format( tokens[ i ] ) in candidates : selection = os.path.join( path, u'{0}.sln'.format( tokens[ i ] ) ) __logger.info( u'Selected solution file {0} as it matches containing folder'.format( selection ) ) if not selection: __logger.error( u'Could not decide between multiple solution files:\n{0}'.format( candidates ) ) return selection def _PathComponents( path ): path_components = [] while True: path, folder = os.path.split( path ) if folder: path_components.append( folder ) else: if path: path_components.append( path ) break path_components.reverse() return path_components ycmd-0+20161219+git486b809.orig/ycmd/completers/cs/cs_completer.py0000644000175000017500000006527513026170313022745 0ustar onuronur# Copyright (C) 2011, 2012 Chiel ten Brinke # Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from builtins import * # noqa from future import standard_library standard_library.install_aliases() from future.utils import itervalues from collections import defaultdict import os import re from ycmd.completers.completer import Completer from ycmd.utils import ForceSemanticCompletion, CodepointOffsetToByteOffset from ycmd import responses from ycmd import utils from ycmd.completers.completer_utils import GetFileContents import requests import urllib.parse import logging from . import solutiondetection import threading SERVER_NOT_FOUND_MSG = ( 'OmniSharp server binary not found at {0}. ' + 'Did you compile it? You can do so by running ' + '"./install.py --omnisharp-completer".' ) INVALID_FILE_MESSAGE = 'File is invalid.' NO_DIAGNOSTIC_MESSAGE = 'No diagnostic for current line!' PATH_TO_OMNISHARP_BINARY = os.path.abspath( os.path.join( os.path.dirname( __file__ ), '..', '..', '..', 'third_party', 'OmniSharpServer', 'OmniSharp', 'bin', 'Release', 'OmniSharp.exe' ) ) LOGFILE_FORMAT = 'omnisharp_{port}_{sln}_{std}_' class CsharpCompleter( Completer ): """ A Completer that uses the Omnisharp server as completion engine. """ def __init__( self, user_options ): super( CsharpCompleter, self ).__init__( user_options ) self._logger = logging.getLogger( __name__ ) self._solution_for_file = {} self._completer_per_solution = {} self._diagnostic_store = None self._max_diagnostics_to_display = user_options[ 'max_diagnostics_to_display' ] self._solution_state_lock = threading.Lock() if not os.path.isfile( PATH_TO_OMNISHARP_BINARY ): raise RuntimeError( SERVER_NOT_FOUND_MSG.format( PATH_TO_OMNISHARP_BINARY ) ) def Shutdown( self ): if self.user_options[ 'auto_stop_csharp_server' ]: for solutioncompleter in itervalues( self._completer_per_solution ): solutioncompleter._StopServer() def SupportedFiletypes( self ): """ Just csharp """ return [ 'cs' ] def _GetSolutionCompleter( self, request_data ): """ Get the solution completer or create a new one if it does not already exist. Use a lock to avoid creating the same solution completer multiple times.""" solution = self._GetSolutionFile( request_data[ "filepath" ] ) with self._solution_state_lock: if solution not in self._completer_per_solution: keep_logfiles = self.user_options[ 'server_keep_logfiles' ] desired_omnisharp_port = self.user_options.get( 'csharp_server_port' ) completer = CsharpSolutionCompleter( solution, keep_logfiles, desired_omnisharp_port ) self._completer_per_solution[ solution ] = completer return self._completer_per_solution[ solution ] def ShouldUseNowInner( self, request_data ): return True def CompletionType( self, request_data ): return ForceSemanticCompletion( request_data ) def ComputeCandidatesInner( self, request_data ): solutioncompleter = self._GetSolutionCompleter( request_data ) completion_type = self.CompletionType( request_data ) return [ responses.BuildCompletionData( completion[ 'CompletionText' ], completion[ 'DisplayText' ], completion[ 'Description' ], None, None, { "required_namespace_import" : completion[ 'RequiredNamespaceImport' ] } ) for completion in solutioncompleter._GetCompletions( request_data, completion_type ) ] def FilterAndSortCandidates( self, candidates, query ): result = super( CsharpCompleter, self ).FilterAndSortCandidates( candidates, query ) result.sort( key = _CompleteIsFromImport ) return result def GetSubcommandsMap( self ): return { 'StopServer' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_StopServer', no_request_data = True ) ), 'RestartServer' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_RestartServer', no_request_data = True ) ), 'ReloadSolution' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_ReloadSolution', no_request_data = True ) ), 'SolutionFile' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_SolutionFile', no_request_data = True ) ), 'GoToDefinition' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GoToDefinition' ) ), 'GoToDeclaration' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GoToDefinition' ) ), 'GoTo' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GoToImplementation', fallback_to_declaration = True ) ), 'GoToDefinitionElseDeclaration' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GoToDefinition' ) ), 'GoToImplementation' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GoToImplementation', fallback_to_declaration = False ) ), 'GoToImplementationElseDeclaration': ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GoToImplementation', fallback_to_declaration = True ) ), 'GetType' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GetType' ) ), 'FixIt' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_FixIt' ) ), 'GetDoc' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_GetDoc' ) ) } def _SolutionSubcommand( self, request_data, method, no_request_data = False, **kwargs ): solutioncompleter = self._GetSolutionCompleter( request_data ) if not no_request_data: kwargs[ 'request_data' ] = request_data return getattr( solutioncompleter, method )( **kwargs ) def OnFileReadyToParse( self, request_data ): solutioncompleter = self._GetSolutionCompleter( request_data ) # Only start the server associated to this solution if the option to # automatically start one is set and no server process is already running. if ( self.user_options[ 'auto_start_csharp_server' ] and not solutioncompleter._ServerIsRunning() ): solutioncompleter._StartServer() return # Bail out if the server is unresponsive. We don't start or restart the # server in this case because current one may still be warming up. if not solutioncompleter.ServerIsHealthy(): return errors = solutioncompleter.CodeCheck( request_data ) diagnostics = [ self._QuickFixToDiagnostic( request_data, x ) for x in errors[ "QuickFixes" ] ] self._diagnostic_store = DiagnosticsToDiagStructure( diagnostics ) return [ responses.BuildDiagnosticData( x ) for x in diagnostics[ : self._max_diagnostics_to_display ] ] def _QuickFixToDiagnostic( self, request_data, quick_fix ): filename = quick_fix[ "FileName" ] # NOTE: end of diagnostic range returned by the OmniSharp server is not # included. location = _BuildLocation( request_data, filename, quick_fix[ 'Line' ], quick_fix[ 'Column' ] ) location_end = _BuildLocation( request_data, filename, quick_fix[ 'EndLine' ], quick_fix[ 'EndColumn' ] ) if not location_end: location_end = location location_extent = responses.Range( location, location_end ) return responses.Diagnostic( list(), location, location_extent, quick_fix[ 'Text' ], quick_fix[ 'LogLevel' ].upper() ) def GetDetailedDiagnostic( self, request_data ): current_line = request_data[ 'line_num' ] current_column = request_data[ 'column_num' ] current_file = request_data[ 'filepath' ] if not self._diagnostic_store: raise ValueError( NO_DIAGNOSTIC_MESSAGE ) diagnostics = self._diagnostic_store[ current_file ][ current_line ] if not diagnostics: raise ValueError( NO_DIAGNOSTIC_MESSAGE ) closest_diagnostic = None distance_to_closest_diagnostic = 999 # FIXME: all of these calculations are currently working with byte # offsets, which are technically incorrect. We should be working with # codepoint offsets, as we want the nearest character-wise diagnostic for diagnostic in diagnostics: distance = abs( current_column - diagnostic.location_.column_number_ ) if distance < distance_to_closest_diagnostic: distance_to_closest_diagnostic = distance closest_diagnostic = diagnostic return responses.BuildDisplayMessageResponse( closest_diagnostic.text_ ) def DebugInfo( self, request_data ): try: completer = self._GetSolutionCompleter( request_data ) except RuntimeError: return ( 'C# completer debug information:\n' ' OmniSharp not running\n' ' OmniSharp executable: {0}\n' ' OmniSharp solution: not found'.format( PATH_TO_OMNISHARP_BINARY ) ) with completer._server_state_lock: if completer._ServerIsRunning(): return ( 'C# completer debug information:\n' ' OmniSharp running at: {0}\n' ' OmniSharp process ID: {1}\n' ' OmniSharp executable: {2}\n' ' OmniSharp logfiles:\n' ' {3}\n' ' {4}\n' ' OmniSharp solution: {5}'.format( completer._ServerLocation(), completer._omnisharp_phandle.pid, PATH_TO_OMNISHARP_BINARY, completer._filename_stdout, completer._filename_stderr, completer._solution_path ) ) if completer._filename_stdout and completer._filename_stderr: return ( 'C# completer debug information:\n' ' OmniSharp no longer running\n' ' OmniSharp executable: {0}\n' ' OmniSharp logfiles:\n' ' {1}\n' ' {2}\n' ' OmniSharp solution: {3}'.format( PATH_TO_OMNISHARP_BINARY, completer._filename_stdout, completer._filename_stderr, completer._solution_path ) ) return ( 'C# completer debug information:\n' ' OmniSharp is not running\n' ' OmniSharp executable: {0}\n' ' OmniSharp solution: {1}'.format( PATH_TO_OMNISHARP_BINARY, completer._solution_path ) ) def ServerIsHealthy( self ): """ Check if our OmniSharp server is healthy (up and serving). """ return self._CheckAllRunning( lambda i: i.ServerIsHealthy() ) def ServerIsReady( self ): """ Check if our OmniSharp server is ready (loaded solution file).""" return self._CheckAllRunning( lambda i: i.ServerIsReady() ) def _CheckAllRunning( self, action ): solutioncompleters = itervalues( self._completer_per_solution ) return all( action( completer ) for completer in solutioncompleters if completer._ServerIsRunning() ) def _GetSolutionFile( self, filepath ): if filepath not in self._solution_for_file: # NOTE: detection could throw an exception if an extra_conf_store needs # to be confirmed path_to_solutionfile = solutiondetection.FindSolutionPath( filepath ) if not path_to_solutionfile: raise RuntimeError( 'Autodetection of solution file failed.' ) self._solution_for_file[ filepath ] = path_to_solutionfile return self._solution_for_file[ filepath ] class CsharpSolutionCompleter( object ): def __init__( self, solution_path, keep_logfiles, desired_omnisharp_port ): self._logger = logging.getLogger( __name__ ) self._solution_path = solution_path self._keep_logfiles = keep_logfiles self._filename_stderr = None self._filename_stdout = None self._omnisharp_port = None self._omnisharp_phandle = None self._desired_omnisharp_port = desired_omnisharp_port self._server_state_lock = threading.RLock() def CodeCheck( self, request_data ): filename = request_data[ 'filepath' ] if not filename: raise ValueError( INVALID_FILE_MESSAGE ) return self._GetResponse( '/codecheck', self._DefaultParameters( request_data ) ) def _StartServer( self ): """ Start the OmniSharp server if not already running. Use a lock to avoid starting the server multiple times for the same solution. """ with self._server_state_lock: if self._ServerIsRunning(): return self._logger.info( 'Starting OmniSharp server' ) path_to_solutionfile = self._solution_path self._logger.info( u'Loading solution file {0}'.format( path_to_solutionfile ) ) self._ChooseOmnisharpPort() command = [ PATH_TO_OMNISHARP_BINARY, '-p', str( self._omnisharp_port ), '-s', u'{0}'.format( path_to_solutionfile ) ] if not utils.OnWindows() and not utils.OnCygwin(): command.insert( 0, 'mono' ) if utils.OnCygwin(): command.extend( [ '--client-path-mode', 'Cygwin' ] ) solutionfile = os.path.basename( path_to_solutionfile ) self._filename_stdout = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._omnisharp_port, sln = solutionfile, std = 'stdout' ) ) self._filename_stderr = utils.CreateLogfile( LOGFILE_FORMAT.format( port = self._omnisharp_port, sln = solutionfile, std = 'stderr' ) ) with utils.OpenForStdHandle( self._filename_stderr ) as fstderr: with utils.OpenForStdHandle( self._filename_stdout ) as fstdout: self._omnisharp_phandle = utils.SafePopen( command, stdout = fstdout, stderr = fstderr ) self._solution_path = path_to_solutionfile def _StopServer( self ): """ Stop the OmniSharp server using a lock. """ with self._server_state_lock: if self._ServerIsRunning(): self._logger.info( 'Stopping OmniSharp server with PID {0}'.format( self._omnisharp_phandle.pid ) ) self._GetResponse( '/stopserver' ) try: utils.WaitUntilProcessIsTerminated( self._omnisharp_phandle, timeout = 5 ) self._logger.info( 'OmniSharp server stopped' ) except RuntimeError: self._logger.exception( 'Error while stopping OmniSharp server' ) self._CleanUp() def _CleanUp( self ): self._omnisharp_port = None self._omnisharp_phandle = None if not self._keep_logfiles: if self._filename_stdout: utils.RemoveIfExists( self._filename_stdout ) self._filename_stdout = None if self._filename_stderr: utils.RemoveIfExists( self._filename_stderr ) self._filename_stderr = None def _RestartServer( self ): """ Restarts the OmniSharp server using a lock. """ with self._server_state_lock: self._StopServer() self._StartServer() def _ReloadSolution( self ): """ Reloads the solutions in the OmniSharp server """ self._logger.info( 'Reloading Solution in OmniSharp server' ) return self._GetResponse( '/reloadsolution' ) def CompletionType( self, request_data ): return ForceSemanticCompletion( request_data ) def _GetCompletions( self, request_data, completion_type ): """ Ask server for completions """ parameters = self._DefaultParameters( request_data ) parameters[ 'WantImportableTypes' ] = completion_type parameters[ 'ForceSemanticCompletion' ] = completion_type parameters[ 'WantDocumentationForEveryCompletionResult' ] = True completions = self._GetResponse( '/autocomplete', parameters ) return completions if completions is not None else [] def _GoToDefinition( self, request_data ): """ Jump to definition of identifier under cursor """ definition = self._GetResponse( '/gotodefinition', self._DefaultParameters( request_data ) ) if definition[ 'FileName' ] is not None: return responses.BuildGoToResponseFromLocation( _BuildLocation( request_data, definition[ 'FileName' ], definition[ 'Line' ], definition[ 'Column' ] ) ) else: raise RuntimeError( 'Can\'t jump to definition' ) def _GoToImplementation( self, request_data, fallback_to_declaration ): """ Jump to implementation of identifier under cursor """ implementation = self._GetResponse( '/findimplementations', self._DefaultParameters( request_data ) ) if implementation[ 'QuickFixes' ]: if len( implementation[ 'QuickFixes' ] ) == 1: return responses.BuildGoToResponseFromLocation( _BuildLocation( request_data, implementation[ 'QuickFixes' ][ 0 ][ 'FileName' ], implementation[ 'QuickFixes' ][ 0 ][ 'Line' ], implementation[ 'QuickFixes' ][ 0 ][ 'Column' ] ) ) else: return [ responses.BuildGoToResponseFromLocation( _BuildLocation( request_data, x[ 'FileName' ], x[ 'Line' ], x[ 'Column' ] ) ) for x in implementation[ 'QuickFixes' ] ] else: if ( fallback_to_declaration ): return self._GoToDefinition( request_data ) elif implementation[ 'QuickFixes' ] is None: raise RuntimeError( 'Can\'t jump to implementation' ) else: raise RuntimeError( 'No implementations found' ) def _GetType( self, request_data ): request = self._DefaultParameters( request_data ) request[ "IncludeDocumentation" ] = False result = self._GetResponse( '/typelookup', request ) message = result[ "Type" ] return responses.BuildDisplayMessageResponse( message ) def _FixIt( self, request_data ): request = self._DefaultParameters( request_data ) result = self._GetResponse( '/fixcodeissue', request ) replacement_text = result[ "Text" ] # Note: column_num is already a byte offset so we don't need to use # _BuildLocation. location = responses.Location( request_data[ 'line_num' ], request_data[ 'column_num' ], request_data[ 'filepath' ] ) fixits = [ responses.FixIt( location, _BuildChunks( request_data, replacement_text ) ) ] return responses.BuildFixItResponse( fixits ) def _GetDoc( self, request_data ): request = self._DefaultParameters( request_data ) request[ "IncludeDocumentation" ] = True result = self._GetResponse( '/typelookup', request ) message = result[ "Type" ] if ( result[ "Documentation" ] ): message += "\n" + result[ "Documentation" ] return responses.BuildDetailedInfoResponse( message ) def _DefaultParameters( self, request_data ): """ Some very common request parameters """ parameters = {} parameters[ 'line' ] = request_data[ 'line_num' ] parameters[ 'column' ] = request_data[ 'column_codepoint' ] filepath = request_data[ 'filepath' ] parameters[ 'buffer' ] = ( request_data[ 'file_data' ][ filepath ][ 'contents' ] ) parameters[ 'filename' ] = filepath return parameters def _ServerIsRunning( self ): """ Check if our OmniSharp server is running (process is up).""" return utils.ProcessIsRunning( self._omnisharp_phandle ) def ServerIsHealthy( self ): """ Check if our OmniSharp server is healthy (up and serving).""" if not self._ServerIsRunning(): return False try: return self._GetResponse( '/checkalivestatus', timeout = .2 ) except Exception: return False def ServerIsReady( self ): """ Check if our OmniSharp server is ready (loaded solution file).""" if not self._ServerIsRunning(): return False try: return self._GetResponse( '/checkreadystatus', timeout = .2 ) except Exception: return False def _SolutionFile( self ): """ Find out which solution file server was started with """ return self._solution_path def _ServerLocation( self ): # We cannot use 127.0.0.1 like we do in other places because OmniSharp # server only listens on localhost. return 'http://localhost:' + str( self._omnisharp_port ) def _GetResponse( self, handler, parameters = {}, timeout = None ): """ Handle communication with server """ target = urllib.parse.urljoin( self._ServerLocation(), handler ) response = requests.post( target, data = parameters, timeout = timeout ) return response.json() def _ChooseOmnisharpPort( self ): if not self._omnisharp_port: if self._desired_omnisharp_port: self._omnisharp_port = int( self._desired_omnisharp_port ) else: self._omnisharp_port = utils.GetUnusedLocalhostPort() self._logger.info( u'using port {0}'.format( self._omnisharp_port ) ) def _CompleteIsFromImport( candidate ): try: return candidate[ "extra_data" ][ "required_namespace_import" ] is not None except ( KeyError, TypeError ): return False def DiagnosticsToDiagStructure( diagnostics ): structure = defaultdict( lambda : defaultdict( list ) ) for diagnostic in diagnostics: structure[ diagnostic.location_.filename_ ][ diagnostic.location_.line_number_ ].append( diagnostic ) return structure def _BuildChunks( request_data, new_buffer ): filepath = request_data[ 'filepath' ] old_buffer = request_data[ 'file_data' ][ filepath ][ 'contents' ] new_buffer = _FixLineEndings( old_buffer, new_buffer ) new_length = len( new_buffer ) old_length = len( old_buffer ) if new_length == old_length and new_buffer == old_buffer: return [] min_length = min( new_length, old_length ) start_index = 0 end_index = min_length for i in range( 0, min_length - 1 ): if new_buffer[ i ] != old_buffer[ i ]: start_index = i break for i in range( 1, min_length ): if new_buffer[ new_length - i ] != old_buffer[ old_length - i ]: end_index = i - 1 break # To handle duplicates, i.e aba => a if ( start_index + end_index > min_length ): start_index -= start_index + end_index - min_length replacement_text = new_buffer[ start_index : new_length - end_index ] ( start_line, start_column ) = _IndexToLineColumn( old_buffer, start_index ) ( end_line, end_column ) = _IndexToLineColumn( old_buffer, old_length - end_index ) # No need for _BuildLocation, because _IndexToLineColumn already converted # start_column and end_column to byte offsets for us. start = responses.Location( start_line, start_column, filepath ) end = responses.Location( end_line, end_column, filepath ) return [ responses.FixItChunk( replacement_text, responses.Range( start, end ) ) ] def _FixLineEndings( old_buffer, new_buffer ): new_windows = "\r\n" in new_buffer old_windows = "\r\n" in old_buffer if new_windows != old_windows: if new_windows: new_buffer = new_buffer.replace( "\r\n", "\n" ) new_buffer = new_buffer.replace( "\r", "\n" ) else: new_buffer = re.sub( "\r(?!\n)|(? index: return ( linenum + 1, CodepointOffsetToByteOffset( line, index - curr_pos + 1 ) ) curr_pos += len( line ) assert False def _BuildLocation( request_data, filename, line_num, column_num ): if line_num <= 0 or column_num <= 0: return None contents = utils.SplitLines( GetFileContents( request_data, filename ) ) line_value = contents[ line_num - 1 ] return responses.Location( line_num, CodepointOffsetToByteOffset( line_value, column_num ), filename ) ycmd-0+20161219+git486b809.orig/ycmd/completers/objc/0000755000175000017500000000000013026170313020205 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/completers/objc/hook.py0000644000175000017500000000217513026170313021524 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import ycm_core from ycmd.completers.cpp.clang_completer import ClangCompleter def GetCompleter( user_options ): if ycm_core.HasClangSupport(): return ClangCompleter( user_options ) else: return None ycmd-0+20161219+git486b809.orig/ycmd/responses.py0000644000175000017500000001655613026170313017523 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os YCM_EXTRA_CONF_FILENAME = '.ycm_extra_conf.py' CONFIRM_CONF_FILE_MESSAGE = ('Found {0}. Load? \n\n(Question can be turned ' 'off with options, see YCM docs)') 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 ' 'DOCS *NOW*, DON\'T file a bug report.' ).format( YCM_EXTRA_CONF_FILENAME ) NO_DIAGNOSTIC_SUPPORT_MESSAGE = ( 'YCM has no diagnostics support for this ' 'filetype; refer to Syntastic docs if using Syntastic.') class ServerError( Exception ): def __init__( self, message ): super( ServerError, self ).__init__( message ) class UnknownExtraConf( ServerError ): def __init__( self, extra_conf_file ): message = CONFIRM_CONF_FILE_MESSAGE.format( extra_conf_file ) super( UnknownExtraConf, self ).__init__( message ) self.extra_conf_file = extra_conf_file class NoExtraConfDetected( ServerError ): def __init__( self ): super( NoExtraConfDetected, self ).__init__( NO_EXTRA_CONF_FILENAME_MESSAGE ) class NoDiagnosticSupport( ServerError ): def __init__( self ): super( NoDiagnosticSupport, self ).__init__( NO_DIAGNOSTIC_SUPPORT_MESSAGE ) # column_num is a byte offset def BuildGoToResponse( filepath, line_num, column_num, description = None ): return BuildGoToResponseFromLocation( Location( line = line_num, column = column_num, filename = filepath ), description ) def BuildGoToResponseFromLocation( location, description = None ): """Build a GoTo response from a responses.Location object.""" response = BuildLocationData( location ) if description: response[ 'description' ] = description return response def BuildDescriptionOnlyGoToResponse( text ): return { 'description': text, } def BuildDisplayMessageResponse( text ): return { 'message': text } def BuildDetailedInfoResponse( text ): """ Retuns the response object for displaying detailed information about types and usage, suach as within a preview window""" return { 'detailed_info': text } def BuildCompletionData( insertion_text, extra_menu_info = None, detailed_info = None, menu_text = None, kind = None, extra_data = None ): completion_data = { 'insertion_text': insertion_text } if extra_menu_info: completion_data[ 'extra_menu_info' ] = extra_menu_info if menu_text: completion_data[ 'menu_text' ] = menu_text if detailed_info: completion_data[ 'detailed_info' ] = detailed_info if kind: completion_data[ 'kind' ] = kind if extra_data: completion_data[ 'extra_data' ] = extra_data return completion_data # start_column is a byte offset def BuildCompletionResponse( completion_datas, start_column, errors=None ): return { 'completions': completion_datas, 'completion_start_column': start_column, 'errors': errors if errors else [], } # location.column_number_ is a byte offset def BuildLocationData( location ): return { 'line_num': location.line_number_, 'column_num': location.column_number_, 'filepath': location.filename_, } def BuildRangeData( source_range ): return { 'start': BuildLocationData( source_range.start_ ), 'end': BuildLocationData( source_range.end_ ), } class Diagnostic( object ): def __init__ ( self, ranges, location, location_extent, text, kind ): self.ranges_ = ranges self.location_ = location self.location_extent_ = location_extent self.text_ = text self.kind_ = kind class FixIt( object ): """A set of replacements (of type FixItChunk) to be applied to fix a single diagnostic. This can be used for any type of refactoring command, not just quick fixes. The individual chunks may span multiple files. NOTE: All offsets supplied in both |location| and (the members of) |chunks| must be byte offsets into the UTF-8 encoded version of the appropriate buffer. """ def __init__ ( self, location, chunks, text = '' ): """location of type Location, chunks of type list""" self.location = location self.chunks = chunks self.text = text class FixItChunk( object ): """An individual replacement within a FixIt (aka Refactor)""" def __init__ ( self, replacement_text, range ): """replacement_text of type string, range of type Range""" self.replacement_text = replacement_text self.range = range class Range( object ): """Source code range relating to a diagnostic or FixIt (aka Refactor).""" def __init__ ( self, start, end ): "start of type Location, end of type Location""" self.start_ = start self.end_ = end class Location( object ): """Source code location for a diagnostic or FixIt (aka Refactor).""" def __init__ ( self, line, column, filename ): """Line is 1-based line, column is 1-based column byte offset, filename is absolute path of the file""" self.line_number_ = line self.column_number_ = column self.filename_ = os.path.realpath( filename ) def BuildDiagnosticData( diagnostic ): kind = ( diagnostic.kind_.name if hasattr( diagnostic.kind_, 'name' ) else diagnostic.kind_ ) fixits = ( diagnostic.fixits_ if hasattr( diagnostic, 'fixits_' ) else [] ) return { 'ranges': [ BuildRangeData( x ) for x in diagnostic.ranges_ ], 'location': BuildLocationData( diagnostic.location_ ), 'location_extent': BuildRangeData( diagnostic.location_extent_ ), 'text': diagnostic.text_, 'kind': kind, 'fixit_available': len( fixits ) > 0, } def BuildFixItResponse( fixits ): """Build a response from a list of FixIt (aka Refactor) objects. This response can be used to apply arbitrary changes to arbitrary files and is suitable for both quick fix and refactor operations""" def BuildFixitChunkData( chunk ): return { 'replacement_text': chunk.replacement_text, 'range': BuildRangeData( chunk.range ), } def BuildFixItData( fixit ): return { 'location': BuildLocationData( fixit.location ), 'chunks' : [ BuildFixitChunkData( x ) for x in fixit.chunks ], 'text': fixit.text, } return { 'fixits' : [ BuildFixItData( x ) for x in fixits ] } def BuildExceptionResponse( exception, traceback ): return { 'exception': exception, 'message': str( exception ), 'traceback': traceback } ycmd-0+20161219+git486b809.orig/ycmd/tests/0000755000175000017500000000000013026170313016255 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/0000755000175000017500000000000013026170313020423 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/0000755000175000017500000000000013026170313022234 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/trivial2.js0000644000175000017500000000000313026170313024317 0ustar onuronurX. ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/.tern-project0000644000175000017500000000032313026170313024647 0ustar onuronur{ "libs": [ "browser", "jquery" ], "loadEagerly": [ "file1.js", "file2.js", "file3.js" ], "plugins": { "requirejs": { "baseURL": "./", "paths": {} } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/file2.js0000644000175000017500000000003113026170313023565 0ustar onuronur console.log( global ); ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/unicode.js0000644000175000017500000000022013026170313024212 0ustar onuronurvar x = 't'.cha var y = '†'.cha var x = 't'.cha var øbjecø = { /* unicøde comment */ 'ålpha': '∫eta' }; øbjecø.a øbjecø.ålpha ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/lamelib/0000755000175000017500000000000013026170313023641 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/lamelib/lame_widget.js0000644000175000017500000000051013026170313026454 0ustar onuronurdefine( ['lamelib/lame_widget'], function( lame_widget ) { return { options: { 'test': 200 }, /** * This is a short documentation string */ a_function: function( bar ) { return { a_value: 'baz' }; } }; } ); ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/file1.js0000644000175000017500000000006713026170313023575 0ustar onuronurvar global = 'this is a test' console.log( global ); ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/trivial.js0000644000175000017500000000005313026170313024242 0ustar onuronurvar X = { y: 'string', z: 'integer' }; ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/requirejs_test.js0000644000175000017500000000064613026170313025650 0ustar onuronurrequire( [ 'coollib/cool_object' ], function ( cool_object ) { cool_object. cool_object.min cool_object.gn } ); require( [ 'lamelib/lame_widget' ], function ( lame_widget ) { lame_widget. lame_widget.options. } ); require( [ 'coollib/cool_widget' ], function ( cool_widget ) { cool_widget.options. cool_widget. } ); require( 'no_such_lib/no_such_file', function( whatsit ) { whatsit. whatsit.ben } ); ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/coollib/0000755000175000017500000000000013026170313023657 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/coollib/cool_widget.js0000644000175000017500000000054313026170313026516 0ustar onuronurdefine( ['lamelib/lame_widget'], function( lame_widget ) { $.widget( 'cool_widget', { options: { 'secret_test': 100 }, _create: function() { this.a_number = 20; }, b_function: function( bar ) { return { b_value: 'biz' }; } } ); } ); ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/coollib/cool_object.js0000644000175000017500000000104613026170313026500 0ustar onuronurdefine( [], function() { return { /** * This function takes a number and invests it in bitcoin. It returns * the expected value (in notional currency) after 1 year. */ mine_bitcoin: function( how_much ) { return how_much * 0.001; }, get_number: 10, get_string: 'string', get_thing: function( a ) { if ( a ) { return this.get_number; } else { return this.get_string; } } }; } ); ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/simple_test.modified.js0000644000175000017500000000072313026170313026703 0ustar onuronur var simple_test_obect = { 'a_simple_function': function( param ) { return 'yes'; }, 'basic_type': 100, 'object': { 'basic_type': 'test_string' } }; var simple_assignment = simple_test_obect. var query_assignment = simple_test_obect.typ var query_assignment = simple_test_obect.asf function blah( simple_test_obect ) { simple_test_obect.a_simple_function; } blah( simple_test_obect ); simple_test_obect = null; ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/file4.js0000644000175000017500000000042113026170313023572 0ustar onuronur// This file contains a usage of the global value 'global', but it does *not* // appear in .tern-project's 'loadEagerly'. This means that it does not get // renamed when we run the rename command. window.eval( 'xyz' + global ); // Though it does if we tell tern about it. ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/simple_test.js0000644000175000017500000000066513026170313025131 0ustar onuronurvar simple_test_obect = { 'a_simple_function': function( param ) { return 'yes'; }, 'basic_type': 100, 'object': { 'basic_type': 'test_string' } }; var simple_assignment = simple_test_obect. var query_assignment = simple_test_obect.typ var query_assignment = simple_test_obect.asf function blah( simple_test_obect ) { simple_test_obect.a_simple_function; } blah( simple_test_obect ); simple_test_obect = null; ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/testdata/file3.js0000644000175000017500000000005613026170313023575 0ustar onuronur function method( xyz ) { return global } ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/get_completions_test.py0000644000175000017500000003643213026170313025237 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import print_function from __future__ import absolute_import from __future__ import unicode_literals from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, contains, contains_inanyorder, empty, has_entries ) from nose.tools import eq_ from pprint import pformat import requests from ycmd.tests.javascript import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, CompletionEntryMatcher from ycmd.utils import ReadFile # The following properties/methods are in Object.prototype, so are present # on all objects: # # toString() # toLocaleString() # valueOf() # hasOwnProperty() # propertyIsEnumerable() # isPrototypeOf() def _CombineRequest( request, data ): return BuildRequest( **_Merge( request, data ) ) def _Merge( request, data ): kw = dict( request ) kw.update( data ) return kw def RunTest( app, test ): """ Method to run a simple completion test and verify the result test is a dictionary containing: 'request': kwargs for BuildRequest 'expect': { 'response': server response code (e.g. httplib.OK) 'data': matcher for the server response json } """ contents = ReadFile( test[ 'request' ][ 'filepath' ] ) app.post_json( '/event_notification', _CombineRequest( test[ 'request' ], { 'event_name': 'FileReadyToParse', 'contents': contents, } ), expect_errors = True ) # We ignore errors here and we check the response code ourself. # This is to allow testing of requests returning errors. response = app.post_json( '/completions', _CombineRequest( test[ 'request' ], { 'contents': contents } ), expect_errors = True ) print( 'completer response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, test[ 'expect' ][ 'response' ] ) assert_that( response.json, test[ 'expect' ][ 'data' ] ) @SharedYcmd def GetCompletions_NoQuery_test( app ): RunTest( app, { 'description': 'semantic completion works for simple object no query', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'simple_test.js' ), 'line_num' : 13, 'column_num': 43, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'a_simple_function', 'fn(param: ?) -> string' ), CompletionEntryMatcher( 'basic_type', 'number' ), CompletionEntryMatcher( 'object', 'object' ), CompletionEntryMatcher( 'toString', 'fn() -> string' ), CompletionEntryMatcher( 'toLocaleString', 'fn() -> string' ), CompletionEntryMatcher( 'valueOf', 'fn() -> number' ), CompletionEntryMatcher( 'hasOwnProperty', 'fn(prop: string) -> bool' ), CompletionEntryMatcher( 'isPrototypeOf', 'fn(obj: ?) -> bool' ), CompletionEntryMatcher( 'propertyIsEnumerable', 'fn(prop: string) -> bool' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Query_test( app ): RunTest( app, { 'description': 'semantic completion works for simple object with query', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'simple_test.js' ), 'line_num' : 14, 'column_num': 45, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'basic_type', 'number' ), CompletionEntryMatcher( 'isPrototypeOf', 'fn(obj: ?) -> bool' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Require_NoQuery_test( app ): RunTest( app, { 'description': 'semantic completion works for simple object no query', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'requirejs_test.js' ), 'line_num' : 2, 'column_num': 15, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'mine_bitcoin', 'fn(how_much: ?) -> number' ), CompletionEntryMatcher( 'get_number', 'number' ), CompletionEntryMatcher( 'get_string', 'string' ), CompletionEntryMatcher( 'get_thing', 'fn(a: ?) -> number|string' ), CompletionEntryMatcher( 'toString', 'fn() -> string' ), CompletionEntryMatcher( 'toLocaleString', 'fn() -> string' ), CompletionEntryMatcher( 'valueOf', 'fn() -> number' ), CompletionEntryMatcher( 'hasOwnProperty', 'fn(prop: string) -> bool' ), CompletionEntryMatcher( 'isPrototypeOf', 'fn(obj: ?) -> bool' ), CompletionEntryMatcher( 'propertyIsEnumerable', 'fn(prop: string) -> bool' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Require_Query_test( app ): RunTest( app, { 'description': 'semantic completion works for require object with query', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'requirejs_test.js' ), 'line_num' : 3, 'column_num': 17, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'mine_bitcoin', 'fn(how_much: ?) -> number' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Require_Query_LCS_test( app ): RunTest( app, { 'description': ( 'completion works for require object ' 'with query not prefix' ), 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'requirejs_test.js' ), 'line_num' : 4, 'column_num': 17, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'get_number', 'number' ), CompletionEntryMatcher( 'get_thing', 'fn(a: ?) -> number|string' ), CompletionEntryMatcher( 'get_string', 'string' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_DirtyNamedBuffers_test( app ): # This tests that when we have dirty buffers in our editor, tern actually # uses them correctly RunTest( app, { 'description': ( 'completion works for require object ' 'with query not prefix' ), 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'requirejs_test.js' ), 'line_num' : 18, 'column_num': 11, 'file_data': { PathToTestFile( 'no_such_lib', 'no_such_file.js' ): { 'contents': ( 'define( [], function() { return { big_endian_node: 1 } } )' ), 'filetypes': [ 'javascript' ] } }, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'big_endian_node', 'number' ), CompletionEntryMatcher( 'toString', 'fn() -> string' ), CompletionEntryMatcher( 'toLocaleString', 'fn() -> string' ), CompletionEntryMatcher( 'valueOf', 'fn() -> number' ), CompletionEntryMatcher( 'hasOwnProperty', 'fn(prop: string) -> bool' ), CompletionEntryMatcher( 'isPrototypeOf', 'fn(obj: ?) -> bool' ), CompletionEntryMatcher( 'propertyIsEnumerable', 'fn(prop: string) -> bool' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_ReturnsDocsInCompletions_test( app ): # This tests that we supply docs for completions RunTest( app, { 'description': 'completions supply docs', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'requirejs_test.js' ), 'line_num' : 8, 'column_num': 15, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'a_function', 'fn(bar: ?) -> {a_value: string}', { 'detailed_info': ( 'fn(bar: ?) -> {a_value: string}\n' 'This is a short documentation string'), } ), CompletionEntryMatcher( 'options', 'options' ), CompletionEntryMatcher( 'toString', 'fn() -> string' ), CompletionEntryMatcher( 'toLocaleString', 'fn() -> string' ), CompletionEntryMatcher( 'valueOf', 'fn() -> number' ), CompletionEntryMatcher( 'hasOwnProperty', 'fn(prop: string) -> bool' ), CompletionEntryMatcher( 'isPrototypeOf', 'fn(obj: ?) -> bool' ), CompletionEntryMatcher( 'propertyIsEnumerable', 'fn(prop: string) -> bool' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_IgoreNonJSFiles_test( app ): trivial1 = { 'filetypes': [ 'python' ], 'contents': ReadFile( PathToTestFile( 'trivial.js' ) ), } trivial2 = { 'filetypes': [ 'javascript' ], 'contents': ReadFile( PathToTestFile( 'trivial2.js' ) ), } request = { 'line_num': 1, 'column_num': 3, 'file_data': { PathToTestFile( 'trivial.js' ): trivial1, PathToTestFile( 'trivial2.js' ): trivial2, }, } app.post_json( '/event_notification', _Merge( request, { 'filepath': PathToTestFile( 'trivial2.js' ), 'event_name': 'FileReadyToParse', } ) ) response = app.post_json( '/completions', _Merge( request, { 'filepath': PathToTestFile( 'trivial2.js' ), } ) ).json print( 'completer response: {0}'.format( pformat( response, indent=2 ) ) ) assert_that( response, has_entries( { 'completion_start_column': 3, # Note: we do *not* see X.y and X.z because tern is not told about # the trivial.js file because we pretended it was Python 'completions': empty(), 'errors': empty(), } ) ) @SharedYcmd def GetCompletions_IncludeMultiFileType_test( app ): trivial1 = { 'filetypes': [ 'python', 'javascript' ], 'contents': ReadFile( PathToTestFile( 'trivial.js' ) ), } trivial2 = { 'filetypes': [ 'javascript' ], 'contents': ReadFile( PathToTestFile( 'trivial2.js' ) ), } request = { 'line_num': 1, 'column_num': 3, 'file_data': { PathToTestFile( 'trivial.js' ): trivial1, PathToTestFile( 'trivial2.js' ): trivial2, }, } app.post_json( '/event_notification', _Merge( request, { 'filepath': PathToTestFile( 'trivial2.js' ), 'event_name': 'FileReadyToParse', } ) ) response = app.post_json( '/completions', _Merge( request, { 'filepath': PathToTestFile( 'trivial2.js' ), # We must force the use of semantic engine because the previous test would # have entered 'empty' results into the completion cache. 'force_semantic': True, } ) ).json print( 'completer response: {0}'.format( pformat( response, indent=2 ) ) ) assert_that( response, has_entries( { 'completion_start_column': 3, # Note: This time, we *do* see the completions, becuase one of the 2 # filetypes for trivial.js is javascript. 'completions': contains_inanyorder( CompletionEntryMatcher( 'y', 'string' ), CompletionEntryMatcher( 'z', 'string' ), CompletionEntryMatcher( 'toString', 'fn() -> string' ), CompletionEntryMatcher( 'toLocaleString', 'fn() -> string' ), CompletionEntryMatcher( 'valueOf', 'fn() -> number' ), CompletionEntryMatcher( 'hasOwnProperty', 'fn(prop: string) -> bool' ), CompletionEntryMatcher( 'isPrototypeOf', 'fn(obj: ?) -> bool' ), CompletionEntryMatcher( 'propertyIsEnumerable', 'fn(prop: string) -> bool' ), ), 'errors': empty(), } ) ) @SharedYcmd def GetCompletions_Unicode_AfterLine_test( app ): RunTest( app, { 'description': 'completions work with unicode chars in the file', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'unicode.js' ), 'line_num' : 1, 'column_num': 16, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'charAt', 'fn(i: number) -> string' ), CompletionEntryMatcher( 'charCodeAt', 'fn(i: number) -> number' ), ), 'completion_start_column': 13, 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Unicode_InLine_test( app ): RunTest( app, { 'description': 'completions work with unicode chars in the file', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'unicode.js' ), 'line_num' : 2, 'column_num': 18, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'charAt', 'fn(i: number) -> string' ), CompletionEntryMatcher( 'charCodeAt', 'fn(i: number) -> number' ), ), 'completion_start_column': 15, 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Unicode_InFile_test( app ): RunTest( app, { 'description': 'completions work with unicode chars in the file', 'request': { 'filetype' : 'javascript', 'filepath' : PathToTestFile( 'unicode.js' ), 'line_num' : 3, 'column_num': 16, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'charAt', 'fn(i: number) -> string' ), CompletionEntryMatcher( 'charCodeAt', 'fn(i: number) -> number' ), ), 'completion_start_column': 13, 'errors': empty(), } ) }, } ) ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/__init__.py0000644000175000017500000000673513026170313022547 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd import handlers from ycmd.tests.test_utils import ( ClearCompletionsCache, CurrentWorkingDirectory, SetUpApp, StopCompleterServer, WaitUntilCompleterServerReady ) from ycmd.utils import GetCurrentDirectory shared_app = None shared_current_dir = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app, shared_current_dir shared_app = SetUpApp() shared_current_dir = GetCurrentDirectory() os.chdir( PathToTestFile() ) WaitUntilCompleterServerReady( shared_app, 'javascript' ) def tearDownPackage(): """Cleans up the tests using the SharedYcmd decorator in this package. It is executed once after running all the tests in the package.""" global shared_app, shared_current_dir StopCompleterServer( shared_app, 'javascript' ) os.chdir( shared_current_dir ) def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state app = SetUpApp() try: with CurrentWorkingDirectory( PathToTestFile() ): test( app, *args, **kwargs ) finally: StopCompleterServer( app, 'javascript' ) handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/event_notification_test.py0000644000175000017500000001464313026170313025733 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import print_function from __future__ import absolute_import from __future__ import unicode_literals from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, empty from mock import patch from nose.tools import eq_ from pprint import pformat import requests import os from ycmd.tests.test_utils import ( BuildRequest, ErrorMatcher, WaitUntilCompleterServerReady ) from ycmd.tests.javascript import IsolatedYcmd, PathToTestFile from ycmd.utils import GetCurrentDirectory, ReadFile @IsolatedYcmd def EventNotification_OnFileReadyToParse_ProjectFile_cwd_test( app ): WaitUntilCompleterServerReady( app, 'javascript' ) contents = ReadFile( PathToTestFile( 'simple_test.js' ) ) response = app.post_json( '/event_notification', BuildRequest( event_name = 'FileReadyToParse', contents = contents, filetype = 'javascript' ), expect_errors = True) eq_( response.status_code, requests.codes.ok ) assert_that( response.json, empty() ) @IsolatedYcmd def EventNotification_OnFileReadyToParse_ProjectFile_parentdir_test( app ): WaitUntilCompleterServerReady( app, 'javascript' ) os.chdir( PathToTestFile( 'lamelib' ) ) contents = ReadFile( PathToTestFile( 'simple_test.js' ) ) response = app.post_json( '/event_notification', BuildRequest( event_name = 'FileReadyToParse', contents = contents, filetype = 'javascript' ), expect_errors = True) eq_( response.status_code, requests.codes.ok ) assert_that( response.json, empty() ) @IsolatedYcmd @patch( 'ycmd.completers.javascript.tern_completer.GlobalConfigExists', return_value = False ) def EventNotification_OnFileReadyToParse_NoProjectFile_test( app, *args ): WaitUntilCompleterServerReady( app, 'javascript' ) # We raise an error if we can't detect a .tern-project file. # We only do this on the first OnFileReadyToParse event after a # server startup. os.chdir( PathToTestFile( '..' ) ) contents = ReadFile( PathToTestFile( 'simple_test.js' ) ) response = app.post_json( '/event_notification', BuildRequest( event_name = 'FileReadyToParse', contents = contents, filetype = 'javascript' ), expect_errors = True ) print( 'event response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( RuntimeError, 'Warning: Unable to detect a .tern-project file ' 'in the hierarchy before ' + GetCurrentDirectory() + ' and no global .tern-config file was found. ' 'This is required for accurate JavaScript ' 'completion. Please see the User Guide for ' 'details.' ) ) # Check that a subsequent call does *not* raise the error response = app.post_json( '/event_notification', BuildRequest( event_name = 'FileReadyToParse', contents = contents, filetype = 'javascript' ), expect_errors = True ) print( 'event response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, requests.codes.ok ) assert_that( response.json, empty() ) # Restart the server and check that it raises it again app.post_json( '/run_completer_command', BuildRequest( command_arguments = [ 'RestartServer' ], filetype = 'javascript', contents = contents, completer_target = 'filetype_default' ) ) WaitUntilCompleterServerReady( app, 'javascript' ) response = app.post_json( '/event_notification', BuildRequest( event_name = 'FileReadyToParse', contents = contents, filetype = 'javascript' ), expect_errors = True ) print( 'event response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( RuntimeError, 'Warning: Unable to detect a .tern-project file ' 'in the hierarchy before ' + GetCurrentDirectory() + ' and no global .tern-config file was found. ' 'This is required for accurate JavaScript ' 'completion. Please see the User Guide for ' 'details.' ) ) @IsolatedYcmd @patch( 'ycmd.completers.javascript.tern_completer.GlobalConfigExists', return_value = True ) def EventNotification_OnFileReadyToParse_UseGlobalConfig_test( app, *args ): WaitUntilCompleterServerReady( app, 'javascript' ) os.chdir( PathToTestFile( '..' ) ) contents = ReadFile( PathToTestFile( 'simple_test.js' ) ) response = app.post_json( '/event_notification', BuildRequest( event_name = 'FileReadyToParse', contents = contents, filetype = 'javascript' ), expect_errors = True ) print( 'event response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, requests.codes.ok ) ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/subcommands_test.py0000644000175000017500000003720513026170313024356 0ustar onuronur# Copyright (C) 2015 ycmd contributors # encoding: utf-8 # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import print_function from __future__ import absolute_import from __future__ import unicode_literals from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, contains, contains_inanyorder, has_entries from nose.tools import eq_ from pprint import pformat import requests from ycmd.tests.javascript import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, ChunkMatcher, ErrorMatcher, LocationMatcher, WaitUntilCompleterServerReady ) from ycmd.utils import ReadFile @SharedYcmd def Subcommands_DefinedSubcommands_test( app ): subcommands_data = BuildRequest( completer_target = 'javascript' ) eq_( sorted( [ 'GoToDefinition', 'GoTo', 'GetDoc', 'GetType', 'GoToReferences', 'RefactorRename', 'RestartServer' ] ), app.post_json( '/defined_subcommands', subcommands_data ).json ) def RunTest( app, test, contents = None ): if not contents: contents = ReadFile( test[ 'request' ][ 'filepath' ] ) def CombineRequest( request, data ): kw = request request.update( data ) return BuildRequest( **kw ) # Because we aren't testing this command, we *always* ignore errors. This # is mainly because we (may) want to test scenarios where the completer # throws an exception and the easiest way to do that is to throw from # within the FlagsForFile function. app.post_json( '/event_notification', CombineRequest( test[ 'request' ], { 'event_name': 'FileReadyToParse', 'contents': contents, 'filetype': 'javascript', } ), expect_errors = True ) # We also ignore errors here, but then we check the response code # ourself. This is to allow testing of requests returning errors. response = app.post_json( '/run_completer_command', CombineRequest( test[ 'request' ], { 'completer_target': 'filetype_default', 'contents': contents, 'filetype': 'javascript', 'command_arguments': ( [ test[ 'request' ][ 'command' ] ] + test[ 'request' ].get( 'arguments', [] ) ) } ), expect_errors = True ) print( 'completer response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, test[ 'expect' ][ 'response' ] ) assert_that( response.json, test[ 'expect' ][ 'data' ] ) @SharedYcmd def Subcommands_GoToDefinition_test( app ): RunTest( app, { 'description': 'GoToDefinition works within file', 'request': { 'command': 'GoToDefinition', 'line_num': 13, 'column_num': 25, 'filepath': PathToTestFile( 'simple_test.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'filepath': PathToTestFile( 'simple_test.js' ), 'line_num': 1, 'column_num': 5, } ) } } ) @SharedYcmd def Subcommands_GoToDefinition_Unicode_test( app ): RunTest( app, { 'description': 'GoToDefinition works within file with unicode', 'request': { 'command': 'GoToDefinition', 'line_num': 11, 'column_num': 12, 'filepath': PathToTestFile( 'unicode.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'filepath': PathToTestFile( 'unicode.js' ), 'line_num': 6, 'column_num': 26, } ) } } ) @SharedYcmd def Subcommands_GoTo_test( app ): RunTest( app, { 'description': 'GoTo works the same as GoToDefinition within file', 'request': { 'command': 'GoTo', 'line_num': 13, 'column_num': 25, 'filepath': PathToTestFile( 'simple_test.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'filepath': PathToTestFile( 'simple_test.js' ), 'line_num': 1, 'column_num': 5, } ) } } ) @IsolatedYcmd def Subcommands_GoTo_RelativePath_test( app ): WaitUntilCompleterServerReady( app, 'javascript' ) RunTest( app, { 'description': 'GoTo works when the buffer differs from the file on disk', 'request': { 'command': 'GoTo', 'line_num': 43, 'column_num': 25, 'filepath': PathToTestFile( 'simple_test.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'filepath': PathToTestFile( 'simple_test.js' ), 'line_num': 31, 'column_num': 5, } ) } }, contents = ReadFile( PathToTestFile( 'simple_test.modified.js' ) ) ) @SharedYcmd def Subcommands_GetDoc_test( app ): RunTest( app, { 'description': 'GetDoc works within file', 'request': { 'command': 'GetDoc', 'line_num': 7, 'column_num': 16, 'filepath': PathToTestFile( 'coollib', 'cool_object.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'detailed_info': ( 'Name: mine_bitcoin\n' 'Type: fn(how_much: ?) -> number\n\n' 'This function takes a number and invests it in bitcoin. It ' 'returns\nthe expected value (in notional currency) after 1 year.' ) } ) } } ) @SharedYcmd def Subcommands_GetType_test( app ): RunTest( app, { 'description': 'GetType works within file', 'request': { 'command': 'GetType', 'line_num': 11, 'column_num': 14, 'filepath': PathToTestFile( 'coollib', 'cool_object.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'message': 'number' } ) } } ) @SharedYcmd def Subcommands_GoToReferences_test( app ): RunTest( app, { 'description': 'GoToReferences works within file', 'request': { 'command': 'GoToReferences', 'line_num': 17, 'column_num': 29, 'filepath': PathToTestFile( 'coollib', 'cool_object.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': contains_inanyorder( has_entries( { 'filepath': PathToTestFile( 'coollib', 'cool_object.js' ), 'line_num': 17, 'column_num': 29, } ), has_entries( { 'filepath': PathToTestFile( 'coollib', 'cool_object.js' ), 'line_num': 12, 'column_num': 9, } ) ) } } ) @SharedYcmd def Subcommands_GoToReferences_Unicode_test( app ): RunTest( app, { 'description': 'GoToReferences works within file with unicode chars', 'request': { 'command': 'GoToReferences', 'line_num': 11, 'column_num': 5, 'filepath': PathToTestFile( 'unicode.js' ), }, 'expect': { 'response': requests.codes.ok, 'data': contains_inanyorder( has_entries( { 'filepath': PathToTestFile( 'unicode.js' ), 'line_num': 5, 'column_num': 5, } ), has_entries( { 'filepath': PathToTestFile( 'unicode.js' ), 'line_num': 9, 'column_num': 1, } ), has_entries( { 'filepath': PathToTestFile( 'unicode.js' ), 'line_num': 11, 'column_num': 1, } ) ) } } ) @SharedYcmd def Subcommands_GetDocWithNoItendifier_test( app ): RunTest( app, { 'description': 'GetDoc works when no identifier', 'request': { 'command': 'GetDoc', 'filepath': PathToTestFile( 'simple_test.js' ), 'line_num': 12, 'column_num': 1, }, 'expect': { 'response': requests.codes.internal_server_error, 'data': ErrorMatcher( RuntimeError, 'TernError: No type found ' 'at the given position.' ), } } ) @SharedYcmd def Subcommands_RefactorRename_Simple_test( app ): filepath = PathToTestFile( 'simple_test.js' ) RunTest( app, { 'description': 'RefactorRename works within a single scope/file', 'request': { 'command': 'RefactorRename', 'arguments': [ 'test' ], 'filepath': filepath, 'line_num': 15, 'column_num': 32, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries ( { 'fixits': contains( has_entries( { 'chunks': contains( ChunkMatcher( 'test', LocationMatcher( filepath, 1, 5 ), LocationMatcher( filepath, 1, 22 ) ), ChunkMatcher( 'test', LocationMatcher( filepath, 13, 25 ), LocationMatcher( filepath, 13, 42 ) ), ChunkMatcher( 'test', LocationMatcher( filepath, 14, 24 ), LocationMatcher( filepath, 14, 41 ) ), ChunkMatcher( 'test', LocationMatcher( filepath, 15, 24 ), LocationMatcher( filepath, 15, 41 ) ), ChunkMatcher( 'test', LocationMatcher( filepath, 21, 7 ), LocationMatcher( filepath, 21, 24 ) ), # On the same line, ensuring offsets are as expected (as # unmodified source, similar to clang) ChunkMatcher( 'test', LocationMatcher( filepath, 21, 28 ), LocationMatcher( filepath, 21, 45 ) ), ), 'location': LocationMatcher( filepath, 15, 32 ) } ) ) } ) } } ) @SharedYcmd def Subcommands_RefactorRename_MultipleFiles_test( app ): file1 = PathToTestFile( 'file1.js' ) file2 = PathToTestFile( 'file2.js' ) file3 = PathToTestFile( 'file3.js' ) RunTest( app, { 'description': 'RefactorRename works across files', 'request': { 'command': 'RefactorRename', 'arguments': [ 'a-quite-long-string' ], 'filepath': file1, 'line_num': 3, 'column_num': 14, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries ( { 'fixits': contains( has_entries( { 'chunks': contains( ChunkMatcher( 'a-quite-long-string', LocationMatcher( file1, 1, 5 ), LocationMatcher( file1, 1, 11 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file1, 3, 14 ), LocationMatcher( file1, 3, 20 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file2, 2, 14 ), LocationMatcher( file2, 2, 20 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file3, 3, 12 ), LocationMatcher( file3, 3, 18 ) ) ), 'location': LocationMatcher( file1, 3, 14 ) } ) ) } ) } } ) # Needs to be isolated to prevent interfering with other tests (this test loads # an extra file into tern's project memory) @IsolatedYcmd def Subcommands_RefactorRename_MultipleFiles_OnFileReadyToParse_test( app ): WaitUntilCompleterServerReady( app, 'javascript' ) file1 = PathToTestFile( 'file1.js' ) file2 = PathToTestFile( 'file2.js' ) file3 = PathToTestFile( 'file3.js' ) # This test is roughly the same as the previous one, except here file4.js is # pushed into the Tern engine via 'opening it in the editor' (i.e. # FileReadyToParse event). The first 3 are loaded into the tern server # because they are listed in the .tern-project file's loadEagerly option. file4 = PathToTestFile( 'file4.js' ) app.post_json( '/event_notification', BuildRequest( **{ 'filetype': 'javascript', 'event_name': 'FileReadyToParse', 'contents': ReadFile( file4 ), 'filepath': file4, } ), expect_errors = False ) RunTest( app, { 'description': 'FileReadyToParse loads files into tern server', 'request': { 'command': 'RefactorRename', 'arguments': [ 'a-quite-long-string' ], 'filepath': file1, 'line_num': 3, 'column_num': 14, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( ChunkMatcher( 'a-quite-long-string', LocationMatcher( file1, 1, 5 ), LocationMatcher( file1, 1, 11 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file1, 3, 14 ), LocationMatcher( file1, 3, 20 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file2, 2, 14 ), LocationMatcher( file2, 2, 20 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file3, 3, 12 ), LocationMatcher( file3, 3, 18 ) ), ChunkMatcher( 'a-quite-long-string', LocationMatcher( file4, 4, 22 ), LocationMatcher( file4, 4, 28 ) ) ), 'location': LocationMatcher( file1, 3, 14 ) } ) ) } ) } } ) @SharedYcmd def Subcommands_RefactorRename_Missing_New_Name_test( app ): RunTest( app, { 'description': 'RefactorRename raises an error without new name', 'request': { 'command': 'RefactorRename', 'line_num': 17, 'column_num': 29, 'filepath': PathToTestFile( 'coollib', 'cool_object.js' ), }, 'expect': { 'response': requests.codes.internal_server_error, 'data': ErrorMatcher( ValueError, 'Please specify a new name to rename it to.\n' 'Usage: RefactorRename ' ), } } ) @SharedYcmd def Subcommands_RefactorRename_Unicode_test( app ): filepath = PathToTestFile( 'unicode.js' ) RunTest( app, { 'description': 'RefactorRename works with unicode identifiers', 'request': { 'command': 'RefactorRename', 'arguments': [ '†es†' ], 'filepath': filepath, 'line_num': 11, 'column_num': 3, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries ( { 'fixits': contains( has_entries( { 'chunks': contains( ChunkMatcher( '†es†', LocationMatcher( filepath, 5, 5 ), LocationMatcher( filepath, 5, 13 ) ), ChunkMatcher( '†es†', LocationMatcher( filepath, 9, 1 ), LocationMatcher( filepath, 9, 9 ) ), ChunkMatcher( '†es†', LocationMatcher( filepath, 11, 1 ), LocationMatcher( filepath, 11, 9 ) ) ), 'location': LocationMatcher( filepath, 11, 3 ) } ) ) } ) } } ) ycmd-0+20161219+git486b809.orig/ycmd/tests/javascript/debug_info_test.py0000644000175000017500000000520213026170313024134 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, matches_regexp from ycmd.tests.javascript import IsolatedYcmd, SharedYcmd from ycmd.tests.test_utils import BuildRequest, StopCompleterServer, UserOption @SharedYcmd def DebugInfo_ServerIsRunning_test( app ): request_data = BuildRequest( filetype = 'javascript' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'JavaScript completer debug information:\n' ' Tern running at: http://127.0.0.1:\d+\n' ' Tern process ID: \d+\n' ' Tern executable: .+\n' ' Tern logfiles:\n' ' .+\n' ' .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesExist_test( app ): with UserOption( 'server_keep_logfiles', True ): StopCompleterServer( app, 'javascript' ) request_data = BuildRequest( filetype = 'javascript' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'JavaScript completer debug information:\n' ' Tern no longer running\n' ' Tern executable: .+\n' ' Tern logfiles:\n' ' .+\n' ' .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesDoNotExist_test( app ): with UserOption( 'server_keep_logfiles', False ): StopCompleterServer( app, 'javascript' ) request_data = BuildRequest( filetype = 'javascript' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'JavaScript completer debug information:\n' ' Tern is not running\n' ' Tern executable: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/0000755000175000017500000000000013026170313020066 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/basic.tags0000644000175000017500000000074513026170313022035 0ustar onuronur!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ !_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ !_TAG_PROGRAM_NAME Exuberant Ctags // !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ !_TAG_PROGRAM_VERSION 5.8 // i1 foo junky;'junklanguage:C++ i1 bar junky;'junklanguage:C++ foosy foo junky;"'junk language:C++ zanzibar fooaaa bar junky;"'junk language:C++ zanzibar ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/0000755000175000017500000000000013026170313023720 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/∂†∫/0000755000175000017500000000000013026170313027002 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/∂†∫/†es†.txt0000644000175000017500000000000013026170313032144 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/0000755000175000017500000000000013026170313025671 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/0000755000175000017500000000000013026170313027314 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/Qt/0000755000175000017500000000000013026170313027700 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/Qt/QtGui0000644000175000017500000000005013026170313030647 0ustar onuronur// This file includes all QtGui headers ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/0000755000175000017500000000000013026170313030345 5ustar onuronur././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QDialogycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QDial0000644000175000017500000000000013026170313031250 0ustar onuronur././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QWidgetycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QWidg0000644000175000017500000000000013026170313031271 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/foo漢字.txt0000644000175000017500000000000013026170313031360 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/test.cpp0000644000175000017500000000007213026170313027353 0ustar onuronur#include "test.hpp" #include const char* c = ""; ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/filename_completer/inner_dir/test.hpp0000644000175000017500000000000013026170313027347 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/windows/0000755000175000017500000000000013026170313021560 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/windows/compile_commands.json0000644000175000017500000000014513026170313025764 0ustar onuronur[ { "directory": "C:\\dir", "command": "/usr/bin/clang++ example.cc", "file": "example.cc" } ] ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/python-future/0000755000175000017500000000000013026170313022717 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/python-future/virtualenv_library/0000755000175000017500000000000013026170313026642 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/python-future/virtualenv_library/orig-prefix.txt0000644000175000017500000000000013026170313031624 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/python-future/virtualenv_library/os.py0000644000175000017500000000000013026170313027623 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/python-future/standard_library/0000755000175000017500000000000013026170313026243 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/python-future/standard_library/os.py0000644000175000017500000000000013026170313027224 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/client/0000755000175000017500000000000013026170313021344 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/client/some_file0000644000175000017500000000000013026170313023217 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/client/.ycm_extra_conf.py0000644000175000017500000000000013026170313024762 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/client/cs_solution.sln0000644000175000017500000000000013026170313024411 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/unix/0000755000175000017500000000000013026170313021051 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/unix/compile_commands.json0000644000175000017500000000014213026170313025252 0ustar onuronur[ { "directory": "/dir", "command": "/usr/bin/clang++ example.cc", "file": "example.cc" } ] ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/extra_conf/0000755000175000017500000000000013026170313022216 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/extra_conf/global_extra_conf.py0000644000175000017500000000013613026170313026240 0ustar onuronurdef NoException(): pass def RaiseException(): raise Exception( 'Exception raised' ) ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/extra_conf/erroneous_extra_conf.py0000644000175000017500000000004613026170313027021 0ustar onuronurraise Exception( 'Exception raised' ) ycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/extra_conf/project/0000755000175000017500000000000013026170313023664 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/testdata/extra_conf/project/.ycm_extra_conf.py0000644000175000017500000000000013026170313027302 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/identifier_utils_test.py0000644000175000017500000003347113026170313023240 0ustar onuronur# coding: utf-8 # # Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_, ok_ from ycmd import identifier_utils as iu from hamcrest import assert_that, has_item def RemoveIdentifierFreeText_CppComments_test(): eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( "foo \nbar //foo \nqux" ) ) def RemoveIdentifierFreeText_PythonComments_test(): eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( "foo \nbar #foo \nqux" ) ) def RemoveIdentifierFreeText_CstyleComments_test(): eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( "foo \nbar /* foo */\nqux" ) ) eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( "foo \nbar /* foo \n foo2 */\nqux" ) ) def RemoveIdentifierFreeText_SimpleSingleQuoteString_test(): eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( "foo \nbar 'foo'\nqux" ) ) def RemoveIdentifierFreeText_SimpleDoubleQuoteString_test(): eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( 'foo \nbar "foo"\nqux' ) ) def RemoveIdentifierFreeText_EscapedQuotes_test(): eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( "foo \nbar 'fo\\'oz\\nfoo'\nqux" ) ) eq_( "foo \nbar \nqux", iu.RemoveIdentifierFreeText( 'foo \nbar "fo\\"oz\\nfoo"\nqux' ) ) def RemoveIdentifierFreeText_SlashesInStrings_test(): eq_( "foo \nbar baz\nqux ", iu.RemoveIdentifierFreeText( 'foo \nbar "fo\\\\"baz\nqux "qwe"' ) ) eq_( "foo \nbar \nqux ", iu.RemoveIdentifierFreeText( "foo '\\\\'\nbar '\\\\'\nqux '\\\\'" ) ) def RemoveIdentifierFreeText_EscapedQuotesStartStrings_test(): eq_( "\\\"foo\\\" zoo", iu.RemoveIdentifierFreeText( "\\\"foo\\\"'\"''bar' zoo'test'" ) ) eq_( "\\'foo\\' zoo", iu.RemoveIdentifierFreeText( "\\'foo\\'\"'\"\"bar\" zoo\"test\"" ) ) def RemoveIdentifierFreeText_NoMultilineString_test(): eq_( "'\nlet x = \nlet y = ", iu.RemoveIdentifierFreeText( "'\nlet x = 'foo'\nlet y = 'bar'" ) ) eq_( "\"\nlet x = \nlet y = ", iu.RemoveIdentifierFreeText( "\"\nlet x = \"foo\"\nlet y = \"bar\"" ) ) def RemoveIdentifierFreeText_PythonMultilineString_test(): eq_( "\nzoo", iu.RemoveIdentifierFreeText( "\"\"\"\nfoobar\n\"\"\"\nzoo" ) ) eq_( "\nzoo", iu.RemoveIdentifierFreeText( "'''\nfoobar\n'''\nzoo" ) ) def ExtractIdentifiersFromText_test(): eq_( [ "foo", "_bar", "BazGoo", "FOO", "_", "x", "one", "two", "moo", "qqq" ], iu.ExtractIdentifiersFromText( "foo $_bar \n&BazGoo\n FOO= !!! '-' - _ (x) one-two !moo [qqq]" ) ) def ExtractIdentifiersFromText_Css_test(): eq_( [ "foo", "-zoo", "font-size", "px", "a99" ], iu.ExtractIdentifiersFromText( "foo -zoo {font-size: 12px;} a99", "css" ) ) def ExtractIdentifiersFromText_Html_test(): eq_( [ "foo", "goo-foo", "zoo", "bar", "aa", "z", "b@g", "fo", "ba" ], iu.ExtractIdentifiersFromText( ' b@g fo.ba', "html" ) ) def ExtractIdentifiersFromText_Html_TemplateChars_test(): assert_that( iu.ExtractIdentifiersFromText( '{{goo}}', 'html' ), has_item( 'goo' ) ) def IsIdentifier_Default_test(): ok_( iu.IsIdentifier( 'foo' ) ) ok_( iu.IsIdentifier( 'foo129' ) ) ok_( iu.IsIdentifier( 'f12' ) ) ok_( iu.IsIdentifier( 'f12' ) ) ok_( iu.IsIdentifier( '_foo' ) ) ok_( iu.IsIdentifier( '_foo129' ) ) ok_( iu.IsIdentifier( '_f12' ) ) ok_( iu.IsIdentifier( '_f12' ) ) ok_( iu.IsIdentifier( 'uniçode' ) ) ok_( iu.IsIdentifier( 'uç' ) ) ok_( iu.IsIdentifier( 'ç' ) ) ok_( iu.IsIdentifier( 'çode' ) ) ok_( not iu.IsIdentifier( '1foo129' ) ) ok_( not iu.IsIdentifier( '-foo' ) ) ok_( not iu.IsIdentifier( 'foo-' ) ) ok_( not iu.IsIdentifier( 'font-face' ) ) ok_( not iu.IsIdentifier( None ) ) ok_( not iu.IsIdentifier( '' ) ) def IsIdentifier_JavaScript_test(): ok_( iu.IsIdentifier( '_føo1', 'javascript' ) ) ok_( iu.IsIdentifier( 'fø_o1', 'javascript' ) ) ok_( iu.IsIdentifier( '$føo1', 'javascript' ) ) ok_( iu.IsIdentifier( 'fø$o1', 'javascript' ) ) ok_( not iu.IsIdentifier( '1føo', 'javascript' ) ) def IsIdentifier_TypeScript_test(): ok_( iu.IsIdentifier( '_føo1', 'typescript' ) ) ok_( iu.IsIdentifier( 'fø_o1', 'typescript' ) ) ok_( iu.IsIdentifier( '$føo1', 'typescript' ) ) ok_( iu.IsIdentifier( 'fø$o1', 'typescript' ) ) ok_( not iu.IsIdentifier( '1føo', 'typescript' ) ) def IsIdentifier_Css_test(): ok_( iu.IsIdentifier( 'foo' , 'css' ) ) ok_( iu.IsIdentifier( 'a1' , 'css' ) ) ok_( iu.IsIdentifier( 'a-' , 'css' ) ) ok_( iu.IsIdentifier( 'a-b' , 'css' ) ) ok_( iu.IsIdentifier( '_b' , 'css' ) ) ok_( iu.IsIdentifier( '-ms-foo' , 'css' ) ) ok_( iu.IsIdentifier( '-_o' , 'css' ) ) ok_( iu.IsIdentifier( 'font-face', 'css' ) ) ok_( not iu.IsIdentifier( '-3b', 'css' ) ) ok_( not iu.IsIdentifier( '-3' , 'css' ) ) ok_( not iu.IsIdentifier( '3' , 'css' ) ) ok_( not iu.IsIdentifier( 'a' , 'css' ) ) ok_( not iu.IsIdentifier( '' , 'css' ) ) def IsIdentifier_R_test(): ok_( iu.IsIdentifier( 'a' , 'r' ) ) ok_( iu.IsIdentifier( 'a.b' , 'r' ) ) ok_( iu.IsIdentifier( 'a.b.c', 'r' ) ) ok_( iu.IsIdentifier( 'a_b' , 'r' ) ) ok_( iu.IsIdentifier( 'a1' , 'r' ) ) ok_( iu.IsIdentifier( 'a_1' , 'r' ) ) ok_( iu.IsIdentifier( '.a' , 'r' ) ) ok_( iu.IsIdentifier( '.a_b' , 'r' ) ) ok_( iu.IsIdentifier( '.a1' , 'r' ) ) ok_( iu.IsIdentifier( '...' , 'r' ) ) ok_( iu.IsIdentifier( '..1' , 'r' ) ) ok_( not iu.IsIdentifier( '.1a', 'r' ) ) ok_( not iu.IsIdentifier( '.1' , 'r' ) ) ok_( not iu.IsIdentifier( '1a' , 'r' ) ) ok_( not iu.IsIdentifier( '123', 'r' ) ) ok_( not iu.IsIdentifier( '_1a', 'r' ) ) ok_( not iu.IsIdentifier( '_a' , 'r' ) ) ok_( not iu.IsIdentifier( '' , 'r' ) ) def IsIdentifier_Clojure_test(): ok_( iu.IsIdentifier( 'foo' , 'clojure' ) ) ok_( iu.IsIdentifier( 'f9' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a.b.c', 'clojure' ) ) ok_( iu.IsIdentifier( 'a.c' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a/c' , 'clojure' ) ) ok_( iu.IsIdentifier( '*' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a*b' , 'clojure' ) ) ok_( iu.IsIdentifier( '?' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a?b' , 'clojure' ) ) ok_( iu.IsIdentifier( ':' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a:b' , 'clojure' ) ) ok_( iu.IsIdentifier( '+' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a+b' , 'clojure' ) ) ok_( iu.IsIdentifier( '-' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a-b' , 'clojure' ) ) ok_( iu.IsIdentifier( '!' , 'clojure' ) ) ok_( iu.IsIdentifier( 'a!b' , 'clojure' ) ) ok_( not iu.IsIdentifier( '9f' , 'clojure' ) ) ok_( not iu.IsIdentifier( '9' , 'clojure' ) ) ok_( not iu.IsIdentifier( 'a/b/c', 'clojure' ) ) ok_( not iu.IsIdentifier( '(a)' , 'clojure' ) ) ok_( not iu.IsIdentifier( '' , 'clojure' ) ) def IsIdentifier_Elisp_test(): # elisp is using the clojure regexes, so we're testing this more lightly ok_( iu.IsIdentifier( 'foo' , 'elisp' ) ) ok_( iu.IsIdentifier( 'f9' , 'elisp' ) ) ok_( iu.IsIdentifier( 'a.b.c', 'elisp' ) ) ok_( iu.IsIdentifier( 'a/c' , 'elisp' ) ) ok_( not iu.IsIdentifier( '9f' , 'elisp' ) ) ok_( not iu.IsIdentifier( '9' , 'elisp' ) ) ok_( not iu.IsIdentifier( 'a/b/c', 'elisp' ) ) ok_( not iu.IsIdentifier( '(a)' , 'elisp' ) ) ok_( not iu.IsIdentifier( '' , 'elisp' ) ) def IsIdentifier_Haskell_test(): ok_( iu.IsIdentifier( 'foo' , 'haskell' ) ) ok_( iu.IsIdentifier( "foo'", 'haskell' ) ) ok_( iu.IsIdentifier( "x'" , 'haskell' ) ) ok_( iu.IsIdentifier( "_x'" , 'haskell' ) ) ok_( iu.IsIdentifier( "_x" , 'haskell' ) ) ok_( iu.IsIdentifier( "x9" , 'haskell' ) ) ok_( not iu.IsIdentifier( "'x", 'haskell' ) ) ok_( not iu.IsIdentifier( "9x", 'haskell' ) ) ok_( not iu.IsIdentifier( "9" , 'haskell' ) ) ok_( not iu.IsIdentifier( '' , 'haskell' ) ) def IsIdentifier_Tex_test(): ok_( iu.IsIdentifier( 'foo', 'tex' ) ) ok_( iu.IsIdentifier( 'fig:foo', 'tex' ) ) ok_( iu.IsIdentifier( 'fig:foo-bar', 'tex' ) ) ok_( iu.IsIdentifier( 'sec:summary', 'tex' ) ) ok_( iu.IsIdentifier( 'eq:bar_foo', 'tex' ) ) ok_( not iu.IsIdentifier( '\section', 'tex' ) ) ok_( not iu.IsIdentifier( 'some8', 'tex' ) ) ok_( not iu.IsIdentifier( '' , 'tex' ) ) def IsIdentifier_Perl6_test(): ok_( iu.IsIdentifier( 'foo' , 'perl6' ) ) ok_( iu.IsIdentifier( "f-o" , 'perl6' ) ) ok_( iu.IsIdentifier( "x'y" , 'perl6' ) ) ok_( iu.IsIdentifier( "_x-y" , 'perl6' ) ) ok_( iu.IsIdentifier( "x-y'a", 'perl6' ) ) ok_( iu.IsIdentifier( "x-_" , 'perl6' ) ) ok_( iu.IsIdentifier( "x-_7" , 'perl6' ) ) ok_( iu.IsIdentifier( "_x" , 'perl6' ) ) ok_( iu.IsIdentifier( "x9" , 'perl6' ) ) ok_( not iu.IsIdentifier( "'x" , 'perl6' ) ) ok_( not iu.IsIdentifier( "x'" , 'perl6' ) ) ok_( not iu.IsIdentifier( "-x" , 'perl6' ) ) ok_( not iu.IsIdentifier( "x-" , 'perl6' ) ) ok_( not iu.IsIdentifier( "x-1" , 'perl6' ) ) ok_( not iu.IsIdentifier( "x--" , 'perl6' ) ) ok_( not iu.IsIdentifier( "x--a", 'perl6' ) ) ok_( not iu.IsIdentifier( "x-'" , 'perl6' ) ) ok_( not iu.IsIdentifier( "x-'a", 'perl6' ) ) ok_( not iu.IsIdentifier( "x-a-", 'perl6' ) ) ok_( not iu.IsIdentifier( "x+" , 'perl6' ) ) ok_( not iu.IsIdentifier( "9x" , 'perl6' ) ) ok_( not iu.IsIdentifier( "9" , 'perl6' ) ) ok_( not iu.IsIdentifier( '' , 'perl6' ) ) def StartOfLongestIdentifierEndingAtIndex_Simple_test(): eq_( 0, iu.StartOfLongestIdentifierEndingAtIndex( 'foo', 3 ) ) eq_( 0, iu.StartOfLongestIdentifierEndingAtIndex( 'f12', 3 ) ) def StartOfLongestIdentifierEndingAtIndex_BadInput_test(): eq_( 0, iu.StartOfLongestIdentifierEndingAtIndex( '', 0 ) ) eq_( 1, iu.StartOfLongestIdentifierEndingAtIndex( '', 1 ) ) eq_( 5, iu.StartOfLongestIdentifierEndingAtIndex( None, 5 ) ) eq_( -1, iu.StartOfLongestIdentifierEndingAtIndex( 'foo', -1 ) ) eq_( 10, iu.StartOfLongestIdentifierEndingAtIndex( 'foo', 10 ) ) def StartOfLongestIdentifierEndingAtIndex_Punctuation_test(): eq_( 1, iu.StartOfLongestIdentifierEndingAtIndex( '(foo', 4 ) ) eq_( 6, iu.StartOfLongestIdentifierEndingAtIndex( ' foo', 9 ) ) eq_( 4, iu.StartOfLongestIdentifierEndingAtIndex( 'gar;foo', 7 ) ) eq_( 2, iu.StartOfLongestIdentifierEndingAtIndex( '...', 2 ) ) def StartOfLongestIdentifierEndingAtIndex_PunctuationWithUnicode_test(): eq_( 1, iu.StartOfLongestIdentifierEndingAtIndex( u'(fäö', 4 ) ) eq_( 2, iu.StartOfLongestIdentifierEndingAtIndex( u' fäö', 5 ) ) # Not a test, but a test helper function def LoopExpectLongestIdentifier( ident, expected, end_index ): eq_( expected, iu.StartOfLongestIdentifierEndingAtIndex( ident, end_index ) ) def StartOfLongestIdentifierEndingAtIndex_Entire_Simple_test(): ident = 'foobar' for i in range( len( ident ) ): yield LoopExpectLongestIdentifier, ident, 0, i def StartOfLongestIdentifierEndingAtIndex_Entire_AllBad_test(): ident = '....' for i in range( len( ident ) ): yield LoopExpectLongestIdentifier, ident, i, i def StartOfLongestIdentifierEndingAtIndex_Entire_FirstCharNotNumber_test(): ident = 'f12341234' for i in range( len( ident ) ): yield LoopExpectLongestIdentifier, ident, 0, i def StartOfLongestIdentifierEndingAtIndex_Entire_SubIdentifierValid_test(): ident = 'f123f1234' for i in range( len( ident ) ): yield LoopExpectLongestIdentifier, ident, 0, i def StartOfLongestIdentifierEndingAtIndex_Entire_Unicode_test(): ident = u'fäöttccoö' for i in range( len( ident ) ): yield LoopExpectLongestIdentifier, ident, 0, i # Not a test, but a test helper function def LoopExpectIdentfierAtIndex( ident, index, expected ): eq_( expected, iu.IdentifierAtIndex( ident, index ) ) def IdentifierAtIndex_Entire_Simple_test(): ident = u'foobar' for i in range( len( ident ) ): yield LoopExpectIdentfierAtIndex, ident, i, ident def IdentifierAtIndex_Entire_Unicode_test(): ident = u'fäöttccoö' for i in range( len( ident ) ): yield LoopExpectIdentfierAtIndex, ident, i, ident def IdentifierAtIndex_BadInput_test(): eq_( '', iu.IdentifierAtIndex( '', 0 ) ) eq_( '', iu.IdentifierAtIndex( '', 5 ) ) eq_( '', iu.IdentifierAtIndex( 'foo', 5 ) ) eq_( 'foo', iu.IdentifierAtIndex( 'foo', -5 ) ) def IdentifierAtIndex_IndexPastIdent_test(): eq_( '', iu.IdentifierAtIndex( 'foo ', 5 ) ) def IdentifierAtIndex_StopsAtNonIdentifier_test(): eq_( 'foo', iu.IdentifierAtIndex( 'foo(goo)', 0 ) ) eq_( 'goo', iu.IdentifierAtIndex( 'foo(goo)', 5 ) ) def IdentifierAtIndex_LooksAhead_Success_test(): eq_( 'goo', iu.IdentifierAtIndex( 'foo(goo)', 3 ) ) eq_( 'goo', iu.IdentifierAtIndex( ' goo', 0 ) ) def IdentifierAtIndex_LooksAhead_Failure_test(): eq_( '', iu.IdentifierAtIndex( 'foo ()***()', 5 ) ) def IdentifierAtIndex_SingleCharIdent_test(): eq_( 'f', iu.IdentifierAtIndex( ' f ', 1 ) ) def IdentifierAtIndex_Css_test(): eq_( 'font-face', iu.IdentifierAtIndex( 'font-face', 0, 'css' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/get_completions_test.py0000644000175000017500000004616713026170313023077 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2013 Google Inc. # 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, equal_to, has_items, contains_string, contains_inanyorder ) from mock import patch from nose.tools import eq_ from ycmd.tests import SharedYcmd, PathToTestFile from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, DummyCompleter, PatchCompleter, UserOption, ExpectedFailure ) @SharedYcmd def GetCompletions_RequestValidation_NoLineNumException_test( app ): response = app.post_json( '/semantic_completion_available', { 'column_num': 0, 'filepath': '/foo', 'file_data': { '/foo': { 'filetypes': [ 'text' ], 'contents': 'zoo' } } }, status = '5*', expect_errors = True ) response.mustcontain( 'missing', 'line_num' ) @SharedYcmd def GetCompletions_IdentifierCompleter_Works_test( app ): event_data = BuildRequest( contents = 'foo foogoo ba', event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) # query is 'oo' completion_data = BuildRequest( contents = 'oo foo foogoo ba', column_num = 3 ) response_data = app.post_json( '/completions', completion_data ).json eq_( 1, response_data[ 'completion_start_column' ] ) assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'foo', '[ID]' ), CompletionEntryMatcher( 'foogoo', '[ID]' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_FilterShortCandidates_test( app ): with UserOption( 'min_num_identifier_candidate_chars', 4 ): event_data = BuildRequest( contents = 'foo foogoo gooo', event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo', column_num = 3 ) response = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( response, contains_inanyorder( CompletionEntryMatcher( 'foogoo' ), CompletionEntryMatcher( 'gooo' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_StartColumn_AfterWord_test( app ): completion_data = BuildRequest( contents = 'oo foo foogoo ba', column_num = 11 ) response_data = app.post_json( '/completions', completion_data ).json eq_( 8, response_data[ 'completion_start_column' ] ) @SharedYcmd def GetCompletions_IdentifierCompleter_WorksForSpecialIdentifierChars_test( app ): contents = """ textarea { font-family: sans-serif; font-size: 12px; }""" event_data = BuildRequest( contents = contents, filetype = 'css', event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) # query is 'fo' completion_data = BuildRequest( contents = 'fo ' + contents, filetype = 'css', column_num = 3 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'font-size', '[ID]' ), CompletionEntryMatcher( 'font-family', '[ID]' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_Unicode_InLine_test( app ): contents = """ This is some text cøntaining unicøde """ event_data = BuildRequest( contents = contents, filetype = 'css', event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) # query is 'tx' completion_data = BuildRequest( contents = 'tx ' + contents, filetype = 'css', column_num = 3 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'text', '[ID]' ) ) ) @ExpectedFailure( 'The identifier completer does not support ' 'unicode characters', contains_string( '[]' ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_UnicodeQuery_InLine_test( app ): contents = """ This is some text cøntaining unicøde """ event_data = BuildRequest( contents = contents, filetype = 'css', event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) # query is 'cø' completion_data = BuildRequest( contents = 'cø ' + contents, filetype = 'css', column_num = 4 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'cøntaining', '[ID]' ), CompletionEntryMatcher( 'unicøde', '[ID]' ) ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', return_value = [ 'foo', 'bar', 'qux' ] ) def GetCompletions_ForceSemantic_Works_test( app, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): completion_data = BuildRequest( filetype = 'dummy_filetype', force_semantic = True ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'foo' ), CompletionEntryMatcher( 'bar' ), CompletionEntryMatcher( 'qux' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_SyntaxKeywordsAdded_test( app ): event_data = BuildRequest( event_name = 'FileReadyToParse', syntax_keywords = ['foo', 'bar', 'zoo'] ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo ', column_num = 3 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'foo' ), CompletionEntryMatcher( 'zoo' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_TagsAdded_test( app ): event_data = BuildRequest( event_name = 'FileReadyToParse', tag_files = [ PathToTestFile( 'basic.tags' ) ] ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo', column_num = 3, filetype = 'cpp' ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'foosy' ), CompletionEntryMatcher( 'fooaaa' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_JustFinishedIdentifier_test( app ): event_data = BuildRequest( event_name = 'CurrentIdentifierFinished', column_num = 4, contents = 'foo' ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo', column_num = 3 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'foo' ) ) ) @SharedYcmd def GetCompletions_IdentifierCompleter_IdentifierUnderCursor_test( app ): event_data = BuildRequest( event_name = 'InsertLeave', column_num = 2, contents = 'foo' ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo', column_num = 3 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'foo' ) ) ) @SharedYcmd def GetCompletions_UltiSnipsCompleter_Works_test( app ): event_data = BuildRequest( event_name = 'BufferVisit', ultisnips_snippets = [ {'trigger': 'foo', 'description': 'bar'}, {'trigger': 'zoo', 'description': 'goo'}, ] ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo ', column_num = 3 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'foo', extra_menu_info=' bar' ), CompletionEntryMatcher( 'zoo', extra_menu_info=' goo' ) ) ) @SharedYcmd def GetCompletions_UltiSnipsCompleter_UnusedWhenOffWithOption_test( app ): with UserOption( 'use_ultisnips_completer', False ): event_data = BuildRequest( event_name = 'BufferVisit', ultisnips_snippets = [ {'trigger': 'foo', 'description': 'bar'}, {'trigger': 'zoo', 'description': 'goo'}, ] ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( contents = 'oo ', column_num = 3 ) eq_( [], app.post_json( '/completions', completion_data ).json[ 'completions' ] ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', return_value = [ 'some_candidate' ] ) def GetCompletions_SemanticCompleter_WorksWhenTriggerIsIdentifier_test( app, *args ): with UserOption( 'semantic_triggers', { 'dummy_filetype': [ '_' ] } ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'some_can', column_num = 9 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'some_candidate' ) ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.ShouldUseNowInner', return_value = True ) @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', return_value = [ 'attribute' ] ) def GetCompletions_CacheIsValid_test( app, candidates_list, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'object.attr', line_num = 1, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attribute' ) ) ) completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'object.attri', line_num = 1, column_num = 13 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attribute' ) ) ) # We ask for candidates only once because of cache. assert_that( candidates_list.call_count, equal_to( 1 ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.ShouldUseNowInner', return_value = True ) @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', side_effect = [ [ 'attributeA' ], [ 'attributeB' ] ] ) def GetCompletions_CacheIsNotValid_DifferentLineNumber_test( app, candidates_list, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.attr\n' 'objectB.attr', line_num = 1, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attributeA' ) ) ) completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.\n' 'objectB.', line_num = 2, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attributeB' ) ) ) # We ask for candidates twice because of cache invalidation: # line numbers are different between requests. assert_that( candidates_list.call_count, equal_to( 2 ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.ShouldUseNowInner', return_value = True ) @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', side_effect = [ [ 'attributeA' ], [ 'attributeB' ] ] ) def GetCompletions_CacheIsNotValid_DifferentStartColumn_test( app, candidates_list, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): # Start column is 9 completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.attr', line_num = 1, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attributeA' ) ) ) # Start column is 8 completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'object.attri', line_num = 1, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attributeB' ) ) ) # We ask for candidates twice because of cache invalidation: # start columns are different between requests. assert_that( candidates_list.call_count, equal_to( 2 ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.ShouldUseNowInner', return_value = True ) @patch( 'ycmd.tests.test_utils.DummyCompleter.CompletionType', side_effect = [ 0, 0, 0, 0, 1, 1, 1, 1 ] ) @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', side_effect = [ [ 'attributeA' ], [ 'attributeB' ] ] ) def GetCompletions_CacheIsNotValid_DifferentCompletionType_test( app, candidates_list, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.attr', line_num = 1, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attributeA' ) ) ) completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.attr', line_num = 1, column_num = 12 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'attributeB' ) ) ) # We ask for candidates twice because of cache invalidation: # completion types are different between requests. assert_that( candidates_list.call_count, equal_to( 2 ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.ShouldUseNowInner', return_value = True ) @patch( 'ycmd.tests.test_utils.DummyCompleter.CandidatesList', return_value = [ 'aba', 'cbc' ] ) def GetCompletions_FilterThenReturnFromCache_test( app, candidates_list, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): # First, fill the cache with an empty query completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.', line_num = 1, column_num = 9 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'aba' ), CompletionEntryMatcher( 'cbc' ) ) ) # Now, filter them. This causes them to be converted to bytes and back completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.c', line_num = 1, column_num = 10 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'cbc' ) ) ) # Finally, request the original (unfiltered) set again. Ensure that we get # proper results (not some bytes objects) # First, fill the cache with an empty query completion_data = BuildRequest( filetype = 'dummy_filetype', contents = 'objectA.', line_num = 1, column_num = 9 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'aba' ), CompletionEntryMatcher( 'cbc' ) ) ) assert_that( candidates_list.call_count, equal_to( 1 ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/bottle_utils_test.py0000644000175000017500000000367513026170313022412 0ustar onuronur# Copyright (C) 2016 ycmd contributors. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . # Intentionally not importing unicode_literals! from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_ from mock import patch, call from ycmd import bottle_utils from ycmd.tests.test_utils import Py2Only, Py3Only import bottle @Py2Only @patch( 'bottle.response' ) def SetResponseHeader_Py2CorrectTypesWithStr_test( *args ): bottle_utils.SetResponseHeader( 'foo', 'bar' ) eq_( bottle.response.set_header.call_args, call( 'foo', u'bar' ) ) @Py2Only @patch( 'bottle.response' ) def SetResponseHeader_Py2CorrectTypesWithUnicode_test( *args ): bottle_utils.SetResponseHeader( u'foo', u'bar' ) eq_( bottle.response.set_header.call_args, call( 'foo', u'bar' ) ) @Py3Only @patch( 'bottle.response' ) def SetResponseHeader_Py3CorrectTypesWithBytes_test( *args ): bottle_utils.SetResponseHeader( b'foo', b'bar' ) eq_( bottle.response.set_header.call_args, call( u'foo', u'bar' ) ) @Py3Only @patch( 'bottle.response' ) def SetResponseHeader_Py3CorrectTypesWithUnicode_test( *args ): bottle_utils.SetResponseHeader( u'foo', u'bar' ) eq_( bottle.response.set_header.call_args, call( u'foo', u'bar' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/utils_test.py0000644000175000017500000003504613026170313021036 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2016 ycmd contributors. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . # Intentionally not importing unicode_literals! from __future__ import division from __future__ import print_function from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os import subprocess import tempfile import ycm_core from future.utils import native from mock import patch, call from nose.tools import eq_, ok_, raises from ycmd import utils from ycmd.tests.test_utils import ( Py2Only, Py3Only, WindowsOnly, UnixOnly, CurrentWorkingDirectory, TemporaryExecutable ) from ycmd.tests import PathToTestFile # NOTE: isinstance() vs type() is carefully used in this test file. Before # changing things here, read the comments in utils.ToBytes. @Py2Only def ToBytes_Py2Bytes_test(): value = utils.ToBytes( bytes( 'abc' ) ) eq_( value, bytes( 'abc' ) ) eq_( type( value ), bytes ) @Py2Only def ToBytes_Py2Str_test(): value = utils.ToBytes( 'abc' ) eq_( value, bytes( 'abc' ) ) eq_( type( value ), bytes ) @Py2Only def ToBytes_Py2FutureStr_test(): value = utils.ToBytes( str( 'abc' ) ) eq_( value, bytes( 'abc' ) ) eq_( type( value ), bytes ) @Py2Only def ToBytes_Py2Unicode_test(): value = utils.ToBytes( u'abc' ) eq_( value, bytes( 'abc' ) ) eq_( type( value ), bytes ) @Py2Only def ToBytes_Py2Int_test(): value = utils.ToBytes( 123 ) eq_( value, bytes( '123' ) ) eq_( type( value ), bytes ) def ToBytes_Bytes_test(): value = utils.ToBytes( bytes( b'abc' ) ) eq_( value, bytes( b'abc' ) ) eq_( type( value ), bytes ) def ToBytes_Str_test(): value = utils.ToBytes( u'abc' ) eq_( value, bytes( b'abc' ) ) eq_( type( value ), bytes ) def ToBytes_Int_test(): value = utils.ToBytes( 123 ) eq_( value, bytes( b'123' ) ) eq_( type( value ), bytes ) def ToBytes_None_test(): value = utils.ToBytes( None ) eq_( value, bytes( b'' ) ) eq_( type( value ), bytes ) @Py2Only def ToUnicode_Py2Bytes_test(): value = utils.ToUnicode( bytes( 'abc' ) ) eq_( value, u'abc' ) ok_( isinstance( value, str ) ) @Py2Only def ToUnicode_Py2Str_test(): value = utils.ToUnicode( 'abc' ) eq_( value, u'abc' ) ok_( isinstance( value, str ) ) @Py2Only def ToUnicode_Py2FutureStr_test(): value = utils.ToUnicode( str( 'abc' ) ) eq_( value, u'abc' ) ok_( isinstance( value, str ) ) @Py2Only def ToUnicode_Py2Unicode_test(): value = utils.ToUnicode( u'abc' ) eq_( value, u'abc' ) ok_( isinstance( value, str ) ) @Py2Only def ToUnicode_Py2Int_test(): value = utils.ToUnicode( 123 ) eq_( value, u'123' ) ok_( isinstance( value, str ) ) def ToUnicode_Bytes_test(): value = utils.ToUnicode( bytes( b'abc' ) ) eq_( value, u'abc' ) ok_( isinstance( value, str ) ) def ToUnicode_Str_test(): value = utils.ToUnicode( u'abc' ) eq_( value, u'abc' ) ok_( isinstance( value, str ) ) def ToUnicode_Int_test(): value = utils.ToUnicode( 123 ) eq_( value, u'123' ) ok_( isinstance( value, str ) ) def ToUnicode_None_test(): value = utils.ToUnicode( None ) eq_( value, u'' ) ok_( isinstance( value, str ) ) @Py2Only def JoinLinesAsUnicode_Py2Bytes_test(): value = utils.JoinLinesAsUnicode( [ bytes( 'abc' ), bytes( 'xyz' ) ] ) eq_( value, u'abc\nxyz' ) ok_( isinstance( value, str ) ) @Py2Only def JoinLinesAsUnicode_Py2Str_test(): value = utils.JoinLinesAsUnicode( [ 'abc', 'xyz' ] ) eq_( value, u'abc\nxyz' ) ok_( isinstance( value, str ) ) @Py2Only def JoinLinesAsUnicode_Py2FutureStr_test(): value = utils.JoinLinesAsUnicode( [ str( 'abc' ), str( 'xyz' ) ] ) eq_( value, u'abc\nxyz' ) ok_( isinstance( value, str ) ) @Py2Only def JoinLinesAsUnicode_Py2Unicode_test(): value = utils.JoinLinesAsUnicode( [ u'abc', u'xyz' ] ) eq_( value, u'abc\nxyz' ) ok_( isinstance( value, str ) ) def JoinLinesAsUnicode_Bytes_test(): value = utils.JoinLinesAsUnicode( [ bytes( b'abc' ), bytes( b'xyz' ) ] ) eq_( value, u'abc\nxyz' ) ok_( isinstance( value, str ) ) def JoinLinesAsUnicode_Str_test(): value = utils.JoinLinesAsUnicode( [ u'abc', u'xyz' ] ) eq_( value, u'abc\nxyz' ) ok_( isinstance( value, str ) ) def JoinLinesAsUnicode_EmptyList_test(): value = utils.JoinLinesAsUnicode( [ ] ) eq_( value, u'' ) ok_( isinstance( value, str ) ) @raises( ValueError ) def JoinLinesAsUnicode_BadInput_test(): utils.JoinLinesAsUnicode( [ 42 ] ) @Py2Only def ToCppStringCompatible_Py2Str_test(): value = utils.ToCppStringCompatible( 'abc' ) eq_( value, 'abc' ) eq_( type( value ), type( '' ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], 'abc' ) @Py2Only def ToCppStringCompatible_Py2Bytes_test(): value = utils.ToCppStringCompatible( bytes( b'abc' ) ) eq_( value, 'abc' ) eq_( type( value ), type( '' ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], 'abc' ) @Py2Only def ToCppStringCompatible_Py2Unicode_test(): value = utils.ToCppStringCompatible( u'abc' ) eq_( value, 'abc' ) eq_( type( value ), type( '' ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], 'abc' ) @Py2Only def ToCppStringCompatible_Py2Int_test(): value = utils.ToCppStringCompatible( 123 ) eq_( value, '123' ) eq_( type( value ), type( '' ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], '123' ) @Py3Only def ToCppStringCompatible_Py3Bytes_test(): value = utils.ToCppStringCompatible( bytes( b'abc' ) ) eq_( value, bytes( b'abc' ) ) ok_( isinstance( value, bytes ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], 'abc' ) @Py3Only def ToCppStringCompatible_Py3Str_test(): value = utils.ToCppStringCompatible( 'abc' ) eq_( value, bytes( b'abc' ) ) ok_( isinstance( value, bytes ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], 'abc' ) @Py3Only def ToCppStringCompatible_Py3Int_test(): value = utils.ToCppStringCompatible( 123 ) eq_( value, bytes( b'123' ) ) ok_( isinstance( value, bytes ) ) vector = ycm_core.StringVector() vector.append( value ) eq_( vector[ 0 ], '123' ) def RemoveIfExists_Exists_test(): tempfile = PathToTestFile( 'remove-if-exists' ) open( tempfile, 'a' ).close() ok_( os.path.exists( tempfile ) ) utils.RemoveIfExists( tempfile ) ok_( not os.path.exists( tempfile ) ) def RemoveIfExists_DoesntExist_test(): tempfile = PathToTestFile( 'remove-if-exists' ) ok_( not os.path.exists( tempfile ) ) utils.RemoveIfExists( tempfile ) ok_( not os.path.exists( tempfile ) ) def PathToFirstExistingExecutable_Basic_test(): if utils.OnWindows(): ok_( utils.PathToFirstExistingExecutable( [ 'notepad.exe' ] ) ) else: ok_( utils.PathToFirstExistingExecutable( [ 'cat' ] ) ) def PathToFirstExistingExecutable_Failure_test(): ok_( not utils.PathToFirstExistingExecutable( [ 'ycmd-foobar' ] ) ) @UnixOnly @patch( 'subprocess.Popen' ) def SafePopen_RemoveStdinWindows_test( *args ): utils.SafePopen( [ 'foo' ], stdin_windows = 'bar' ) eq_( subprocess.Popen.call_args, call( [ 'foo' ] ) ) @WindowsOnly @patch( 'subprocess.Popen' ) def SafePopen_ReplaceStdinWindowsPIPEOnWindows_test( *args ): utils.SafePopen( [ 'foo' ], stdin_windows = subprocess.PIPE ) eq_( subprocess.Popen.call_args, call( [ 'foo' ], stdin = subprocess.PIPE, creationflags = utils.CREATE_NO_WINDOW ) ) @WindowsOnly @patch( 'ycmd.utils.GetShortPathName', side_effect = lambda x: x ) @patch( 'subprocess.Popen' ) def SafePopen_WindowsPath_test( *args ): tempfile = PathToTestFile( 'safe-popen-file' ) open( tempfile, 'a' ).close() try: utils.SafePopen( [ 'foo', tempfile ], stdin_windows = subprocess.PIPE ) eq_( subprocess.Popen.call_args, call( [ 'foo', tempfile ], stdin = subprocess.PIPE, creationflags = utils.CREATE_NO_WINDOW ) ) finally: os.remove( tempfile ) @UnixOnly def ConvertArgsToShortPath_PassthroughOnUnix_test( *args ): eq_( 'foo', utils.ConvertArgsToShortPath( 'foo' ) ) eq_( [ 'foo' ], utils.ConvertArgsToShortPath( [ 'foo' ] ) ) @UnixOnly def SetEnviron_UnicodeOnUnix_test( *args ): env = {} utils.SetEnviron( env, u'key', u'value' ) eq_( env, { u'key': u'value' } ) @Py2Only @WindowsOnly def SetEnviron_UnicodeOnWindows_test( *args ): env = {} utils.SetEnviron( env, u'key', u'value' ) eq_( env, { native( bytes( b'key' ) ): native( bytes( b'value' ) ) } ) def PathsToAllParentFolders_Basic_test(): eq_( [ os.path.normpath( '/home/user/projects' ), os.path.normpath( '/home/user' ), os.path.normpath( '/home' ), os.path.normpath( '/' ) ], list( utils.PathsToAllParentFolders( '/home/user/projects/test.c' ) ) ) @patch( 'os.path.isdir', return_value = True ) def PathsToAllParentFolders_IsDirectory_test( *args ): eq_( [ os.path.normpath( '/home/user/projects' ), os.path.normpath( '/home/user' ), os.path.normpath( '/home' ), os.path.normpath( '/' ) ], list( utils.PathsToAllParentFolders( '/home/user/projects' ) ) ) def PathsToAllParentFolders_FileAtRoot_test(): eq_( [ os.path.normpath( '/' ) ], list( utils.PathsToAllParentFolders( '/test.c' ) ) ) @WindowsOnly def PathsToAllParentFolders_WindowsPath_test(): eq_( [ os.path.normpath( r'C:\\foo\\goo\\zoo' ), os.path.normpath( r'C:\\foo\\goo' ), os.path.normpath( r'C:\\foo' ), os.path.normpath( r'C:\\' ) ], list( utils.PathsToAllParentFolders( r'C:\\foo\\goo\\zoo\\test.c' ) ) ) def OpenForStdHandle_PrintDoesntThrowException_test(): try: temp = PathToTestFile( 'open-for-std-handle' ) with utils.OpenForStdHandle( temp ) as f: print( 'foo', file = f ) finally: os.remove( temp ) def CodepointOffsetToByteOffset_test(): # Tuples of ( ( unicode_line_value, codepoint_offset ), expected_result ). tests = [ # Simple ascii strings. ( ( 'test', 1 ), 1 ), ( ( 'test', 4 ), 4 ), ( ( 'test', 5 ), 5 ), # Unicode char at beginning. ( ( '†est', 1 ), 1 ), ( ( '†est', 2 ), 4 ), ( ( '†est', 4 ), 6 ), ( ( '†est', 5 ), 7 ), # Unicode char at end. ( ( 'tes†', 1 ), 1 ), ( ( 'tes†', 2 ), 2 ), ( ( 'tes†', 4 ), 4 ), ( ( 'tes†', 5 ), 7 ), # Unicode char in middle. ( ( 'tes†ing', 1 ), 1 ), ( ( 'tes†ing', 2 ), 2 ), ( ( 'tes†ing', 4 ), 4 ), ( ( 'tes†ing', 5 ), 7 ), ( ( 'tes†ing', 7 ), 9 ), ( ( 'tes†ing', 8 ), 10 ), # Converts bytes to Unicode. ( ( utils.ToBytes( '†est' ), 2 ), 4 ) ] for test in tests: yield lambda: eq_( utils.CodepointOffsetToByteOffset( *test[ 0 ] ), test[ 1 ] ) def ByteOffsetToCodepointOffset_test(): # Tuples of ( ( unicode_line_value, byte_offset ), expected_result ). tests = [ # Simple ascii strings. ( ( 'test', 1 ), 1 ), ( ( 'test', 4 ), 4 ), ( ( 'test', 5 ), 5 ), # Unicode char at beginning. ( ( '†est', 1 ), 1 ), ( ( '†est', 4 ), 2 ), ( ( '†est', 6 ), 4 ), ( ( '†est', 7 ), 5 ), # Unicode char at end. ( ( 'tes†', 1 ), 1 ), ( ( 'tes†', 2 ), 2 ), ( ( 'tes†', 4 ), 4 ), ( ( 'tes†', 7 ), 5 ), # Unicode char in middle. ( ( 'tes†ing', 1 ), 1 ), ( ( 'tes†ing', 2 ), 2 ), ( ( 'tes†ing', 4 ), 4 ), ( ( 'tes†ing', 7 ), 5 ), ( ( 'tes†ing', 9 ), 7 ), ( ( 'tes†ing', 10 ), 8 ), ] for test in tests: yield lambda: eq_( utils.ByteOffsetToCodepointOffset( *test[ 0 ] ), test[ 1 ] ) def SplitLines_test(): # Tuples of ( input, expected_output ) for utils.SplitLines. tests = [ ( '', [ '' ] ), ( ' ', [ ' ' ] ), ( '\n', [ '', '' ] ), ( ' \n', [ ' ', '' ] ), ( ' \n ', [ ' ', ' ' ] ), ( 'test\n', [ 'test', '' ] ), ( '\r', [ '', '' ] ), ( '\r ', [ '', ' ' ] ), ( 'test\r', [ 'test', '' ] ), ( '\n\r', [ '', '', '' ] ), ( '\r\n', [ '', '' ] ), ( '\r\n\n', [ '', '', '' ] ), # Other behaviors are just the behavior of splitlines, so just a couple of # tests to prove that we don't mangle it. ( 'test\ntesting', [ 'test', 'testing' ] ), ( '\ntesting', [ '', 'testing' ] ), ] for test in tests: yield lambda: eq_( utils.SplitLines( test[ 0 ] ), test[ 1 ] ) def FindExecutable_AbsolutePath_test(): with TemporaryExecutable() as executable: eq_( executable, utils.FindExecutable( executable ) ) def FindExecutable_RelativePath_test(): with TemporaryExecutable() as executable: dirname, exename = os.path.split( executable ) relative_executable = os.path.join( '.', exename ) with CurrentWorkingDirectory( dirname ): eq_( relative_executable, utils.FindExecutable( relative_executable ) ) @patch.dict( 'os.environ', { 'PATH': tempfile.gettempdir() } ) def FindExecutable_ExecutableNameInPath_test(): with TemporaryExecutable() as executable: dirname, exename = os.path.split( executable ) eq_( executable, utils.FindExecutable( exename ) ) def FindExecutable_ReturnNoneIfFileIsNotExecutable_test(): with tempfile.NamedTemporaryFile() as non_executable: eq_( None, utils.FindExecutable( non_executable.name ) ) @WindowsOnly def FindExecutable_CurrentDirectory_test(): with TemporaryExecutable() as executable: dirname, exename = os.path.split( executable ) with CurrentWorkingDirectory( dirname ): eq_( executable, utils.FindExecutable( exename ) ) @WindowsOnly @patch.dict( 'os.environ', { 'PATHEXT': '.xyz' } ) def FindExecutable_AdditionalPathExt_test(): with TemporaryExecutable( extension = '.xyz' ) as executable: eq_( executable, utils.FindExecutable( executable ) ) @Py2Only def GetCurrentDirectory_Py2NoCurrentDirectory_test(): with patch( 'os.getcwdu', side_effect = OSError ): eq_( utils.GetCurrentDirectory(), tempfile.gettempdir() ) @Py3Only def GetCurrentDirectory_Py3NoCurrentDirectory_test(): with patch( 'os.getcwd', side_effect = FileNotFoundError ): # noqa eq_( utils.GetCurrentDirectory(), tempfile.gettempdir() ) ycmd-0+20161219+git486b809.orig/ycmd/tests/server_utils_test.py0000644000175000017500000002077413026170313022426 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, calling, contains, contains_inanyorder, empty, equal_to, has_length, raises ) from mock import patch from nose.tools import ok_ import os.path import sys from ycmd.server_utils import ( AddNearestThirdPartyFoldersToSysPath, CompatibleWithCurrentCore, PathToNearestThirdPartyFolder ) from ycmd.tests import PathToTestFile DIR_OF_THIRD_PARTY = os.path.abspath( os.path.join( os.path.dirname( __file__ ), '..', '..', 'third_party' ) ) THIRD_PARTY_FOLDERS = ( os.path.join( DIR_OF_THIRD_PARTY, 'argparse' ), os.path.join( DIR_OF_THIRD_PARTY, 'bottle' ), os.path.join( DIR_OF_THIRD_PARTY, 'frozendict' ), os.path.join( DIR_OF_THIRD_PARTY, 'godef' ), os.path.join( DIR_OF_THIRD_PARTY, 'gocode' ), os.path.join( DIR_OF_THIRD_PARTY, 'JediHTTP' ), os.path.join( DIR_OF_THIRD_PARTY, 'OmniSharpServer' ), os.path.join( DIR_OF_THIRD_PARTY, 'racerd' ), os.path.join( DIR_OF_THIRD_PARTY, 'requests' ), os.path.join( DIR_OF_THIRD_PARTY, 'tern_runtime' ), os.path.join( DIR_OF_THIRD_PARTY, 'waitress' ) ) @patch( 'ycmd.server_utils._logger', autospec = True ) def RunCompatibleWithCurrentCoreImportException( test, logger ): with patch( 'ycmd.server_utils.ImportCore', side_effect = ImportError( test[ 'exception_message' ] ) ): assert_that( CompatibleWithCurrentCore(), equal_to( test[ 'exit_status' ] ) ) assert_that( logger.method_calls, has_length( 1 ) ) logger.exception.assert_called_with( test[ 'logged_message' ] ) @patch( 'ycmd.server_utils._logger', autospec = True ) def CompatibleWithCurrentCore_Compatible_test( logger ): assert_that( CompatibleWithCurrentCore(), equal_to( 0 ) ) assert_that( logger.method_calls, empty() ) def CompatibleWithCurrentCore_Unexpected_test(): RunCompatibleWithCurrentCoreImportException( { 'exception_message': 'unexpected import exception', 'exit_status': 3, 'logged_message': 'unexpected import exception' } ) def CompatibleWithCurrentCore_Missing_test(): import_errors = [ # Raised by Python 2. 'No module named ycm_core', # Raised by Python 3. "No module named 'ycm_core'" ] for error in import_errors: yield RunCompatibleWithCurrentCoreImportException, { 'exception_message': error, 'exit_status': 4, 'logged_message': 'ycm_core library not detected; you need to compile it ' 'by running the build.py script. See the documentation ' 'for more details.' } def CompatibleWithCurrentCore_Python2_test(): import_exception_messages = [ # Raised on Linux and OS X with Python 3.3 and 3.4. 'dynamic module does not define init function (PyInit_ycm_core).', # Raised on Linux and OS X with Python 3.5. 'dynamic module does not define module export function (PyInit_ycm_core).', # Raised on Windows. 'Module use of python26.dll conflicts with this version of Python.', 'Module use of python27.dll conflicts with this version of Python.' ] for message in import_exception_messages: yield RunCompatibleWithCurrentCoreImportException, { 'exception_message': message, 'exit_status': 5, 'logged_message': 'ycm_core library compiled for Python 2 ' 'but loaded in Python 3.' } def CompatibleWithCurrentCore_Python3_test(): import_exception_messages = [ # Raised on Linux and OS X. 'dynamic module does not define init function (initycm_core).', # Raised on Windows. 'Module use of python34.dll conflicts with this version of Python.', 'Module use of python35.dll conflicts with this version of Python.' ] for message in import_exception_messages: yield RunCompatibleWithCurrentCoreImportException, { 'exception_message': message, 'exit_status': 6, 'logged_message': 'ycm_core library compiled for Python 3 ' 'but loaded in Python 2.' } @patch( 'ycm_core.YcmCoreVersion', side_effect = AttributeError() ) @patch( 'ycmd.server_utils._logger', autospec = True ) def CompatibleWithCurrentCore_Outdated_NoYcmCoreVersionMethod_test( logger, *args ): assert_that( CompatibleWithCurrentCore(), equal_to( 7 ) ) assert_that( logger.method_calls, has_length( 1 ) ) logger.exception.assert_called_with( 'ycm_core library too old; PLEASE RECOMPILE by running the build.py ' 'script. See the documentation for more details.' ) @patch( 'ycm_core.YcmCoreVersion', return_value = 10 ) @patch( 'ycmd.server_utils.ExpectedCoreVersion', return_value = 11 ) @patch( 'ycmd.server_utils._logger', autospec = True ) def CompatibleWithCurrentCore_Outdated_NoVersionMatch_test( logger, *args ): assert_that( CompatibleWithCurrentCore(), equal_to( 7 ) ) assert_that( logger.method_calls, has_length( 1 ) ) logger.error.assert_called_with( 'ycm_core library too old; PLEASE RECOMPILE by running the build.py ' 'script. See the documentation for more details.' ) def PathToNearestThirdPartyFolder_Success_test(): ok_( PathToNearestThirdPartyFolder( os.path.abspath( __file__ ) ) ) def PathToNearestThirdPartyFolder_Failure_test(): ok_( not PathToNearestThirdPartyFolder( os.path.expanduser( '~' ) ) ) def AddNearestThirdPartyFoldersToSysPath_Failure_test(): assert_that( calling( AddNearestThirdPartyFoldersToSysPath ).with_args( os.path.expanduser( '~' ) ), raises( RuntimeError, '.*third_party folder.*' ) ) @patch( 'sys.path', [ PathToTestFile( 'python-future', 'some', 'path' ), PathToTestFile( 'python-future', 'standard_library' ), PathToTestFile( 'python-future', 'standard_library', 'site-packages' ), PathToTestFile( 'python-future', 'another', 'path' ) ] ) def AddNearestThirdPartyFoldersToSysPath_FutureAfterStandardLibrary_test( *args ): AddNearestThirdPartyFoldersToSysPath( __file__ ) assert_that( sys.path[ : len( THIRD_PARTY_FOLDERS ) ], contains_inanyorder( *THIRD_PARTY_FOLDERS ) ) assert_that( sys.path[ len( THIRD_PARTY_FOLDERS ) : ], contains( PathToTestFile( 'python-future', 'some', 'path' ), PathToTestFile( 'python-future', 'standard_library' ), os.path.join( DIR_OF_THIRD_PARTY, 'python-future', 'src' ), PathToTestFile( 'python-future', 'standard_library', 'site-packages' ), PathToTestFile( 'python-future', 'another', 'path' ) ) ) @patch( 'sys.path', [ PathToTestFile( 'python-future', 'some', 'path' ), PathToTestFile( 'python-future', 'another', 'path' ) ] ) def AddNearestThirdPartyFoldersToSysPath_ErrorIfNoStandardLibrary_test( *args ): assert_that( calling( AddNearestThirdPartyFoldersToSysPath ).with_args( __file__ ), raises( RuntimeError, 'Could not find standard library path in Python path.' ) ) @patch( 'sys.path', [ PathToTestFile( 'python-future', 'some', 'path' ), PathToTestFile( 'python-future', 'virtualenv_library' ), PathToTestFile( 'python-future', 'standard_library' ), PathToTestFile( 'python-future', 'another', 'path' ) ] ) def AddNearestThirdPartyFoldersToSysPath_IgnoreVirtualEnvLibrary_test( *args ): AddNearestThirdPartyFoldersToSysPath( __file__ ) assert_that( sys.path[ : len( THIRD_PARTY_FOLDERS ) ], contains_inanyorder( *THIRD_PARTY_FOLDERS ) ) assert_that( sys.path[ len( THIRD_PARTY_FOLDERS ) : ], contains( PathToTestFile( 'python-future', 'some', 'path' ), PathToTestFile( 'python-future', 'virtualenv_library' ), PathToTestFile( 'python-future', 'standard_library' ), os.path.join( DIR_OF_THIRD_PARTY, 'python-future', 'src' ), PathToTestFile( 'python-future', 'another', 'path' ) ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/__init__.py0000644000175000017500000000364713026170313020400 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd.tests.test_utils import ClearCompletionsCache, SetUpApp shared_app = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/extra_conf_store_test.py0000644000175000017500000001705013026170313023235 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import inspect from mock import patch from hamcrest import ( assert_that, calling, equal_to, has_length, none, raises, same_instance ) from ycmd import extra_conf_store from ycmd.responses import UnknownExtraConf from ycmd.tests import PathToTestFile from ycmd.tests.test_utils import UserOption class ExtraConfStore_test(): def setUp( self ): extra_conf_store.Reset() def ModuleForSourceFile_UnknownExtraConf_test( self ): filename = PathToTestFile( 'extra_conf', 'project', 'some_file' ) assert_that( calling( extra_conf_store.ModuleForSourceFile ).with_args( filename ), raises( UnknownExtraConf, 'Found .*\.ycm_extra_conf\.py\. Load?' ) ) def ModuleForSourceFile_NoConfirmation_test( self ): filename = PathToTestFile( 'extra_conf', 'project', 'some_file' ) extra_conf_file = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) with UserOption( 'confirm_extra_conf', 0 ): module = extra_conf_store.ModuleForSourceFile( filename ) assert_that( inspect.ismodule( module ) ) assert_that( inspect.getfile( module ), equal_to( extra_conf_file ) ) def ModuleForSourceFile_Whitelisted_test( self ): filename = PathToTestFile( 'extra_conf', 'project', 'some_file' ) extra_conf_file = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) with UserOption( 'extra_conf_globlist', [ extra_conf_file ] ): module = extra_conf_store.ModuleForSourceFile( filename ) assert_that( inspect.ismodule( module ) ) assert_that( inspect.getfile( module ), equal_to( extra_conf_file ) ) def ModuleForSourceFile_Blacklisted_test( self ): filename = PathToTestFile( 'extra_conf', 'project', 'some_file' ) extra_conf_file = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) with UserOption( 'extra_conf_globlist', [ '!' + extra_conf_file ] ): assert_that( extra_conf_store.ModuleForSourceFile( filename ), none() ) def ModuleForSourceFile_GlobalExtraConf_test( self ): filename = PathToTestFile( 'extra_conf', 'some_file' ) extra_conf_file = PathToTestFile( 'extra_conf', 'global_extra_conf.py' ) with UserOption( 'global_ycm_extra_conf', extra_conf_file ): module = extra_conf_store.ModuleForSourceFile( filename ) assert_that( inspect.ismodule( module ) ) assert_that( inspect.getfile( module ), equal_to( extra_conf_file ) ) @patch( 'ycmd.extra_conf_store._logger', autospec = True ) def CallGlobalExtraConfMethod_NoGlobalExtraConf_test( self, logger ): with UserOption( 'global_ycm_extra_conf', PathToTestFile( 'extra_conf', 'no_extra_conf.py' ) ): extra_conf_store._CallGlobalExtraConfMethod( 'SomeMethod' ) assert_that( logger.method_calls, has_length( 1 ) ) logger.debug.assert_called_with( 'No global extra conf, not calling method ' 'SomeMethod' ) @patch( 'ycmd.extra_conf_store._logger', autospec = True ) def CallGlobalExtraConfMethod_NoMethodInGlobalExtraConf_test( self, logger ): with UserOption( 'global_ycm_extra_conf', PathToTestFile( 'extra_conf', 'global_extra_conf.py' ) ): extra_conf_store._CallGlobalExtraConfMethod( 'MissingMethod' ) assert_that( logger.method_calls, has_length( 1 ) ) logger.debug.assert_called_with( 'Global extra conf not loaded or ' 'no function MissingMethod' ) @patch( 'ycmd.extra_conf_store._logger', autospec = True ) def CallGlobalExtraConfMethod_NoExceptionFromMethod_test( self, logger ): extra_conf_file = PathToTestFile( 'extra_conf', 'global_extra_conf.py' ) with UserOption( 'global_ycm_extra_conf', extra_conf_file ): extra_conf_store._CallGlobalExtraConfMethod( 'NoException' ) assert_that( logger.method_calls, has_length( 1 ) ) logger.info.assert_called_with( 'Calling global extra conf method ' 'NoException on conf file ' '{0}'.format( extra_conf_file ) ) @patch( 'ycmd.extra_conf_store._logger', autospec = True ) def CallGlobalExtraConfMethod_CatchExceptionFromMethod_test( self, logger ): extra_conf_file = PathToTestFile( 'extra_conf', 'global_extra_conf.py' ) with UserOption( 'global_ycm_extra_conf', extra_conf_file ): extra_conf_store._CallGlobalExtraConfMethod( 'RaiseException' ) assert_that( logger.method_calls, has_length( 2 ) ) logger.info.assert_called_with( 'Calling global extra conf method ' 'RaiseException on conf file ' '{0}'.format( extra_conf_file ) ) logger.exception.assert_called_with( 'Error occurred while calling global extra conf method RaiseException ' 'on conf file {0}'.format( extra_conf_file ) ) @patch( 'ycmd.extra_conf_store._logger', autospec = True ) def CallGlobalExtraConfMethod_CatchExceptionFromExtraConf_test( self, logger ): extra_conf_file = PathToTestFile( 'extra_conf', 'erroneous_extra_conf.py' ) with UserOption( 'global_ycm_extra_conf', extra_conf_file ): extra_conf_store._CallGlobalExtraConfMethod( 'NoException' ) assert_that( logger.method_calls, has_length( 1 ) ) logger.exception.assert_called_with( 'Error occurred while ' 'loading global extra conf ' '{0}'.format( extra_conf_file ) ) def Load_DoNotReloadExtraConf_NoForce_test( self ): extra_conf_file = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) with patch( 'ycmd.extra_conf_store._ShouldLoad', return_value = True ): module = extra_conf_store.Load( extra_conf_file ) assert_that( inspect.ismodule( module ) ) assert_that( inspect.getfile( module ), equal_to( extra_conf_file ) ) assert_that( extra_conf_store.Load( extra_conf_file ), same_instance( module ) ) def Load_DoNotReloadExtraConf_ForceEqualsTrue_test( self ): extra_conf_file = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) with patch( 'ycmd.extra_conf_store._ShouldLoad', return_value = True ): module = extra_conf_store.Load( extra_conf_file ) assert_that( inspect.ismodule( module ) ) assert_that( inspect.getfile( module ), equal_to( extra_conf_file ) ) assert_that( extra_conf_store.Load( extra_conf_file, force = True ), same_instance( module ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/0000755000175000017500000000000013026170313017252 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/rust/testdata/0000755000175000017500000000000013026170313021063 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/rust/testdata/std_completions.rs0000644000175000017500000000013113026170313024632 0ustar onuronuruse std::path::Path; pub fn main() { let program = Path::new( "/foo" ); program. } ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/testdata/test.rs0000644000175000017500000000031713026170313022411 0ustar onuronurpub fn create_universe() { } pub fn build_rocket() { } pub fn build_shuttle() { } pub fn main() { // Identifier here can be used for GoTo test create_universe(); // Test completion build_ } ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/testdata/docs.rs0000644000175000017500000000015613026170313022363 0ustar onuronurmod t { /// some docs on a function pub fn fun() { } } pub fn main() { t::fun(); t::dne(); } ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/get_completions_test.py0000644000175000017500000001101313026170313024052 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, empty, has_entry, has_items from nose.tools import eq_ from mock import patch from ycmd.completers.rust.rust_completer import ( ERROR_FROM_RACERD_MESSAGE, NON_EXISTING_RUST_SOURCES_PATH_MESSAGE ) from ycmd.tests.rust import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, ErrorMatcher, UserOption, WaitUntilCompleterServerReady ) from ycmd.utils import ReadFile import requests @SharedYcmd def GetCompletions_Basic_test( app ): filepath = PathToTestFile( 'test.rs' ) contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'rust', contents = contents, force_semantic = True, line_num = 9, column_num = 11 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'build_rocket' ), CompletionEntryMatcher( 'build_shuttle' ) ) ) # This test is isolated because it affects the GoTo tests, although it # shouldn't. @IsolatedYcmd def GetCompletions_WhenStandardLibraryCompletionFails_MentionRustSrcPath_test( app ): WaitUntilCompleterServerReady( app, 'rust' ) filepath = PathToTestFile( 'std_completions.rs' ) contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'rust', contents = contents, force_semantic = True, line_num = 5, column_num = 11 ) response = app.post_json( '/completions', completion_data, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, ERROR_FROM_RACERD_MESSAGE ) ) @IsolatedYcmd def GetCompletions_NonExistingRustSrcPathFromUserOption_test( app ): with UserOption( 'rust_src_path', '/non/existing/rust/src/path' ): response = app.get( '/ready', { 'subserver': 'rust' }, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, NON_EXISTING_RUST_SOURCES_PATH_MESSAGE ) ) @IsolatedYcmd @patch.dict( 'os.environ', { 'RUST_SRC_PATH': '/non/existing/rust/src/path' } ) def GetCompletions_NonExistingRustSrcPathFromEnvironmentVariable_test( app ): response = app.get( '/ready', { 'subserver': 'rust' }, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, NON_EXISTING_RUST_SOURCES_PATH_MESSAGE ) ) @SharedYcmd def GetCompletions_NoCompletionsFound_test( app ): filepath = PathToTestFile( 'test.rs' ) contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'rust', contents = contents, force_semantic = True, line_num = 4, column_num = 1 ) response = app.post_json( '/completions', completion_data ) eq_( response.status_code, requests.codes.ok ) assert_that( response.json, has_entry( 'completions', empty() ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/__init__.py0000644000175000017500000000612613026170313021370 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd import handlers from ycmd.tests.test_utils import ( ClearCompletionsCache, SetUpApp, StopCompleterServer, WaitUntilCompleterServerReady ) shared_app = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() WaitUntilCompleterServerReady( shared_app, 'rust' ) def tearDownPackage(): """Cleans up the tests using the SharedYcmd decorator in this package. It is executed once after running all the tests in the package.""" global shared_app StopCompleterServer( shared_app, 'rust' ) def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state app = SetUpApp() try: test( app, *args, **kwargs ) finally: StopCompleterServer( app, 'rust' ) handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/subcommands_test.py0000644000175000017500000000660713026170313023207 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_ from ycmd.tests.rust import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest from ycmd.utils import ReadFile @SharedYcmd def RunGoToTest( app, params ): filepath = PathToTestFile( 'test.rs' ) contents = ReadFile( filepath ) command = params[ 'command' ] goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ command ], line_num = 7, column_num = 12, contents = contents, filetype = 'rust', filepath = filepath ) results = app.post_json( '/run_completer_command', goto_data ) eq_( { 'line_num': 1, 'column_num': 8, 'filepath': filepath }, results.json ) def Subcommands_GoTo_all_test(): tests = [ { 'command': 'GoTo' }, { 'command': 'GoToDefinition' }, { 'command': 'GoToDeclaration' } ] for test in tests: yield RunGoToTest, test @SharedYcmd def Subcommands_GetDoc_Method_test( app ): filepath = PathToTestFile( 'docs.rs' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'rust', line_num = 7, column_num = 9, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json eq_( response, { 'detailed_info': 'pub fn fun()\n---\n' 'some docs on a function' } ) @SharedYcmd def Subcommands_GetDoc_Fail_Method_test( app ): filepath = PathToTestFile( 'docs.rs' ) contents = ReadFile( filepath ) # no docs exist for this function event_data = BuildRequest( filepath = filepath, filetype = 'rust', line_num = 8, column_num = 9, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors=True ).json eq_( response[ 'exception' ][ 'TYPE' ], 'RuntimeError' ) eq_( response[ 'message' ], 'Can\'t lookup docs.' ) ycmd-0+20161219+git486b809.orig/ycmd/tests/rust/debug_info_test.py0000644000175000017500000000534313026170313022771 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, matches_regexp from ycmd.tests.rust import IsolatedYcmd, SharedYcmd from ycmd.tests.test_utils import BuildRequest, StopCompleterServer, UserOption @SharedYcmd def DebugInfo_ServerIsRunning_test( app ): request_data = BuildRequest( filetype = 'rust' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Rust completer debug information:\n' ' Racerd running at: http://127.0.0.1:\d+\n' ' Racerd process ID: \d+\n' ' Racerd executable: .+\n' ' Racerd logfiles:\n' ' .+\n' ' .+\n' ' Rust sources: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesExist_test( app ): with UserOption( 'server_keep_logfiles', True ): StopCompleterServer( app, 'rust' ) request_data = BuildRequest( filetype = 'rust' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Rust completer debug information:\n' ' Racerd no longer running\n' ' Racerd executable: .+\n' ' Racerd logfiles:\n' ' .+\n' ' .+\n' ' Rust sources: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesDoNotExist_test( app ): with UserOption( 'server_keep_logfiles', False ): StopCompleterServer( app, 'rust' ) request_data = BuildRequest( filetype = 'rust' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Rust completer debug information:\n' ' Racerd is not running\n' ' Racerd executable: .+\n' ' Rust sources: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/0000755000175000017500000000000013026170313017341 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/0000755000175000017500000000000013026170313021152 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/multiple_missing_includes.cc0000644000175000017500000000010313026170313026725 0ustar onuronur#include "first_missing_include" #include "second_missing_include" ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/FixIt_Clang_cpp11.cpp0000644000175000017500000000341013026170313025007 0ustar onuronur// // A selection of the tests from llvm/tools/clang/test/FixIt/fixit-cxx0x.cpp // // Modified to test fixits across multiple lines and ensure that the number of // diagnostics doesn't hit the compile threshold. // /* This is a test of the various code modification hints that only apply in C++0x. */ struct A { explicit operator int(); // expected-note{{conversion to integral type}} }; // _FixIt_Check_cpp11_Ins (2 inserts on one line) void x() { switch(A()) { // expected-error{{explicit conversion to}} } } // _FixIt_Check_cpp11_InsMultiLine // same as above, except the 2 inserts split over multiple lines, neiher of // which are the *same* line as the diagnostic report (diagnostic on line // "switch", inserts on following line and later line void y() { switch( // diag A // insert: static_cast( ( ) // insert: ) ) { } } // _FixIt_Check_cpp11_Del using ::T = void; // expected-error {{name defined in alias declaration must be an identifier}} namespace dtor_fixit { class foo { // _FixIt_Check_cpp11_Repl ~bar() { } // expected-error {{expected the class name after '~' to name a destructor}} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:9}:"foo" }; class bar { ~bar(); }; // _FixIt_Check_cpp11_DelAdd ~bar::bar() {} // expected-error {{'~' in destructor name should be after nested name specifier}} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:4}:"" // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:9-[[@LINE-2]]:9}:"~" } namespace test_fixit_multiple { class foo { ~bar() { } }; class bar { ~bar(); }; ~bar::bar() { } } void z() { bool x; if ( x = true ) { } } namespace Typo { struct SpellingIsNotMyStrongPoint; } void typo() { Typo::SpellingIsNotMyStringPiont *p; } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/GetType_Clang_test.cc0000644000175000017500000000134713026170313025212 0ustar onuronur// This file is used in RunCompleterCommand_GetType_Clang_test namespace Ns { template< typename T > struct BasicType { BasicType( const T * ); }; typedef BasicType< char > Type; } struct Foo { int x; int y; char c; }; int main() { Foo foo; Ns::Type a = "hello"; Ns::Type b = a; auto &arFoo = foo; auto *apFoo = &foo; const auto &acrFoo = foo; const auto *acpFoo = &foo; int acry = acrFoo.y; int acpx = acpFoo->x; int ary = arFoo.y; int apx = apFoo->x; Foo &rFoo = foo; Foo *pFoo = &foo; const Foo &crFoo = foo; const Foo *cpFoo = &foo; int cry = crFoo.y; int cpx = cpFoo->x; int ry = rFoo.y; int px = pFoo->x; struct Unicøde; Unicøde *ø; return 0; } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/GetDoc_Clang.cc0000644000175000017500000000360013026170313023731 0ustar onuronur#include "GetDoc_Clang.h" /// This is a test namespace namespace Test { /// This is a global variable, that isn't really all that global. int a_global_variable; /// This is a method which is only pretend global /// @param test Set this to true. Do it. int get_a_global_variable( bool test ); char postfix_comment(); ///< Method postfix /** * This is not the brief. * * \brief brevity is for suckers * * This is more information */ char with_brief(); /** The * indentation * of this comment * is * all messed up. */ int messed_up(); } /// This really is a global variable. /// /// The first line of comment is the brief. char a_global_variable; /** JavaDoc-style */ bool javadoc_style; //! Qt-style bool qt_style; /// This method has lots of lines of text in its comment. /// /// That's important because the preview window /// /// Has /// /// Limited Space. char get_a_global_variable( ); bool postfix_comment; ///< The brief follows the declaration. typedef TestClass AnotherClass; // Double slash is not considered attached to declaration bool double_slash; /* slash asterisk is also not considered attached to declaration */ bool slash_asterisk; /** Main */ int main() { char c = get_a_global_variable( ); int i = Test::get_a_global_variable( true ); typedef int(*FUNCTION_POINTER)( bool ); FUNCTION_POINTER fp = &Test::get_a_global_variable; bool b = c == a_global_variable && i == Test::a_global_variable && javadoc_style && qt_style && postfix_comment && double_slash && slash_asterisk; TestClass tc; const AnotherClass& ac = tc; tc.a_public_method( tc.a_public_var ); tc.an_undocumented_method(); Test::postfix_comment(); Test::messed_up(); return b ? 0 : 1; } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/GoTo_all_Clang_test.cc0000644000175000017500000000076413026170313025333 0ustar onuronur// This file is used in RunCompleterCommand_GoTo_all_Clang_test namespace Local { int x; char in_line() { return 'y'; }; char out_of_line(); } char Local::out_of_line() { return 'x'; } int main(); int main() { int ix = Local::x; char cy = Local::in_line(); char cx = Local::out_of_line(); return 0; } void unicode() { /* †est ê */ struct Unicøde { int u; }; struct Another_Unicøde; Unicøde *ç; ç->u; Another_Unicøde *u; u; } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/FixIt_Clang_objc.m0000644000175000017500000000037213026170313024456 0ustar onuronur@protocol X; // _FixIt_Check_objc, _FixIt_Check_objc_NoFixIt void foo() { *P; // expected-warning{{protocol has no object type specified; defaults to qualified 'id'}} char *x = nullptr; // no fix-it for this error (nullptr undefinied) } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/.ycm_extra_conf.py0000644000175000017500000000011513026170313024577 0ustar onuronurdef FlagsForFile( filename ): return { 'flags': ['-x', 'c++', '-I', '.'] } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/GoTo_Clang_ZeroBasedLineAndColumn_test.cc0000644000175000017500000000024613026170313031045 0ustar onuronur// this file is used in RunCompleterCommand_GoTo_Clang_ZeroBasedLineAndColumn_test struct Foo { int x; int y; char c; }; int main() { Foo foo; return 0; } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/basic.cpp0000644000175000017500000000020113026170313022730 0ustar onuronurstruct Foo { int x; int y; char c; }; int main() { Foo foo; // The location after the dot is line 11, col 7 foo. } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/client_data/0000755000175000017500000000000013026170313023421 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/client_data/.ycm_extra_conf.py0000644000175000017500000000014113026170313027045 0ustar onuronurdef FlagsForFile( filename, **kwargs ): return { 'flags': kwargs[ 'client_data' ][ 'flags' ] } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/client_data/include.hpp0000644000175000017500000000000013026170313025543 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/client_data/main.cpp0000644000175000017500000000015513026170313025052 0ustar onuronurstruct Foo { int x; }; int main() { Foo foo; // The location after the dot is line 9, col 7 foo. } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/client_data/include.cpp0000644000175000017500000000001313026170313025542 0ustar onuronur#include " ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/general_fallback/0000755000175000017500000000000013026170313024406 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/general_fallback/lang_cpp.cc0000644000175000017500000000245013026170313026501 0ustar onuronurnamespace { struct TTest { static void PrintDiagnostic(); int a_parameter; int another_parameter; }: void do_something(int); void do_another_thing(int); // TESTCASE1: use of . on template argument. Templates used this way are // compile-time duck typing template void DO_SOMETHING_TO( T& t ) { /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ do_something( t.a_parameter ); } // TESTCASE2: use of -> on template argument. Templates used this way are // compile-time duck typing template void DO_SOMETHING_WITH( T* t ) { /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ do_something( t->a_parameter ); } // TESTCASE3: use of :: on template argument. Templates used this way are // compile-time duck typing template void PRINT_A_DIAGNOSTIC( ) { /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ T::PrintDiagnostic(); } } int main (int , char **) { // bonus test case (regression test) for identifier/forced semantic without // trigger TTest test; /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ DO_SOMETHING_TO(test); } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/general_fallback/.ycm_extra_conf.py0000644000175000017500000000100213026170313030027 0ustar onuronurftopts = { 'cpp': [ '-Wall', '-Wextra', '-x', 'c++', '-std=c++11', ], 'c': [ '-Wall', '-Wextra', '-std=c99', '-x', 'c', '-I', '.', ], 'objc': [ '-x', 'objective-c', '-I', '.', ], } def FlagsForFile(filename, **kwargs): client_data = kwargs['client_data'] ft = client_data['&filetype'] try: opts = ftopts[ft] except: opts = ftopts['cpp'] if 'throw' in client_data: raise ValueError( client_data['throw'] ) return { 'flags': opts } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/general_fallback/lang_c.c0000644000175000017500000000500713026170313025777 0ustar onuronur// Identifier completion makes sense for duck-typing. // // The purpose of this test is to both demonstrate the use-case and test the // functionality. Completions of "A.a_parameter" using the identifier // completer feels natural, whereas offering no suggestions feels broken typedef struct { int a_parameter; int another_parameter; } TTest; typedef struct { int another_int; int and_a_final_int; } TTest_Which_Is_Not_TTest; static void do_something( int ); static void do_another_thing( int ); // TESTCASE1: use of . on macro parameter. Macros used this way are compile-time // duck-typing. Note this in this particular instance, libclang actually // offers semantic completions if there is only call to this macro // (e.g. DO_SOMETHING_TO( a_test ) - clever little shrew), so we don't call it /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ #define DO_SOMETHING_TO( A ) \ do { \ do_something( A.a_parameter ); \ do_another_thing( A.another_parameter ); \ } while (0) // TESTCASE2: use of -> on macro parameter. Macros used this way are // compile-time duck-typing /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ #define DO_SOMETHING_VIA( P ) \ do { \ do_something( P->a_parameter ); \ do_another_thing( P->another_parameter ); \ } while (0) int main( int argc, char ** argv ) { TTest a_test; // TESTCASE3: use of -> on struct. This is an error, but the user might // subsequently change a_test to be a pointer. Assumption: user knows what they // are doing /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ if ( a_test->anoth ) { (void) 0; } // TESTCASE4: use of . on struct. Gets semantic suggestions /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ if ( a_test.a_parameter ) { (void) 0; } // TESTCASE5: use of . on struct for non-matching text. Again, probably an // error, but assume the user knows best, and might change it later. /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ if ( a_test.do_ ) { (void) 0; } TTest *p_test = &a_test; // TESTCASE6: use of -> on pointer. Semantic completions /* 1 2 3 4 1234567890123456789012345678901234567890123456789 */ if ( p_test-> ) { } } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/GetParent_Clang_test.cc0000644000175000017500000000125413026170313025517 0ustar onuronur// this file is used in RunCompleterCommand_GetParent_Clang_test struct A { struct B { int x; char do_x(); char do_z_inline() { return 'z'; } template char do_anything(T &t) { return t; } }; int y; char do_y(); char do_Z_inline() { return 'Z'; } template char do_anything(T &t); }; template char A::do_anything(T &t) { return t; } char A::B::do_x() { return 'x'; } char A::do_y() { return 'y'; } int main() { auto l = [](){ return "lambda"; }; l(); return 0; } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/noflags/0000755000175000017500000000000013026170313022603 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/noflags/.ycm_extra_conf.py0000644000175000017500000000006713026170313026236 0ustar onuronurdef FlagsForFile( filename ): return { 'flags': [] } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/noflags/basic.cpp0000644000175000017500000000020113026170313024361 0ustar onuronurstruct Foo { int x; int y; char c; }; int main() { Foo foo; // The location after the dot is line 11, col 7 foo. } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/0000755000175000017500000000000013026170313023552 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/quote/0000755000175000017500000000000013026170313024707 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/quote/b.hpp0000644000175000017500000000000013026170313025627 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/system/0000755000175000017500000000000013026170313025076 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/system/c.hpp0000644000175000017500000000000013026170313026017 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/system/a.hpp0000644000175000017500000000000013026170313026015 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/.ycm_extra_conf.py0000644000175000017500000000032413026170313027201 0ustar onuronurimport os.path def FlagsForFile( filename, **kwargs ): d = os.path.dirname( filename ) return { 'flags': [ '-iquote', os.path.join( d, 'quote' ), '-I', os.path.join( d, 'system' ) ] } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/main.cpp0000644000175000017500000000032113026170313025176 0ustar onuronur#include "a.hpp" // ./a.hpp #include // system/a.hpp #include "b.hpp" // quote/b.hpp #include // error #include "c.hpp" // system/c.hpp #include // system/c.hpp // not an #include line ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/test-include/a.hpp0000644000175000017500000000000013026170313024471 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/clang/testdata/unicode.cc0000644000175000017500000000051313026170313023106 0ustar onuronur int main( int argc, char ** argv ) { int id_with_å_unicode_chars = 10; struct MyStruct { int member_with_å_unicøde; } myå; myå.w } int another_main() { struct MyStruct { /** * This method has unicøde in it */ int member_with_å_unicøde; } myå; int a = myå.member_with_å_unicøde } ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/get_completions_test.py0000644000175000017500000004444313026170313024156 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa import json import requests from nose.tools import eq_ from hamcrest import ( assert_that, contains, contains_inanyorder, empty, has_item, has_items, has_entry, has_entries, contains_string ) from ycmd.completers.cpp.clang_completer import NO_COMPLETIONS_MESSAGE from ycmd.responses import UnknownExtraConf, NoExtraConfDetected from ycmd.tests.clang import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, ErrorMatcher, UserOption, ExpectedFailure ) from ycmd.utils import ReadFile NO_COMPLETIONS_ERROR = ErrorMatcher( RuntimeError, NO_COMPLETIONS_MESSAGE ) def RunTest( app, test ): """ Method to run a simple completion test and verify the result Note: by default uses the .ycm_extra_conf from general_fallback/ which: - supports cpp, c and objc - requires extra_conf_data containing 'filetype&' = the filetype This should be sufficient for many standard test cases. If not, specify a path (as a list of path items) in 'extra_conf' member of |test|. test is a dictionary containing: 'request': kwargs for BuildRequest 'expect': { 'response': server response code (e.g. requests.codes.ok) 'data': matcher for the server response json } 'extra_conf': [ optional list of path items to extra conf file ] """ extra_conf = ( test[ 'extra_conf' ] if 'extra_conf' in test else [ 'general_fallback', '.ycm_extra_conf.py' ] ) app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( *extra_conf ) } ) contents = ReadFile( test[ 'request' ][ 'filepath' ] ) def CombineRequest( request, data ): kw = request request.update( data ) return BuildRequest( **kw ) # Because we aren't testing this command, we *always* ignore errors. This # is mainly because we (may) want to test scenarios where the completer # throws an exception and the easiest way to do that is to throw from # within the FlagsForFile function. app.post_json( '/event_notification', CombineRequest( test[ 'request' ], { 'event_name': 'FileReadyToParse', 'contents': contents, } ), expect_errors = True ) # We also ignore errors here, but then we check the response code ourself. # This is to allow testing of requests returning errors. response = app.post_json( '/completions', CombineRequest( test[ 'request' ], { 'contents': contents } ), expect_errors = True ) eq_( response.status_code, test[ 'expect' ][ 'response' ] ) print( 'Completer response: {0}'.format( json.dumps( response.json, indent = 2 ) ) ) assert_that( response.json, test[ 'expect' ][ 'data' ] ) @SharedYcmd def GetCompletions_ForcedWithNoTrigger_test( app ): RunTest( app, { 'description': 'semantic completion with force query=DO_SO', 'request': { 'filetype' : 'cpp', 'filepath' : PathToTestFile( 'general_fallback', 'lang_cpp.cc' ), 'line_num' : 54, 'column_num': 8, 'extra_conf_data': { '&filetype': 'cpp' }, 'force_semantic': True, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'DO_SOMETHING_TO', 'void' ), CompletionEntryMatcher( 'DO_SOMETHING_WITH', 'void' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Fallback_NoSuggestions_test( app ): # TESTCASE1 (general_fallback/lang_c.c) RunTest( app, { 'description': 'Triggered, fallback but no query so no completions', 'request': { 'filetype' : 'c', 'filepath' : PathToTestFile( 'general_fallback', 'lang_c.c' ), 'line_num' : 29, 'column_num': 21, 'extra_conf_data': { '&filetype': 'c' }, 'force_semantic': False, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': empty(), 'errors': has_item( NO_COMPLETIONS_ERROR ), } ) }, } ) @SharedYcmd def GetCompletions_Fallback_NoSuggestions_MinimumCharaceters_test( app ): # TESTCASE1 (general_fallback/lang_cpp.cc) RunTest( app, { 'description': 'fallback general completion obeys min chars setting ' ' (query="a")', 'request': { 'filetype' : 'cpp', 'filepath' : PathToTestFile( 'general_fallback', 'lang_cpp.cc' ), 'line_num' : 21, 'column_num': 22, 'extra_conf_data': { '&filetype': 'cpp' }, 'force_semantic': False, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': empty(), 'errors': has_item( NO_COMPLETIONS_ERROR ), } ) }, } ) @SharedYcmd def GetCompletions_Fallback_Suggestions_test( app ): # TESTCASE1 (general_fallback/lang_c.c) RunTest( app, { 'description': '. after macro with some query text (.a_)', 'request': { 'filetype' : 'c', 'filepath' : PathToTestFile( 'general_fallback', 'lang_c.c' ), 'line_num' : 29, 'column_num': 23, 'extra_conf_data': { '&filetype': 'c' }, 'force_semantic': False, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': has_item( CompletionEntryMatcher( 'a_parameter', '[ID]' ) ), 'errors': has_item( NO_COMPLETIONS_ERROR ), } ) }, } ) @SharedYcmd def GetCompletions_Fallback_Exception_test( app ): # TESTCASE4 (general_fallback/lang_c.c) # extra conf throws exception RunTest( app, { 'description': '. on struct returns identifier because of error', 'request': { 'filetype' : 'c', 'filepath' : PathToTestFile( 'general_fallback', 'lang_c.c' ), 'line_num' : 62, 'column_num': 20, 'extra_conf_data': { '&filetype': 'c', 'throw': 'testy' }, 'force_semantic': False, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'a_parameter', '[ID]' ), CompletionEntryMatcher( 'another_parameter', '[ID]' ), ), 'errors': has_item( ErrorMatcher( ValueError, 'testy' ) ) } ) }, } ) @SharedYcmd def GetCompletions_Forced_NoFallback_test( app ): # TESTCASE2 (general_fallback/lang_c.c) RunTest( app, { 'description': '-> after macro with forced semantic', 'request': { 'filetype' : 'c', 'filepath' : PathToTestFile( 'general_fallback', 'lang_c.c' ), 'line_num' : 41, 'column_num': 30, 'extra_conf_data': { '&filetype': 'c' }, 'force_semantic': True, }, 'expect': { 'response': requests.codes.internal_server_error, 'data': NO_COMPLETIONS_ERROR, }, } ) @SharedYcmd def GetCompletions_FilteredNoResults_Fallback_test( app ): # no errors because the semantic completer returned results, but they # were filtered out by the query, so this is considered working OK # (whereas no completions from the semantic engine is considered an # error) # TESTCASE5 (general_fallback/lang_cpp.cc) RunTest( app, { 'description': '. on struct returns IDs after query=do_', 'request': { 'filetype': 'c', 'filepath': PathToTestFile( 'general_fallback', 'lang_c.c' ), 'line_num': 71, 'column_num': 18, 'extra_conf_data': { '&filetype': 'c' }, 'force_semantic': False, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains_inanyorder( # do_ is an identifier because it is already in the file when we # load it CompletionEntryMatcher( 'do_', '[ID]' ), CompletionEntryMatcher( 'do_something', '[ID]' ), CompletionEntryMatcher( 'do_another_thing', '[ID]' ), ), 'errors': empty() } ) }, } ) @IsolatedYcmd def GetCompletions_WorksWithExplicitFlags_test( app ): app.post_json( '/ignore_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) contents = """ struct Foo { int x; int y; char c; }; int main() { Foo foo; foo. } """ completion_data = BuildRequest( filepath = '/foo.cpp', filetype = 'cpp', contents = contents, line_num = 11, column_num = 7, compilation_flags = ['-x', 'c++'] ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions'], has_items( CompletionEntryMatcher( 'c' ), CompletionEntryMatcher( 'x' ), CompletionEntryMatcher( 'y' ) ) ) eq_( 7, response_data[ 'completion_start_column' ] ) @IsolatedYcmd def GetCompletions_NoCompletionsWhenAutoTriggerOff_test( app ): with UserOption( 'auto_trigger', False ): app.post_json( '/ignore_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) contents = """ struct Foo { int x; int y; char c; }; int main() { Foo foo; foo. } """ completion_data = BuildRequest( filepath = '/foo.cpp', filetype = 'cpp', contents = contents, line_num = 11, column_num = 7, compilation_flags = ['-x', 'c++'] ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, empty() ) @IsolatedYcmd def GetCompletions_UnknownExtraConfException_test( app ): filepath = PathToTestFile( 'basic.cpp' ) completion_data = BuildRequest( filepath = filepath, filetype = 'cpp', contents = ReadFile( filepath ), line_num = 11, column_num = 7, force_semantic = True ) response = app.post_json( '/completions', completion_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, has_entry( 'exception', has_entry( 'TYPE', UnknownExtraConf.__name__ ) ) ) app.post_json( '/ignore_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) response = app.post_json( '/completions', completion_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, has_entry( 'exception', has_entry( 'TYPE', NoExtraConfDetected.__name__ ) ) ) @IsolatedYcmd def GetCompletions_WorksWhenExtraConfExplicitlyAllowed_test( app ): app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) filepath = PathToTestFile( 'basic.cpp' ) completion_data = BuildRequest( filepath = filepath, filetype = 'cpp', contents = ReadFile( filepath ), line_num = 11, column_num = 7 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'c' ), CompletionEntryMatcher( 'x' ), CompletionEntryMatcher( 'y' ) ) ) @SharedYcmd def GetCompletions_ExceptionWhenNoFlagsFromExtraConf_test( app ): app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( 'noflags', '.ycm_extra_conf.py' ) } ) filepath = PathToTestFile( 'noflags', 'basic.cpp' ) completion_data = BuildRequest( filepath = filepath, filetype = 'cpp', contents = ReadFile( filepath ), line_num = 11, column_num = 7, force_semantic = True ) response = app.post_json( '/completions', completion_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, has_entry( 'exception', has_entry( 'TYPE', RuntimeError.__name__ ) ) ) @SharedYcmd def GetCompletions_ForceSemantic_OnlyFilteredCompletions_test( app ): contents = """ int main() { int foobar; int floozar; int gooboo; int bleble; fooar } """ completion_data = BuildRequest( filepath = '/foo.cpp', filetype = 'cpp', force_semantic = True, contents = contents, line_num = 9, column_num = 8, compilation_flags = ['-x', 'c++'] ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, contains_inanyorder( CompletionEntryMatcher( 'foobar' ), CompletionEntryMatcher( 'floozar' ) ) ) @SharedYcmd def GetCompletions_ClientDataGivenToExtraConf_test( app ): app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( 'client_data', '.ycm_extra_conf.py' ) } ) filepath = PathToTestFile( 'client_data', 'main.cpp' ) completion_data = BuildRequest( filepath = filepath, filetype = 'cpp', contents = ReadFile( filepath ), line_num = 9, column_num = 7, extra_conf_data = { 'flags': ['-x', 'c++'] } ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_item( CompletionEntryMatcher( 'x' ) ) ) @SharedYcmd def GetCompletions_FilenameCompleter_ClientDataGivenToExtraConf_test( app ): app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( 'client_data', '.ycm_extra_conf.py' ) } ) filepath = PathToTestFile( 'client_data', 'include.cpp' ) completion_data = BuildRequest( filepath = filepath, filetype = 'cpp', contents = ReadFile( filepath ), line_num = 1, column_num = 11, extra_conf_data = { 'flags': ['-x', 'c++'] } ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_item( CompletionEntryMatcher( 'include.hpp', extra_menu_info = '[File]' ) ) ) @SharedYcmd def GetCompletions_UnicodeInLine_test( app ): RunTest( app, { 'description': 'member completion with a unicode identifier', 'extra_conf': [ '.ycm_extra_conf.py' ], 'request': { 'filetype' : 'cpp', 'filepath' : PathToTestFile( 'unicode.cc' ), 'line_num' : 9, 'column_num': 8, 'extra_conf_data': { '&filetype': 'cpp' }, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completion_start_column': 8, 'completions': contains_inanyorder( CompletionEntryMatcher( 'member_with_å_unicøde', 'int' ), CompletionEntryMatcher( '~MyStruct', 'void' ), CompletionEntryMatcher( 'operator=', 'MyStruct &' ), CompletionEntryMatcher( 'MyStruct::', '' ), ), 'errors': empty(), } ) }, } ) @ExpectedFailure( 'Filtering and sorting does not work when the candidate ' 'contains non-ASCII characters. This is due to the way ' 'the filtering and sorting code works.', contains_string( "value for 'completions' no item matches" ) ) @SharedYcmd def GetCompletions_UnicodeInLineFilter_test( app ): RunTest( app, { 'description': 'member completion with a unicode identifier', 'extra_conf': [ '.ycm_extra_conf.py' ], 'request': { 'filetype' : 'cpp', 'filepath' : PathToTestFile( 'unicode.cc' ), 'line_num' : 9, 'column_num': 10, 'extra_conf_data': { '&filetype': 'cpp' }, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completion_start_column': 8, 'completions': contains_inanyorder( CompletionEntryMatcher( 'member_with_å_unicøde', 'int' ), ), 'errors': empty(), } ) }, } ) ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/__init__.py0000644000175000017500000000520213026170313021451 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd import handlers from ycmd.tests.test_utils import ClearCompletionsCache, SetUpApp shared_app = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state try: test( SetUpApp(), *args, **kwargs ) finally: handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/comment_strip_test.py0000644000175000017500000001171313026170313023640 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . """This tests the comment "sanitisation" which is done on C/C++/ObjC method/variable,etc. headers in order to remove non-data-ink from the raw comment""" # flake8: noqa from __future__ import print_function from __future__ import unicode_literals from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_ from ycmd.completers.cpp import clang_completer def _Check_FormatRawComment( comment, expected ): try: result = clang_completer._FormatRawComment( comment ) eq_( result, expected ) except: print( "Failed while parsing:\n" "'" + comment + "'\n" "Expecting:\n" "'" + expected + "'\n" "But found:\n" "'" + result + "'" ) raise def ClangCompleter_FormatRawComment_SingleLine_Doxygen_test(): # - /// # Indent + /// + _Check_FormatRawComment( ' /// Single line comment', 'Single line comment' ) # No indent, Internal indent removed, trailing whitespace removed _Check_FormatRawComment( '/// Single line comment ', 'Single line comment' ) # Extra / prevents initial indent being removed _Check_FormatRawComment( '//// Single line comment ', '/ Single line comment' ) _Check_FormatRawComment( '////* Test ', '/* Test' ) def ClangCompleter_FormatRawComment_SingleLine_InlineDoxygen_test(): # Inline-style comments with and without leading/trailing tokens # - ///< _Check_FormatRawComment( '/////< _Check_FormatRawComment( '////! _Check_FormatRawComment( '//!Test', 'Test' ) _Check_FormatRawComment( ' ///* # - /** # - */ _Check_FormatRawComment( '/*Test', 'Test' ) _Check_FormatRawComment( ' /** Test */ ', 'Test' ) _Check_FormatRawComment( '/*** Test', '* Test' ) def ClangCompleter_FormatRawComment_MultiOneLine_JavaDoc_test(): # sic: This one isn't ideal, but it is (probably) uncommon _Check_FormatRawComment( '/** Test */ /** Test2 */', 'Test */ /** Test2' ) def ClangCompleter_FormatRawComment_MultiLine_Doxygen_Inbalance_test(): # The dedenting only applies to consistent indent # Note trailing whitespace is intentional _Check_FormatRawComment( """ /// This is /// a ///Multi-line /// Comment /// With many different */ ///< Doxygen-like ///! comment ****/ Entries """, """ This is a Multi-line Comment With many different Doxygen-like comment ****/ Entries """ ) # noqa def ClangCompleter_FormatRawComment_MultiLine_JavaDoc_Inconsistent_test(): # The dedenting only applies to consistent indent, and leaves any subsequent # indent intact # Note trailing whitespace is intentional _Check_FormatRawComment( """ /** All of the * Lines in this Comment consistently * * Have a 2-space indent */ """, """ All of the Lines in this Comment consistently * Have a 2-space indent """ ) # noqa def ClangCompleter_FormatRawComment_ZeroLine_test(): _Check_FormatRawComment( '', '' ) def ClangCompleter_FormatRawComment_MultiLine_empty_test(): # Note trailing whitespace is intentional _Check_FormatRawComment( """ * /// */ """, """ """ ) # noqa ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/diagnostics_test.py0000644000175000017500000001723513026170313023271 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, contains, contains_string, has_entries, has_entry, has_items, empty, equal_to ) from pprint import pprint from ycmd.tests.clang import IsolatedYcmd, PathToTestFile from ycmd.tests.test_utils import BuildRequest from ycmd.utils import ReadFile @IsolatedYcmd def Diagnostics_ZeroBasedLineAndColumn_test( app ): contents = """ void foo() { double baz = "foo"; } // Padding to 5 lines // Padding to 5 lines """ event_data = BuildRequest( compilation_flags = ['-x', 'c++'], event_name = 'FileReadyToParse', contents = contents, filetype = 'cpp' ) results = app.post_json( '/event_notification', event_data ).json assert_that( results, contains( has_entries( { 'kind': equal_to( 'ERROR' ), 'text': contains_string( 'cannot initialize' ), 'ranges': contains( has_entries( { 'start': has_entries( { 'line_num': 3, 'column_num': 16, } ), 'end': has_entries( { 'line_num': 3, 'column_num': 21, } ), } ) ), 'location': has_entries( { 'line_num': 3, 'column_num': 10 } ), 'location_extent': has_entries( { 'start': has_entries( { 'line_num': 3, 'column_num': 10, } ), 'end': has_entries( { 'line_num': 3, 'column_num': 13, } ), } ) } ) ) ) @IsolatedYcmd def Diagnostics_SimpleLocationExtent_test( app ): contents = """ void foo() { baz = 5; } // Padding to 5 lines // Padding to 5 lines """ event_data = BuildRequest( compilation_flags = ['-x', 'c++'], event_name = 'FileReadyToParse', contents = contents, filetype = 'cpp' ) results = app.post_json( '/event_notification', event_data ).json assert_that( results, contains( has_entries( { 'location_extent': has_entries( { 'start': has_entries( { 'line_num': 3, 'column_num': 3, } ), 'end': has_entries( { 'line_num': 3, 'column_num': 6, } ), } ) } ) ) ) @IsolatedYcmd def Diagnostics_PragmaOnceWarningIgnored_test( app ): contents = """ #pragma once struct Foo { int x; int y; int c; int d; }; """ event_data = BuildRequest( compilation_flags = ['-x', 'c++'], event_name = 'FileReadyToParse', contents = contents, filepath = '/foo.h', filetype = 'cpp' ) response = app.post_json( '/event_notification', event_data ).json assert_that( response, empty() ) @IsolatedYcmd def Diagnostics_Works_test( app ): contents = """ struct Foo { int x // semicolon missing here! int y; int c; int d; }; """ diag_data = BuildRequest( compilation_flags = ['-x', 'c++'], line_num = 3, contents = contents, filetype = 'cpp' ) event_data = diag_data.copy() event_data.update( { 'event_name': 'FileReadyToParse', } ) app.post_json( '/event_notification', event_data ) results = app.post_json( '/detailed_diagnostic', diag_data ).json assert_that( results, has_entry( 'message', contains_string( "expected ';'" ) ) ) @IsolatedYcmd def Diagnostics_Multiline_test( app ): contents = """ struct Foo { Foo(int z) {} }; int main() { Foo foo("goo"); } """ diag_data = BuildRequest( compilation_flags = [ '-x', 'c++' ], line_num = 7, contents = contents, filetype = 'cpp' ) event_data = diag_data.copy() event_data.update( { 'event_name': 'FileReadyToParse', } ) app.post_json( '/event_notification', event_data ) results = app.post_json( '/detailed_diagnostic', diag_data ).json assert_that( results, has_entry( 'message', contains_string( "\n" ) ) ) @IsolatedYcmd def Diagnostics_FixIt_Available_test( app ): contents = ReadFile( PathToTestFile( 'FixIt_Clang_cpp11.cpp' ) ) event_data = BuildRequest( contents = contents, event_name = 'FileReadyToParse', filetype = 'cpp', compilation_flags = [ '-x', 'c++', '-std=c++03', '-Wall', '-Wextra', '-pedantic' ] ) response = app.post_json( '/event_notification', event_data ).json pprint( response ) assert_that( response, has_items( has_entries( { 'location': has_entries( { 'line_num': 16, 'column_num': 3 } ), 'text': equal_to( 'switch condition type \'A\' ' 'requires explicit conversion to \'int\''), 'fixit_available': True } ), has_entries( { 'location': has_entries( { 'line_num': 11, 'column_num': 3 } ), 'text': equal_to( 'explicit conversion functions are a C++11 extension' ), 'fixit_available': False } ), ) ) @IsolatedYcmd def Diagnostics_MultipleMissingIncludes_test( app ): contents = ReadFile( PathToTestFile( 'multiple_missing_includes.cc' ) ) event_data = BuildRequest( contents = contents, event_name = 'FileReadyToParse', filetype = 'cpp', compilation_flags = [ '-x', 'c++' ] ) response = app.post_json( '/event_notification', event_data ).json pprint( response ) assert_that( response, has_items( has_entries( { 'kind': equal_to( 'ERROR' ), 'location': has_entries( { 'line_num': 1, 'column_num': 10 } ), 'text': equal_to( "'first_missing_include' file not found" ), 'fixit_available': False } ), has_entries( { 'kind': equal_to( 'ERROR' ), 'location': has_entries( { 'line_num': 2, 'column_num': 10 } ), 'text': equal_to( "'second_missing_include' file not found" ), 'fixit_available': False } ), ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/subcommands_test.py0000644000175000017500000011753413026170313023300 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, calling, contains, contains_string, equal_to, has_entries, raises ) from nose.tools import eq_ from pprint import pprint from webtest import AppError import requests import os.path from ycmd.completers.cpp.clang_completer import NO_DOCUMENTATION_MESSAGE from ycmd.tests.clang import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, ErrorMatcher, ChunkMatcher, LineColMatcher ) from ycmd.utils import ReadFile @SharedYcmd def Subcommands_DefinedSubcommands_test( app ): subcommands_data = BuildRequest( completer_target = 'cpp' ) eq_( sorted( [ 'ClearCompilationFlagCache', 'FixIt', 'GetDoc', 'GetDocImprecise', 'GetParent', 'GetType', 'GetTypeImprecise', 'GoTo', 'GoToDeclaration', 'GoToDefinition', 'GoToImprecise', 'GoToInclude' ] ), app.post_json( '/defined_subcommands', subcommands_data ).json ) @SharedYcmd def Subcommands_GoTo_ZeroBasedLineAndColumn_test( app ): contents = ReadFile( PathToTestFile( 'GoTo_Clang_ZeroBasedLineAndColumn_test.cc' ) ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = ['GoToDefinition'], compilation_flags = ['-x', 'c++'], line_num = 10, column_num = 3, contents = contents, filetype = 'cpp' ) eq_( { 'filepath': os.path.abspath( '/foo' ), 'line_num': 2, 'column_num': 8 }, app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def RunGoToTest_all( app, filename, command, test ): contents = ReadFile( PathToTestFile( filename ) ) common_request = { 'completer_target' : 'filetype_default', 'command_arguments': command, 'compilation_flags': ['-x', 'c++'], 'line_num' : 10, 'column_num' : 3, 'contents' : contents, 'filetype' : 'cpp' } common_response = { 'filepath': os.path.abspath( '/foo' ), } request = common_request request.update( { 'line_num' : test['request'][0], 'column_num': test['request'][1], }) response = common_response response.update({ 'line_num' : test['response'][0], 'column_num': test['response'][1], }) goto_data = BuildRequest( **request ) actual_response = app.post_json( '/run_completer_command', goto_data ).json pprint( actual_response ) eq_( response, actual_response ) def Subcommands_GoTo_all_test(): # GoToDeclaration tests = [ # Local::x -> declaration of x { 'request': [ 23, 21 ], 'response': [ 4, 9 ] }, # Local::in_line -> declaration of Local::in_line { 'request': [ 24, 26 ], 'response': [ 6, 10 ] }, # Local -> declaration of Local { 'request': [ 24, 16 ], 'response': [ 2, 11 ] }, # Local::out_of_line -> declaration of Local::out_of_line { 'request': [ 25, 27 ], 'response': [ 11, 10 ] }, # GoToDeclaration on definition of out_of_line moves to declaration { 'request': [ 14, 13 ], 'response': [ 11, 10] }, # main -> declaration of main { 'request': [ 21, 7 ], 'response': [ 19, 5] }, # Another_Unicøde { 'request': [ 36, 25 ], 'response': [ 32, 54] }, { 'request': [ 38, 3 ], 'response': [ 36, 28] }, ] for test in tests: yield ( RunGoToTest_all, 'GoTo_all_Clang_test.cc', [ 'GoToDeclaration' ], test ) # GoToDefinition - identical to GoToDeclaration # # The semantics of this seem the wrong way round to me. GoToDefinition should # go to where a method is implemented, not where it is declared. # tests = [ # Local::x -> declaration of x { 'request': [ 23, 21 ], 'response': [ 4, 9] }, # Local::in_line -> declaration of Local::in_line { 'request': [ 24, 26 ], 'response': [ 6, 10 ] }, # Local -> declaration of Local { 'request': [ 24, 16 ], 'response': [ 2, 11 ] }, # sic: Local::out_of_line -> definition of Local::out_of_line { 'request': [ 25, 27 ], 'response': [ 14, 13 ] }, # sic # sic: GoToDeclaration on definition of out_of_line moves to itself { 'request': [ 14, 13 ], 'response': [ 14, 13 ] }, # sic # main -> definition of main (not declaration) { 'request': [ 21, 7 ], 'response': [ 21, 5] }, # sic # Unicøde { 'request': [ 34, 8 ], 'response': [ 32, 26 ] }, ] for test in tests: yield ( RunGoToTest_all, 'GoTo_all_Clang_test.cc', [ 'GoToDefinition' ], test ) # GoTo - identical to GoToDeclaration # # The semantics of this seem the wrong way round to me. GoToDefinition should # go to where a method is implemented, not where it is declared. # tests = [ # Local::x -> declaration of x { 'request': [23, 21], 'response': [ 4, 9] }, # Local::in_line -> declaration of Local::in_line { 'request': [24, 26], 'response': [ 6, 10] }, # Local -> declaration of Local { 'request': [24, 16], 'response': [ 2, 11] }, # sic: Local::out_of_line -> definition of Local::out_of_line { 'request': [25, 27], 'response': [14, 13] }, # sic # sic: GoToDeclaration on definition of out_of_line moves to itself { 'request': [14, 13], 'response': [14, 13] }, # sic # main -> definition of main (not declaration) { 'request': [21, 7], 'response': [21, 5] }, # sic # Another_Unicøde { 'request': [ 36, 25 ], 'response': [ 32, 54] }, ] for test in tests: yield ( RunGoToTest_all, 'GoTo_all_Clang_test.cc', [ 'GoTo' ], test ) # GoToImprecise - identical to GoToDeclaration # # The semantics of this seem the wrong way round to me. GoToDefinition should # go to where a method is implemented, not where it is declared. # tests = [ # Local::x -> declaration of x { 'request': [23, 21], 'response': [ 4, 9] }, # Local::in_line -> declaration of Local::in_line { 'request': [24, 26], 'response': [ 6, 10] }, # Local -> declaration of Local { 'request': [24, 16], 'response': [ 2, 11] }, # sic: Local::out_of_line -> definition of Local::out_of_line { 'request': [25, 27], 'response': [14, 13] }, # sic # sic: GoToDeclaration on definition of out_of_line moves to itself { 'request': [14, 13], 'response': [14, 13] }, # sic # main -> definition of main (not declaration) { 'request': [21, 7], 'response': [21, 5] }, # sic ] for test in tests: yield ( RunGoToTest_all, 'GoTo_all_Clang_test.cc', [ 'GoToImprecise' ], test ) @SharedYcmd def RunGoToIncludeTest( app, command, test ): app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( 'test-include', '.ycm_extra_conf.py' ) } ) filepath = PathToTestFile( 'test-include', 'main.cpp' ) goto_data = BuildRequest( filepath = filepath, filetype = 'cpp', contents = ReadFile( filepath ), command_arguments = [ command ], line_num = test[ 'request' ][ 0 ], column_num = test[ 'request' ][ 1 ] ) response = { 'filepath' : PathToTestFile( 'test-include', test[ 'response' ] ), 'line_num' : 1, 'column_num' : 1, } actual_response = app.post_json( '/run_completer_command', goto_data ).json pprint( actual_response ) eq_( response, actual_response ) def Subcommands_GoToInclude_test(): tests = [ { 'request': [ 1, 1 ], 'response': 'a.hpp' }, { 'request': [ 2, 1 ], 'response': os.path.join( 'system', 'a.hpp' ) }, { 'request': [ 3, 1 ], 'response': os.path.join( 'quote', 'b.hpp' ) }, { 'request': [ 5, 1 ], 'response': os.path.join( 'system', 'c.hpp' ) }, { 'request': [ 6, 1 ], 'response': os.path.join( 'system', 'c.hpp' ) }, ] for test in tests: yield RunGoToIncludeTest, 'GoToInclude', test yield RunGoToIncludeTest, 'GoTo', test yield RunGoToIncludeTest, 'GoToImprecise', test def Subcommands_GoToInclude_Fail_test(): test = { 'request': [ 4, 1 ], 'response': '' } assert_that( calling( RunGoToIncludeTest ).with_args( 'GoToInclude', test ), raises( AppError, 'Include file not found.' ) ) assert_that( calling( RunGoToIncludeTest ).with_args( 'GoTo', test ), raises( AppError, 'Include file not found.' ) ) assert_that( calling( RunGoToIncludeTest ).with_args( 'GoToImprecise', test ), raises( AppError, 'Include file not found.' ) ) test = { 'request': [ 7, 1 ], 'response': '' } assert_that( calling( RunGoToIncludeTest ).with_args( 'GoToInclude', test ), raises( AppError, 'Not an include/import line.' ) ) assert_that( calling( RunGoToIncludeTest ).with_args( 'GoTo', test ), raises( AppError, r'Can\\\'t jump to definition or declaration.' ) ) assert_that( calling( RunGoToIncludeTest ).with_args( 'GoToImprecise', test ), raises( AppError, r'Can\\\'t jump to definition or declaration.' ) ) @SharedYcmd def RunGetSemanticTest( app, filename, test, command): contents = ReadFile( PathToTestFile( filename ) ) # We use the -fno-delayed-template-parsing flag to not delay # parsing of templates on Windows. This is the default on # other platforms. See the _ExtraClangFlags function in # ycmd/completers/cpp/flags.py file for more information. common_args = { 'completer_target' : 'filetype_default', 'command_arguments': command, 'compilation_flags': [ '-x', 'c++', # C++11 flag is needed for lambda functions '-std=c++11', '-fno-delayed-template-parsing' ], 'line_num' : 10, 'column_num' : 3, 'contents' : contents, 'filetype' : 'cpp' } args = test[ 0 ] expected = test[ 1 ] request = common_args request.update( args ) request_data = BuildRequest( **request ) response = app.post_json( '/run_completer_command', request_data ).json pprint( response ) eq_( { 'message': expected }, response ) def Subcommands_GetType_test(): tests = [ # Basic pod types [{'line_num': 20, 'column_num': 3}, 'Foo'], [{'line_num': 1, 'column_num': 1}, 'Internal error: cursor not valid'], [{'line_num': 12, 'column_num': 2}, 'Foo'], [{'line_num': 12, 'column_num': 8}, 'Foo'], [{'line_num': 12, 'column_num': 9}, 'Foo'], [{'line_num': 12, 'column_num': 10}, 'Foo'], [{'line_num': 13, 'column_num': 3}, 'int'], [{'line_num': 13, 'column_num': 7}, 'int'], [{'line_num': 15, 'column_num': 7}, 'char'], # Function [{'line_num': 18, 'column_num': 2}, 'int ()'], [{'line_num': 18, 'column_num': 6}, 'int ()'], # Declared and canonical type # On Ns:: (Unknown) [{'line_num': 21, 'column_num': 3}, 'Unknown type'], # sic # On Type (Type) [{'line_num': 21, 'column_num': 8}, 'Type => Ns::BasicType'], # sic # On "a" (Ns::Type) [{'line_num': 21, 'column_num': 15}, 'Ns::Type => Ns::BasicType'], [{'line_num': 22, 'column_num': 13}, 'Ns::Type => Ns::BasicType'], # Cursor on decl for refs & pointers [{'line_num': 35, 'column_num': 3}, 'Foo'], [{'line_num': 35, 'column_num': 11}, 'Foo &'], [{'line_num': 35, 'column_num': 15}, 'Foo'], [{'line_num': 36, 'column_num': 3}, 'Foo'], [{'line_num': 36, 'column_num': 11}, 'Foo *'], [{'line_num': 36, 'column_num': 18}, 'Foo'], [{'line_num': 38, 'column_num': 3}, 'const Foo &'], [{'line_num': 38, 'column_num': 16}, 'const Foo &'], [{'line_num': 39, 'column_num': 3}, 'const Foo *'], [{'line_num': 39, 'column_num': 16}, 'const Foo *'], # Cursor on usage [{'line_num': 41, 'column_num': 13}, 'const Foo'], [{'line_num': 41, 'column_num': 19}, 'const int'], [{'line_num': 42, 'column_num': 13}, 'const Foo *'], [{'line_num': 42, 'column_num': 20}, 'const int'], [{'line_num': 43, 'column_num': 12}, 'Foo'], [{'line_num': 43, 'column_num': 17}, 'int'], [{'line_num': 44, 'column_num': 12}, 'Foo *'], [{'line_num': 44, 'column_num': 18}, 'int'], # Auto in declaration (canonical types apparently differ) [{'line_num': 24, 'column_num': 3}, 'Foo & => Foo &'], # sic [{'line_num': 24, 'column_num': 11}, 'Foo & => Foo &'], # sic [{'line_num': 24, 'column_num': 18}, 'Foo'], [{'line_num': 25, 'column_num': 3}, 'Foo * => Foo *'], # sic [{'line_num': 25, 'column_num': 11}, 'Foo * => Foo *'], # sic [{'line_num': 25, 'column_num': 18}, 'Foo'], [{'line_num': 27, 'column_num': 3}, 'const Foo & => const Foo &'], # sic [{'line_num': 27, 'column_num': 16}, 'const Foo & => const Foo &'], # sic [{'line_num': 28, 'column_num': 3}, 'const Foo * => const Foo *'], # sic [{'line_num': 28, 'column_num': 16}, 'const Foo * => const Foo *'], # sic # Auto in usage (canonical types apparently differ) [{'line_num': 30, 'column_num': 14}, 'const Foo => const Foo'], # sic [{'line_num': 30, 'column_num': 21}, 'const int'], [{'line_num': 31, 'column_num': 14}, 'const Foo * => const Foo *'], # sic [{'line_num': 31, 'column_num': 22}, 'const int'], [{'line_num': 32, 'column_num': 13}, 'Foo => Foo'], # sic [{'line_num': 32, 'column_num': 19}, 'int'], [{'line_num': 33, 'column_num': 13}, 'Foo * => Foo *'], # sic [{'line_num': 33, 'column_num': 20}, 'int'], # Unicode [{'line_num': 47, 'column_num': 13}, 'Unicøde *'], ] for test in tests: yield ( RunGetSemanticTest, 'GetType_Clang_test.cc', test, [ 'GetType' ] ) # For every practical scenario, GetTypeImprecise is the same as GetType (it # just skips the reparse) for test in tests: yield ( RunGetSemanticTest, 'GetType_Clang_test.cc', test, [ 'GetTypeImprecise' ] ) def Subcommands_GetParent_test(): tests = [ [{'line_num': 1, 'column_num': 1}, 'Internal error: cursor not valid'], # Would be file name if we had one: [{'line_num': 2, 'column_num': 8}, '/foo'], # The reported scope does not include parents [{'line_num': 3, 'column_num': 11}, 'A'], [{'line_num': 4, 'column_num': 13}, 'B'], [{'line_num': 5, 'column_num': 13}, 'B'], [{'line_num': 9, 'column_num': 17}, 'do_z_inline()'], [{'line_num': 15, 'column_num': 22}, 'do_anything(T &)'], [{'line_num': 19, 'column_num': 9}, 'A'], [{'line_num': 20, 'column_num': 9}, 'A'], [{'line_num': 22, 'column_num': 12}, 'A'], [{'line_num': 23, 'column_num': 5}, 'do_Z_inline()'], [{'line_num': 24, 'column_num': 12}, 'do_Z_inline()'], [{'line_num': 28, 'column_num': 14}, 'A'], [{'line_num': 34, 'column_num': 1}, 'do_anything(T &)'], [{'line_num': 39, 'column_num': 1}, 'do_x()'], [{'line_num': 44, 'column_num': 1}, 'do_y()'], [{'line_num': 49, 'column_num': 1}, 'main()'], # Lambdas report the name of the variable [{'line_num': 49, 'column_num': 14}, 'l'], [{'line_num': 50, 'column_num': 19}, 'l'], [{'line_num': 51, 'column_num': 16}, 'main()'], ] for test in tests: yield ( RunGetSemanticTest, 'GetParent_Clang_test.cc', test, [ 'GetParent' ] ) @SharedYcmd def RunFixItTest( app, line, column, lang, file_name, check ): contents = ReadFile( PathToTestFile( file_name ) ) language_options = { 'cpp11': { 'compilation_flags': [ '-x', 'c++', '-std=c++11', '-Wall', '-Wextra', '-pedantic' ], 'filetype' : 'cpp', }, 'objective-c': { 'compilation_flags': [ '-x', 'objective-c', '-Wall', '-Wextra' ], 'filetype' : 'objc', }, } # Build the command arguments from the standard ones and the language-specific # arguments. args = { 'completer_target' : 'filetype_default', 'contents' : contents, 'command_arguments': [ 'FixIt' ], 'line_num' : line, 'column_num' : column, } args.update( language_options[ lang ] ) # Get the diagnostics for the file. event_data = BuildRequest( **args ) results = app.post_json( '/run_completer_command', event_data ).json pprint( results ) check( results ) def FixIt_Check_cpp11_Ins( results ): # First fixit # switch(A()) { // expected-error{{explicit conversion to}} assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to('static_cast('), 'range': has_entries( { 'start': has_entries( { 'line_num': 16, 'column_num': 10 } ), 'end' : has_entries( { 'line_num': 16, 'column_num': 10 } ), } ), } ), has_entries( { 'replacement_text': equal_to(')'), 'range': has_entries( { 'start': has_entries( { 'line_num': 16, 'column_num': 13 } ), 'end' : has_entries( { 'line_num': 16, 'column_num': 13 } ), } ), } ) ), 'location': has_entries( { 'line_num': 16, 'column_num': 3 } ) } ) ) } ) ) def FixIt_Check_cpp11_InsMultiLine( results ): # Similar to FixIt_Check_cpp11_1 but inserts split across lines # assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to('static_cast('), 'range': has_entries( { 'start': has_entries( { 'line_num': 26, 'column_num': 7 } ), 'end' : has_entries( { 'line_num': 26, 'column_num': 7 } ), } ), } ), has_entries( { 'replacement_text': equal_to(')'), 'range': has_entries( { 'start': has_entries( { 'line_num': 28, 'column_num': 2 } ), 'end' : has_entries( { 'line_num': 28, 'column_num': 2 } ), } ), } ) ), 'location': has_entries( { 'line_num': 25, 'column_num': 3 } ) } ) ) } ) ) def FixIt_Check_cpp11_Del( results ): # Removal of :: assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to(''), 'range': has_entries( { 'start': has_entries( { 'line_num': 35, 'column_num': 7 } ), 'end' : has_entries( { 'line_num': 35, 'column_num': 9 } ), } ), } ) ), 'location': has_entries( { 'line_num': 35, 'column_num': 7 } ) } ) ) } ) ) def FixIt_Check_cpp11_Repl( results ): assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to('foo'), 'range': has_entries( { 'start': has_entries( { 'line_num': 40, 'column_num': 6 } ), 'end' : has_entries( { 'line_num': 40, 'column_num': 9 } ), } ), } ) ), 'location': has_entries( { 'line_num': 40, 'column_num': 6 } ) } ) ) } ) ) def FixIt_Check_cpp11_DelAdd( results ): assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to(''), 'range': has_entries( { 'start': has_entries( { 'line_num': 48, 'column_num': 3 } ), 'end' : has_entries( { 'line_num': 48, 'column_num': 4 } ), } ), } ), has_entries( { 'replacement_text': equal_to('~'), 'range': has_entries( { 'start': has_entries( { 'line_num': 48, 'column_num': 9 } ), 'end' : has_entries( { 'line_num': 48, 'column_num': 9 } ), } ), } ), ), 'location': has_entries( { 'line_num': 48, 'column_num': 3 } ) } ) ) } ) ) def FixIt_Check_objc( results ): assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to('id'), 'range': has_entries( { 'start': has_entries( { 'line_num': 5, 'column_num': 3 } ), 'end' : has_entries( { 'line_num': 5, 'column_num': 3 } ), } ), } ) ), 'location': has_entries( { 'line_num': 5, 'column_num': 3 } ) } ) ) } ) ) def FixIt_Check_objc_NoFixIt( results ): # and finally, a warning with no fixits assert_that( results, equal_to( { 'fixits': [] } ) ) def FixIt_Check_cpp11_MultiFirst( results ): assert_that( results, has_entries( { 'fixits': contains( # first fix-it at 54,16 has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to('foo'), 'range': has_entries( { 'start': has_entries( { 'line_num': 54, 'column_num': 16 } ), 'end' : has_entries( { 'line_num': 54, 'column_num': 19 } ), } ), } ) ), 'location': has_entries( { 'line_num': 54, 'column_num': 16 } ) } ), # second fix-it at 54,52 has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to(''), 'range': has_entries( { 'start': has_entries( { 'line_num': 54, 'column_num': 52 } ), 'end' : has_entries( { 'line_num': 54, 'column_num': 53 } ), } ), } ), has_entries( { 'replacement_text': equal_to('~'), 'range': has_entries( { 'start': has_entries( { 'line_num': 54, 'column_num': 58 } ), 'end' : has_entries( { 'line_num': 54, 'column_num': 58 } ), } ), } ), ), 'location': has_entries( { 'line_num': 54, 'column_num': 52 } ) } ) ) } ) ) def FixIt_Check_cpp11_MultiSecond( results ): assert_that( results, has_entries( { 'fixits': contains( # second fix-it at 54,52 has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to(''), 'range': has_entries( { 'start': has_entries( { 'line_num': 54, 'column_num': 52 } ), 'end' : has_entries( { 'line_num': 54, 'column_num': 53 } ), } ), } ), has_entries( { 'replacement_text': equal_to('~'), 'range': has_entries( { 'start': has_entries( { 'line_num': 54, 'column_num': 58 } ), 'end' : has_entries( { 'line_num': 54, 'column_num': 58 } ), } ), } ), ), 'location': has_entries( { 'line_num': 54, 'column_num': 52 } ) } ), # first fix-it at 54,16 has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to('foo'), 'range': has_entries( { 'start': has_entries( { 'line_num': 54, 'column_num': 16 } ), 'end' : has_entries( { 'line_num': 54, 'column_num': 19 } ), } ), } ) ), 'location': has_entries( { 'line_num': 54, 'column_num': 16 } ) } ) ) } ) ) def FixIt_Check_unicode_Ins( results ): assert_that( results, has_entries( { 'fixits': contains( has_entries( { 'chunks': contains( has_entries( { 'replacement_text': equal_to(';'), 'range': has_entries( { 'start': has_entries( { 'line_num': 21, 'column_num': 39 } ), 'end' : has_entries( { 'line_num': 21, 'column_num': 39 } ), } ), } ) ), 'location': has_entries( { 'line_num': 21, 'column_num': 39 } ) } ) ) } ) ) def FixIt_Check_cpp11_Note( results ): assert_that( results, has_entries( { 'fixits': contains( # First note: put parens around it has_entries( { 'text': contains_string( 'parentheses around the assignment' ), 'chunks': contains( ChunkMatcher( '(', LineColMatcher( 59, 8 ), LineColMatcher( 59, 8 ) ), ChunkMatcher( ')', LineColMatcher( 61, 12 ), LineColMatcher( 61, 12 ) ) ), 'location': LineColMatcher( 60, 8 ), } ), # Second note: change to == has_entries( { 'text': contains_string( '==' ), 'chunks': contains( ChunkMatcher( '==', LineColMatcher( 60, 8 ), LineColMatcher( 60, 9 ) ) ), 'location': LineColMatcher( 60, 8 ), } ) ) } ) ) def FixIt_Check_cpp11_SpellCheck( results ): assert_that( results, has_entries( { 'fixits': contains( # Change to SpellingIsNotMyStrongPoint has_entries( { 'text': contains_string( "did you mean 'SpellingIsNotMyStrongPoint'" ), 'chunks': contains( ChunkMatcher( 'SpellingIsNotMyStrongPoint', LineColMatcher( 72, 9 ), LineColMatcher( 72, 35 ) ) ), 'location': LineColMatcher( 72, 9 ), } ) ) } ) ) def Subcommands_FixIt_all_test(): cfile = 'FixIt_Clang_cpp11.cpp' mfile = 'FixIt_Clang_objc.m' ufile = 'unicode.cc' tests = [ # L # i C # n o # e l Lang File, Checker [ 16, 0, 'cpp11', cfile, FixIt_Check_cpp11_Ins ], [ 16, 1, 'cpp11', cfile, FixIt_Check_cpp11_Ins ], [ 16, 10, 'cpp11', cfile, FixIt_Check_cpp11_Ins ], [ 25, 14, 'cpp11', cfile, FixIt_Check_cpp11_InsMultiLine ], [ 25, 0, 'cpp11', cfile, FixIt_Check_cpp11_InsMultiLine ], [ 35, 7, 'cpp11', cfile, FixIt_Check_cpp11_Del ], [ 40, 6, 'cpp11', cfile, FixIt_Check_cpp11_Repl ], [ 48, 3, 'cpp11', cfile, FixIt_Check_cpp11_DelAdd ], [ 5, 3, 'objective-c', mfile, FixIt_Check_objc ], [ 7, 1, 'objective-c', mfile, FixIt_Check_objc_NoFixIt ], # multiple errors on a single line; both with fixits [ 54, 15, 'cpp11', cfile, FixIt_Check_cpp11_MultiFirst ], [ 54, 16, 'cpp11', cfile, FixIt_Check_cpp11_MultiFirst ], [ 54, 16, 'cpp11', cfile, FixIt_Check_cpp11_MultiFirst ], [ 54, 17, 'cpp11', cfile, FixIt_Check_cpp11_MultiFirst ], [ 54, 18, 'cpp11', cfile, FixIt_Check_cpp11_MultiFirst ], # should put closest fix-it first? [ 54, 51, 'cpp11', cfile, FixIt_Check_cpp11_MultiSecond ], [ 54, 52, 'cpp11', cfile, FixIt_Check_cpp11_MultiSecond ], [ 54, 53, 'cpp11', cfile, FixIt_Check_cpp11_MultiSecond ], # unicode in line for fixit [ 21, 16, 'cpp11', ufile, FixIt_Check_unicode_Ins ], # FixIt attached to a "child" diagnostic (i.e. a Note) [ 60, 1, 'cpp11', cfile, FixIt_Check_cpp11_Note ], # FixIt due to forced spell checking [ 72, 9, 'cpp11', cfile, FixIt_Check_cpp11_SpellCheck ], ] for test in tests: yield RunFixItTest, test[0], test[1], test[2], test[3], test[4] @SharedYcmd def Subcommands_GetDoc_Variable_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 70, column_num = 24, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ char a_global_variable This really is a global variable. Type: char Name: a_global_variable --- This really is a global variable. The first line of comment is the brief.""" } ) @SharedYcmd def Subcommands_GetDoc_Method_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 22, column_num = 13, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ char with_brief() brevity is for suckers Type: char () Name: with_brief --- This is not the brief. \\brief brevity is for suckers This is more information """ } ) @SharedYcmd def Subcommands_GetDoc_Namespace_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 65, column_num = 14, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ namespace Test {} This is a test namespace Type: Name: Test --- This is a test namespace""" } ) # noqa @SharedYcmd def Subcommands_GetDoc_Undocumented_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 81, column_num = 17, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( ValueError, NO_DOCUMENTATION_MESSAGE ) ) @SharedYcmd def Subcommands_GetDoc_NoCursor_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 1, column_num = 1, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( ValueError, NO_DOCUMENTATION_MESSAGE ) ) # Following tests repeat the tests above, but without re-parsing the file @SharedYcmd def Subcommands_GetDocImprecise_Variable_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) app.post_json( '/event_notification', BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], contents = contents, event_name = 'FileReadyToParse' ) ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 70, column_num = 24, contents = contents, command_arguments = [ 'GetDocImprecise' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ char a_global_variable This really is a global variable. Type: char Name: a_global_variable --- This really is a global variable. The first line of comment is the brief.""" } ) @SharedYcmd def Subcommands_GetDocImprecise_Method_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) app.post_json( '/event_notification', BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], contents = contents, event_name = 'FileReadyToParse' ) ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 22, column_num = 13, contents = contents, command_arguments = [ 'GetDocImprecise' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ char with_brief() brevity is for suckers Type: char () Name: with_brief --- This is not the brief. \\brief brevity is for suckers This is more information """ } ) @SharedYcmd def Subcommands_GetDocImprecise_Namespace_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) app.post_json( '/event_notification', BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], contents = contents, event_name = 'FileReadyToParse' ) ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 65, column_num = 14, contents = contents, command_arguments = [ 'GetDocImprecise' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ namespace Test {} This is a test namespace Type: Name: Test --- This is a test namespace""" } ) # noqa @SharedYcmd def Subcommands_GetDocImprecise_Undocumented_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) app.post_json( '/event_notification', BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], contents = contents, event_name = 'FileReadyToParse' ) ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 81, column_num = 17, contents = contents, command_arguments = [ 'GetDocImprecise' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( ValueError, NO_DOCUMENTATION_MESSAGE ) ) @SharedYcmd def Subcommands_GetDocImprecise_NoCursor_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) app.post_json( '/event_notification', BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], contents = contents, event_name = 'FileReadyToParse' ) ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 1, column_num = 1, contents = contents, command_arguments = [ 'GetDocImprecise' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( ValueError, NO_DOCUMENTATION_MESSAGE ) ) @SharedYcmd def Subcommands_GetDocImprecise_NoReadyToParse_test( app ): filepath = PathToTestFile( 'GetDoc_Clang.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 11, column_num = 18, contents = contents, command_arguments = [ 'GetDocImprecise' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json eq_( response, { 'detailed_info': """\ int get_a_global_variable(bool test) This is a method which is only pretend global Type: int (bool) Name: get_a_global_variable --- This is a method which is only pretend global @param test Set this to true. Do it.""" } ) @SharedYcmd def Subcommands_GetDoc_Unicode_test( app ): filepath = PathToTestFile( 'unicode.cc' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cpp', compilation_flags = [ '-x', 'c++' ], line_num = 21, column_num = 16, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json pprint( response ) eq_( response, { 'detailed_info': """\ int member_with_å_unicøde This method has unicøde in it Type: int Name: member_with_å_unicøde --- This method has unicøde in it """ } ) ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/debug_info_test.py0000644000175000017500000000527713026170313023066 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, contains_string, matches_regexp from ycmd.tests.clang import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest @SharedYcmd def DebugInfo_ExtraConfLoaded_test( app ): app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) request_data = BuildRequest( filepath = PathToTestFile( 'basic.cpp' ), filetype = 'cpp' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'C-family completer debug information:\n' ' Configuration file found and loaded\n' ' Configuration path: .+\n' ' Flags: .+' ) ) @SharedYcmd def DebugInfo_NoExtraConfFound_test( app ): request_data = BuildRequest( filetype = 'cpp' ) # First time, an exception is raised when no .ycm_extra_conf.py file is found. assert_that( app.post_json( '/debug_info', request_data ).json, contains_string( 'C-family completer debug information:\n' ' No configuration file found' ) ) # Second time, None is returned as the .ycm_extra_conf.py path. assert_that( app.post_json( '/debug_info', request_data ).json, contains_string( 'C-family completer debug information:\n' ' No configuration file found' ) ) @IsolatedYcmd def DebugInfo_ExtraConfFoundButNotLoaded_test( app ): request_data = BuildRequest( filepath = PathToTestFile( 'basic.cpp' ), filetype = 'cpp' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'C-family completer debug information:\n' ' Configuration file found but not loaded\n' ' Configuration path: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/clang/flags_test.py0000644000175000017500000002727713026170313022065 0ustar onuronur# Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_, ok_ from ycmd.completers.cpp import flags from mock import patch, Mock from ycmd.tests.test_utils import MacOnly from hamcrest import assert_that, contains @patch( 'ycmd.extra_conf_store.ModuleForSourceFile', return_value = Mock() ) def FlagsForFile_BadNonUnicodeFlagsAreAlsoRemoved_test( *args ): fake_flags = { 'flags': [ bytes( b'-c' ), '-c', bytes( b'-foo' ), '-bar' ] } with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = fake_flags ): flags_object = flags.Flags() flags_list = flags_object.FlagsForFile( '/foo', False ) eq_( list( flags_list ), [ '-foo', '-bar' ] ) @patch( 'ycmd.extra_conf_store.ModuleForSourceFile', return_value = Mock() ) def FlagsForFile_FlagsCachedByDefault_test( *args ): flags_object = flags.Flags() results = { 'flags': [ '-x', 'c' ] } with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = results ): flags_list = flags_object.FlagsForFile( '/foo', False ) assert_that( flags_list, contains( '-x', 'c' ) ) results[ 'flags' ] = [ '-x', 'c++' ] with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = results ): flags_list = flags_object.FlagsForFile( '/foo', False ) assert_that( flags_list, contains( '-x', 'c' ) ) @patch( 'ycmd.extra_conf_store.ModuleForSourceFile', return_value = Mock() ) def FlagsForFile_FlagsNotCachedWhenDoCacheIsFalse_test( *args ): flags_object = flags.Flags() results = { 'flags': [ '-x', 'c' ], 'do_cache': False } with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = results ): flags_list = flags_object.FlagsForFile( '/foo', False ) assert_that( flags_list, contains( '-x', 'c' ) ) results[ 'flags' ] = [ '-x', 'c++' ] with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = results ): flags_list = flags_object.FlagsForFile( '/foo', False ) assert_that( flags_list, contains( '-x', 'c++' ) ) @patch( 'ycmd.extra_conf_store.ModuleForSourceFile', return_value = Mock() ) def FlagsForFile_FlagsCachedWhenDoCacheIsTrue_test( *args ): flags_object = flags.Flags() results = { 'flags': [ '-x', 'c' ], 'do_cache': True } with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = results ): flags_list = flags_object.FlagsForFile( '/foo', False ) assert_that( flags_list, contains( '-x', 'c' ) ) results[ 'flags' ] = [ '-x', 'c++' ] with patch( 'ycmd.completers.cpp.flags._CallExtraConfFlagsForFile', return_value = results ): flags_list = flags_object.FlagsForFile( '/foo', False ) assert_that( flags_list, contains( '-x', 'c' ) ) def SanitizeFlags_Passthrough_test(): eq_( [ '-foo', '-bar' ], list( flags._SanitizeFlags( [ '-foo', '-bar' ] ) ) ) def SanitizeFlags_ArchRemoved_test(): expected = [ '-foo', '-bar' ] to_remove = [ '-arch', 'arch_of_evil' ] eq_( expected, list( flags._SanitizeFlags( expected + to_remove ) ) ) eq_( expected, list( flags._SanitizeFlags( to_remove + expected ) ) ) eq_( expected, list( flags._SanitizeFlags( expected[ :1 ] + to_remove + expected[ -1: ] ) ) ) def RemoveUnusedFlags_Passthrough_test(): eq_( [ '-foo', '-bar' ], flags._RemoveUnusedFlags( [ '-foo', '-bar' ], 'file' ) ) def RemoveUnusedFlags_RemoveDashC_test(): expected = [ '-foo', '-bar' ] to_remove = [ '-c' ] filename = 'file' eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( to_remove + expected, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ -1: ], filename ) ) def RemoveUnusedFlags_RemoveColor_test(): expected = [ '-foo', '-bar' ] to_remove = [ '--fcolor-diagnostics' ] filename = 'file' eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( to_remove + expected, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ -1: ], filename ) ) def RemoveUnusedFlags_RemoveDashO_test(): expected = [ '-foo', '-bar' ] to_remove = [ '-o', 'output_name' ] filename = 'file' eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( to_remove + expected, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ -1: ], filename ) ) def RemoveUnusedFlags_RemoveMP_test(): expected = [ '-foo', '-bar' ] to_remove = [ '-MP' ] filename = 'file' eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( to_remove + expected, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ -1: ], filename ) ) def RemoveUnusedFlags_RemoveFilename_test(): expected = [ 'foo', '-bar' ] to_remove = [ 'file' ] filename = 'file' eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ 1: ], filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ -1: ], filename ) ) def RemoveUnusedFlags_RemoveFlagWithoutPrecedingDashFlag_test(): expected = [ 'g++', '-foo', '-x', 'c++', '-bar', 'include_dir' ] to_remove = [ 'unrelated_file' ] filename = 'file' eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ 1: ], filename ) ) def RemoveUnusedFlags_Depfiles_test(): full_flags = [ '/bin/clang', '-x', 'objective-c', '-arch', 'armv7', '-MMD', '-MT', 'dependencies', '-MF', 'file', '--serialize-diagnostics', 'diagnostics' ] expected = [ '/bin/clang', '-x', 'objective-c', '-arch', 'armv7', ] assert_that( flags._RemoveUnusedFlags( full_flags, 'test.m' ), contains( *expected ) ) def EnableTypoCorrection_Empty_test(): eq_( flags._EnableTypoCorrection( [] ), [ '-fspell-checking' ] ) def EnableTypoCorrection_Trivial_test(): eq_( flags._EnableTypoCorrection( [ '-x', 'c++' ] ), [ '-x', 'c++', '-fspell-checking' ] ) def EnableTypoCorrection_Reciprocal_test(): eq_( flags._EnableTypoCorrection( [ '-fno-spell-checking' ] ), [ '-fno-spell-checking' ] ) def EnableTypoCorrection_ReciprocalOthers_test(): eq_( flags._EnableTypoCorrection( [ '-x', 'c++', '-fno-spell-checking' ] ), [ '-x', 'c++', '-fno-spell-checking' ] ) def RemoveUnusedFlags_RemoveFilenameWithoutPrecedingInclude_test(): def tester( flag ): expected = [ 'clang', flag, '/foo/bar', '-isystem/zoo/goo' ] eq_( expected, flags._RemoveUnusedFlags( expected + to_remove, filename ) ) eq_( expected, flags._RemoveUnusedFlags( expected[ :1 ] + to_remove + expected[ 1: ], filename ) ) eq_( expected + expected[ 1: ], flags._RemoveUnusedFlags( expected + to_remove + expected[ 1: ], filename ) ) include_flags = [ '-isystem', '-I', '-iquote', '-isysroot', '--sysroot', '-gcc-toolchain', '-include', '-include-pch', '-iframework', '-F', '-imacros' ] to_remove = [ '/moo/boo' ] filename = 'file' for flag in include_flags: yield tester, flag def RemoveXclangFlags_test(): expected = [ '-I', '/foo/bar', '-DMACRO=Value' ] to_remove = [ '-Xclang', 'load', '-Xclang', 'libplugin.so', '-Xclang', '-add-plugin', '-Xclang', 'plugin-name' ] eq_( expected, flags._RemoveXclangFlags( expected + to_remove ) ) eq_( expected, flags._RemoveXclangFlags( to_remove + expected ) ) eq_( expected + expected, flags._RemoveXclangFlags( expected + to_remove + expected ) ) def AddLanguageFlagWhenAppropriate_Passthrough_test(): eq_( [ '-foo', '-bar' ], flags._AddLanguageFlagWhenAppropriate( [ '-foo', '-bar' ] ) ) def _AddLanguageFlagWhenAppropriateTester( compiler, language_flag = [] ): to_removes = [ [], [ '/usr/bin/ccache' ], [ 'some_command', 'another_command' ] ] expected = [ '-foo', '-bar' ] for to_remove in to_removes: eq_( [ compiler ] + language_flag + expected, flags._AddLanguageFlagWhenAppropriate( to_remove + [ compiler ] + expected ) ) def AddLanguageFlagWhenAppropriate_CCompiler_test(): compilers = [ 'cc', 'gcc', 'clang', '/usr/bin/cc', '/some/other/path', 'some_command' ] for compiler in compilers: yield _AddLanguageFlagWhenAppropriateTester, compiler def AddLanguageFlagWhenAppropriate_CppCompiler_test(): compilers = [ 'c++', 'g++', 'clang++', '/usr/bin/c++', '/some/other/path++', 'some_command++', 'c++-5', 'g++-5.1', 'clang++-3.7.3', '/usr/bin/c++-5', 'c++-5.11', 'g++-50.1.49', 'clang++-3.12.3', '/usr/bin/c++-10', '/some/other/path++-4.9.3', 'some_command++-5.1', '/some/other/path++-4.9.31', 'some_command++-5.10' ] for compiler in compilers: yield _AddLanguageFlagWhenAppropriateTester, compiler, [ '-x', 'c++' ] def ExtraClangFlags_test(): flags_object = flags.Flags() num_found = 0 for flag in flags_object.extra_clang_flags: if flag.startswith( '-resource-dir=' ): ok_( flag.endswith( 'clang_includes' ) ) num_found += 1 eq_( 1, num_found ) @MacOnly @patch( 'ycmd.completers.cpp.flags._GetMacClangVersionList', return_value = [ '1.0.0', '7.0.1', '7.0.2', '___garbage__' ] ) @patch( 'ycmd.completers.cpp.flags._MacClangIncludeDirExists', side_effect = [ False, True, True, True ] ) def Mac_LatestMacClangIncludes_test( *args ): eq_( flags._LatestMacClangIncludes(), [ '/Applications/Xcode.app/Contents/Developer/Toolchains/' 'XcodeDefault.xctoolchain/usr/lib/clang/7.0.2/include' ] ) @MacOnly def Mac_LatestMacClangIncludes_NoSuchDirectory_test(): def RaiseOSError( x ): raise OSError( x ) with patch( 'os.listdir', side_effect = RaiseOSError ): eq_( flags._LatestMacClangIncludes(), [] ) @MacOnly def Mac_PathsForAllMacToolchains_test(): eq_( flags._PathsForAllMacToolchains( 'test' ), [ '/Applications/Xcode.app/Contents/Developer/Toolchains/' 'XcodeDefault.xctoolchain/test', '/Library/Developer/CommandLineTools/test' ] ) ycmd-0+20161219+git486b809.orig/ycmd/tests/client_test.py0000644000175000017500000002256113026170313021152 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import native from base64 import b64decode, b64encode from hamcrest import assert_that, empty, equal_to, is_in from tempfile import NamedTemporaryFile import functools import json import os import psutil import re import requests import subprocess import sys import time import urllib.parse from ycmd.hmac_utils import CreateHmac, CreateRequestHmac, SecureBytesEqual from ycmd.tests import PathToTestFile from ycmd.tests.test_utils import BuildRequest from ycmd.user_options_store import DefaultOptions from ycmd.utils import ( CloseStandardStreams, CreateLogfile, GetUnusedLocalhostPort, ReadFile, RemoveIfExists, SafePopen, SetEnviron, ToBytes, ToUnicode ) HEADERS = { 'content-type': 'application/json' } HMAC_HEADER = 'x-ycm-hmac' HMAC_SECRET_LENGTH = 16 DIR_OF_THIS_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) ) PATH_TO_YCMD = os.path.join( DIR_OF_THIS_SCRIPT, '..' ) LOGFILE_FORMAT = 'server_{port}_{std}_' class Client_test( object ): def __init__( self ): self._location = None self._port = None self._hmac_secret = None self._servers = [] self._logfiles = [] self._options_dict = DefaultOptions() self._popen_handle = None def setUp( self ): self._hmac_secret = os.urandom( HMAC_SECRET_LENGTH ) self._options_dict[ 'hmac_secret' ] = ToUnicode( b64encode( self._hmac_secret ) ) def tearDown( self ): for server in self._servers: if server.is_running(): server.terminate() CloseStandardStreams( self._popen_handle ) for logfile in self._logfiles: RemoveIfExists( logfile ) def Start( self, idle_suicide_seconds = 60, check_interval_seconds = 60 * 10 ): # The temp options file is deleted by ycmd during startup with NamedTemporaryFile( mode = 'w+', delete = False ) as options_file: json.dump( self._options_dict, options_file ) options_file.flush() self._port = GetUnusedLocalhostPort() self._location = 'http://127.0.0.1:' + str( self._port ) # Define environment variable to enable subprocesses coverage. See: # http://coverage.readthedocs.org/en/coverage-4.0.3/subprocess.html env = os.environ.copy() SetEnviron( env, 'COVERAGE_PROCESS_START', '.coveragerc' ) ycmd_args = [ sys.executable, PATH_TO_YCMD, '--port={0}'.format( self._port ), '--options_file={0}'.format( options_file.name ), '--log=debug', '--idle_suicide_seconds={0}'.format( idle_suicide_seconds ), '--check_interval_seconds={0}'.format( check_interval_seconds ), ] stdout = CreateLogfile( LOGFILE_FORMAT.format( port = self._port, std = 'stdout' ) ) stderr = CreateLogfile( LOGFILE_FORMAT.format( port = self._port, std = 'stderr' ) ) self._logfiles.extend( [ stdout, stderr ] ) ycmd_args.append( '--stdout={0}'.format( stdout ) ) ycmd_args.append( '--stderr={0}'.format( stderr ) ) self._popen_handle = SafePopen( ycmd_args, stdin_windows = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, env = env ) self._servers.append( psutil.Process( self._popen_handle.pid ) ) self._WaitUntilReady() extra_conf = PathToTestFile( 'client', '.ycm_extra_conf.py' ) self.PostRequest( 'load_extra_conf_file', { 'filepath': extra_conf } ) def _IsReady( self, filetype = None ): params = { 'subserver': filetype } if filetype else None response = self.GetRequest( 'ready', params ) response.raise_for_status() return response.json() def _WaitUntilReady( self, filetype = None, timeout = 5 ): expiration = time.time() + timeout while True: try: if time.time() > expiration: server = ( 'the {0} subserver'.format( filetype ) if filetype else 'ycmd' ) raise RuntimeError( 'Waited for {0} to be ready for {1} seconds, ' 'aborting.'.format( server, timeout ) ) if self._IsReady( filetype ): return except requests.exceptions.ConnectionError: pass finally: time.sleep( 0.1 ) def StartSubserverForFiletype( self, filetype ): filepath = PathToTestFile( 'client', 'some_file' ) # Calling the BufferVisit event before the FileReadyToParse one is needed # for the TypeScript completer. self.PostRequest( 'event_notification', BuildRequest( filepath = filepath, filetype = filetype, event_name = 'BufferVisit' ) ) self.PostRequest( 'event_notification', BuildRequest( filepath = filepath, filetype = filetype, event_name = 'FileReadyToParse' ) ) self._WaitUntilReady( filetype ) response = self.PostRequest( 'debug_info', BuildRequest( filepath = filepath, filetype = filetype ) ).json() pid_match = re.search( 'process ID: (\d+)', response ) if not pid_match: raise RuntimeError( 'Cannot find PID in debug informations for {0} ' 'filetype.'.format( filetype ) ) subserver_pid = int( pid_match.group( 1 ) ) self._servers.append( psutil.Process( subserver_pid ) ) logfiles = re.findall( '(\S+\.log)', response ) if not logfiles: raise RuntimeError( 'Cannot find logfiles in debug informations for {0} ' 'filetype.'.format( filetype ) ) self._logfiles.extend( logfiles ) def AssertServersAreRunning( self ): for server in self._servers: assert_that( server.is_running(), equal_to( True ) ) def AssertServersShutDown( self, timeout = 5 ): _, alive_procs = psutil.wait_procs( self._servers, timeout = timeout ) assert_that( alive_procs, empty() ) def AssertLogfilesAreRemoved( self ): existing_logfiles = [] for logfile in self._logfiles: if os.path.isfile( logfile ): existing_logfiles.append( logfile ) assert_that( existing_logfiles, empty() ) def GetRequest( self, handler, params = None ): return self._Request( 'GET', handler, params = params ) def PostRequest( self, handler, data = None ): return self._Request( 'POST', handler, data = data ) def _ToUtf8Json( self, data ): return ToBytes( json.dumps( data ) if data else None ) def _Request( self, method, handler, data = None, params = None ): request_uri = self._BuildUri( handler ) data = self._ToUtf8Json( data ) headers = self._ExtraHeaders( method, request_uri, data ) response = requests.request( method, request_uri, headers = headers, data = data, params = params ) return response def _BuildUri( self, handler ): return native( ToBytes( urllib.parse.urljoin( self._location, handler ) ) ) def _ExtraHeaders( self, method, request_uri, request_body = None ): if not request_body: request_body = bytes( b'' ) headers = dict( HEADERS ) headers[ HMAC_HEADER ] = b64encode( CreateRequestHmac( ToBytes( method ), ToBytes( urllib.parse.urlparse( request_uri ).path ), request_body, self._hmac_secret ) ) return headers def AssertResponse( self, response ): assert_that( response.status_code, equal_to( requests.codes.ok ) ) assert_that( HMAC_HEADER, is_in( response.headers ) ) assert_that( self._ContentHmacValid( response ), equal_to( True ) ) def _ContentHmacValid( self, response ): our_hmac = CreateHmac( response.content, self._hmac_secret ) their_hmac = ToBytes( b64decode( response.headers[ HMAC_HEADER ] ) ) return SecureBytesEqual( our_hmac, their_hmac ) @staticmethod def CaptureLogfiles( test ): @functools.wraps( test ) def Wrapper( self, *args ): try: test( self, *args ) finally: for logfile in self._logfiles: if os.path.isfile( logfile ): sys.stdout.write( 'Logfile {0}:\n\n'.format( logfile ) ) sys.stdout.write( ReadFile( logfile ) ) sys.stdout.write( '\n' ) return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/filename_completer_test.py0000644000175000017500000003372213026170313023527 0ustar onuronur# coding: utf-8 # # Copyright (C) 2014 Davit Samvelyan # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os from hamcrest import assert_that, contains_inanyorder from nose.tools import eq_, ok_ from ycmd.completers.general.filename_completer import FilenameCompleter from ycmd.request_wrap import RequestWrap from ycmd import user_options_store from ycmd.tests.test_utils import CurrentWorkingDirectory, UserOption from ycmd.utils import GetCurrentDirectory, ToBytes TEST_DIR = os.path.dirname( os.path.abspath( __file__ ) ) DATA_DIR = os.path.join( TEST_DIR, 'testdata', 'filename_completer', 'inner_dir' ) PATH_TO_TEST_FILE = os.path.join( DATA_DIR, "test.cpp" ) REQUEST_DATA = { 'line_num': 1, 'filepath' : PATH_TO_TEST_FILE, 'file_data' : { PATH_TO_TEST_FILE : { 'filetypes' : [ 'cpp' ] } } } def _CompletionResultsForLine( filename_completer, contents, extra_data = None, column_num = None ): request = REQUEST_DATA.copy() # Strictly, column numbers are *byte* offsets, not character offsets. If # the contents of the file contain unicode characters, then we should manually # supply the correct byte offset. column_num = len( contents ) + 1 if not column_num else column_num request[ 'column_num' ] = column_num request[ 'file_data' ][ PATH_TO_TEST_FILE ][ 'contents' ] = contents if extra_data: request.update( extra_data ) request = RequestWrap( request ) candidates = filename_completer.ComputeCandidatesInner( request ) return [ ( c[ 'insertion_text' ], c[ 'extra_menu_info' ] ) for c in candidates ] def _ShouldUseNowForLine( filename_completer, contents, extra_data = None, column_num = None ): request = REQUEST_DATA.copy() # Strictly, column numbers are *byte* offsets, not character offsets. If # the contents of the file contain unicode characters, then we should manually # supply the correct byte offset. column_num = len( contents ) + 1 if not column_num else column_num request[ 'column_num' ] = column_num request[ 'file_data' ][ PATH_TO_TEST_FILE ][ 'contents' ] = contents if extra_data: request.update( extra_data ) request = RequestWrap( request ) return filename_completer.ShouldUseNow( request ) class FilenameCompleter_test( object ): def setUp( self ): self._filename_completer = FilenameCompleter( user_options_store.DefaultOptions() ) # We cache include flags for test.cpp file for unit testing. self._filename_completer._flags.flags_for_file[ PATH_TO_TEST_FILE ] = [ "-I", os.path.join( DATA_DIR, "include" ), "-I", os.path.join( DATA_DIR, "include", "Qt" ), "-I", os.path.join( DATA_DIR, "include", "QtGui" ), ] def _CompletionResultsForLine( self, contents, column_num=None ): return _CompletionResultsForLine( self._filename_completer, contents, column_num = column_num ) def _ShouldUseNowForLine( self, contents, column_num=None ): return _ShouldUseNowForLine( self._filename_completer, contents, column_num = column_num ) def QuotedIncludeCompletion_test( self ): data = self._CompletionResultsForLine( '#include "' ) eq_( [ ( u'foo漢字.txt', '[File]' ), ( 'include', '[Dir]' ), ( 'Qt', '[Dir]' ), ( 'QtGui', '[File&Dir]' ), ( 'QDialog', '[File]' ), ( 'QWidget', '[File]' ), ( 'test.cpp', '[File]' ), ( 'test.hpp', '[File]' ), ], data ) data = self._CompletionResultsForLine( '#include "include/' ) eq_( [ ( 'Qt', '[Dir]' ), ( 'QtGui', '[Dir]' ), ], data ) def IncludeCompletion_test( self ): data = self._CompletionResultsForLine( '#include <' ) eq_( [ ( 'Qt', '[Dir]' ), ( 'QtGui', '[File&Dir]' ), ( 'QDialog', '[File]' ), ( 'QWidget', '[File]' ), ], data ) data = self._CompletionResultsForLine( '#include . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that from mock import patch from nose.tools import eq_ import requests from ycmd.responses import NoDiagnosticSupport, BuildDisplayMessageResponse from ycmd.tests import SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, DummyCompleter, ErrorMatcher, MessageMatcher, PatchCompleter ) @SharedYcmd def Diagnostics_DoesntWork_test( app ): with PatchCompleter( DummyCompleter, filetype = 'dummy_filetype' ): diag_data = BuildRequest( contents = "foo = 5", line_num = 2, filetype = 'dummy_filetype' ) response = app.post_json( '/detailed_diagnostic', diag_data, expect_errors = True ) eq_( response.status_code, requests.codes.internal_server_error ) assert_that( response.json, ErrorMatcher( NoDiagnosticSupport ) ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.GetDetailedDiagnostic', return_value = BuildDisplayMessageResponse( 'detailed diagnostic' ) ) def Diagnostics_DoesWork_test( app, *args ): with PatchCompleter( DummyCompleter, filetype = 'dummy_filetype' ): diag_data = BuildRequest( contents = 'foo = 5', filetype = 'dummy_filetype' ) response = app.post_json( '/detailed_diagnostic', diag_data ) assert_that( response.json, MessageMatcher( 'detailed diagnostic' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/request_wrap_test.py0000644000175000017500000001525413026170313022416 0ustar onuronur# coding: utf-8 # # Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.utils import ToBytes from nose.tools import eq_ from ..request_wrap import RequestWrap def PrepareJson( contents = '', line_num = 1, column_num = 1, filetype = '' ): return { 'line_num': line_num, 'column_num': column_num, 'filepath': '/foo', 'file_data': { '/foo': { 'filetypes': [ filetype ], 'contents': contents } } } def LineValue_OneLine_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 1, contents = 'zoo' ) )[ 'line_value' ] ) def LineValue_LastLine_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 3, contents = 'goo\nbar\nzoo' ) )[ 'line_value' ] ) def LineValue_MiddleLine_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 2, contents = 'goo\nzoo\nbar' ) )[ 'line_value' ] ) def LineValue_WindowsLines_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 3, contents = 'goo\r\nbar\r\nzoo' ) )[ 'line_value' ] ) def LineValue_MixedFormatLines_test(): eq_( 'zoo', RequestWrap( PrepareJson( line_num = 3, contents = 'goo\nbar\r\nzoo' ) )[ 'line_value' ] ) def LineValue_EmptyContents_test(): eq_( '', RequestWrap( PrepareJson( line_num = 1, contents = '' ) )[ 'line_value' ] ) def StartColumn_RightAfterDot_test(): eq_( 5, RequestWrap( PrepareJson( column_num = 5, contents = 'foo.') )[ 'start_column' ] ) def StartColumn_Dot_test(): eq_( 5, RequestWrap( PrepareJson( column_num = 8, contents = 'foo.bar') )[ 'start_column' ] ) def StartColumn_DotWithUnicode_test(): eq_( 7, RequestWrap( PrepareJson( column_num = 11, contents = 'fäö.bär') )[ 'start_column' ] ) def StartColumn_UnicodeNotIdentifier_test(): contents = "var x = '†es†ing'." # † not considered an identifier character for i in range( 13, 15 ): print( ToBytes( contents )[ i - 1 : i ] ) eq_( 13, RequestWrap( PrepareJson( column_num = i, contents = contents ) )[ 'start_column' ] ) eq_( 13, RequestWrap( PrepareJson( column_num = 15, contents = contents ) )[ 'start_column' ] ) for i in range( 18, 20 ): print( ToBytes( contents )[ i - 1 : i ] ) eq_( 18, RequestWrap( PrepareJson( column_num = i, contents = contents ) )[ 'start_column' ] ) def StartColumn_QueryIsUnicode_test(): contents = "var x = ålpha.alphå" eq_( 16, RequestWrap( PrepareJson( column_num = 16, contents = contents ) )[ 'start_column' ] ) eq_( 16, RequestWrap( PrepareJson( column_num = 19, contents = contents ) )[ 'start_column' ] ) def StartColumn_QueryStartsWithUnicode_test(): contents = "var x = ålpha.ålpha" eq_( 16, RequestWrap( PrepareJson( column_num = 16, contents = contents ) )[ 'start_column' ] ) eq_( 16, RequestWrap( PrepareJson( column_num = 19, contents = contents ) )[ 'start_column' ] ) def StartColumn_ThreeByteUnicode_test(): contents = "var x = '†'." eq_( 15, RequestWrap( PrepareJson( column_num = 15, contents = contents ) )[ 'start_column' ] ) def StartColumn_Paren_test(): eq_( 5, RequestWrap( PrepareJson( column_num = 8, contents = 'foo(bar') )[ 'start_column' ] ) def StartColumn_AfterWholeWord_test(): eq_( 1, RequestWrap( PrepareJson( column_num = 7, contents = 'foobar') )[ 'start_column' ] ) def StartColumn_AfterWholeWord_Html_test(): eq_( 1, RequestWrap( PrepareJson( column_num = 7, filetype = 'html', contents = 'fo-bar') )[ 'start_column' ] ) def StartColumn_AfterWholeUnicodeWord_test(): eq_( 1, RequestWrap( PrepareJson( column_num = 6, contents = u'fäö') )[ 'start_column' ] ) def StartColumn_InMiddleOfWholeWord_test(): eq_( 1, RequestWrap( PrepareJson( column_num = 4, contents = 'foobar') )[ 'start_column' ] ) def StartColumn_ColumnOne_test(): eq_( 1, RequestWrap( PrepareJson( column_num = 1, contents = 'foobar') )[ 'start_column' ] ) def Query_AtWordEnd_test(): eq_( 'foo', RequestWrap( PrepareJson( column_num = 4, contents = 'foo') )[ 'query' ] ) def Query_InWordMiddle_test(): eq_( 'foo', RequestWrap( PrepareJson( column_num = 4, contents = 'foobar') )[ 'query' ] ) def Query_StartOfLine_test(): eq_( '', RequestWrap( PrepareJson( column_num = 1, contents = 'foobar') )[ 'query' ] ) def Query_StopsAtParen_test(): eq_( 'bar', RequestWrap( PrepareJson( column_num = 8, contents = 'foo(bar') )[ 'query' ] ) def Query_InWhiteSpace_test(): eq_( '', RequestWrap( PrepareJson( column_num = 8, contents = 'foo ') )[ 'query' ] ) def Query_UnicodeSinglecharInclusive_test(): eq_( 'ø', RequestWrap( PrepareJson( column_num = 7, contents = 'abc.ø' ) )[ 'query' ] ) def Query_UnicodeSinglecharExclusive_test(): eq_( '', RequestWrap( PrepareJson( column_num = 5, contents = 'abc.ø' ) )[ 'query' ] ) ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/0000755000175000017500000000000013026170313020463 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/0000755000175000017500000000000013026170313022274 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/unicode.ts0000644000175000017500000000065513026170313024300 0ustar onuronur class Bår { methodA( a: { foo: string; bar: number; } ) {} methød() { return '†est'.cha } å: number; åbc: number; abc: number; a: number; } var baz = new Bår(); baz.å; baz.abc; baz.a; baz.å; var føø_long_long = new Bår(); føø_long_long.methød(); føø_long_long.å; føø_long_long.åbc; føø_long_long.abc; /** * Test unicøde st†††† */ class Båøz { } ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/file2.ts0000644000175000017500000000003013026170313023636 0ustar onuronurnew Bar().testMethod(); ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/tsconfig.json0000644000175000017500000000020413026170313024777 0ustar onuronur{ "compilerOptions": { "noEmit": true }, "files": [ "test.ts", "file2.ts", "file3.ts", "unicode.ts" ] } ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/file3.ts0000644000175000017500000000004713026170313023647 0ustar onuronurvar bar = new Bar(); bar.testMethod(); ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/buffer_unload/0000755000175000017500000000000013026170313025107 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/buffer_unload/main.ts0000644000175000017500000000012013026170313026374 0ustar onuronurimport { Imported } from "./imported"; let imported = new Imported(); imported. ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/buffer_unload/imported.ts0000644000175000017500000000005713026170313027304 0ustar onuronurexport class Imported { method() { } } ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/testdata/test.ts0000644000175000017500000000061113026170313023621 0ustar onuronur class Foo { // Unicode string: 说话 methodA() {} methodB() {} methodC( a: { foo: string; bar: number; } ) {} } var foo = new Foo(); // line 12, column 6 foo.m /** * Class documentation * * Multi-line */ class Bar { /** * Method documentation */ testMethod() {} } var bar = new Bar(); bar.testMethod(); bar.nonExistingMethod(); Bar.apply() ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/get_completions_test.py0000644000175000017500000001463713026170313025302 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( all_of, any_of, assert_that, calling, contains_inanyorder, has_entries, has_item, is_not, raises ) from mock import patch from webtest import AppError from ycmd.tests.typescript import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, StopCompleterServer ) from ycmd.utils import ReadFile def RunTest( app, test ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, force_semantic = True, line_num = 17, column_num = 6 ) response = app.post_json( '/completions', completion_data ) assert_that( response.json, test[ 'expect' ][ 'data' ] ) @SharedYcmd def GetCompletions_Basic_test( app ): RunTest( app, { 'expect': { 'data': has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'methodA', extra_params = { 'menu_text': 'methodA (method) Foo.methodA(): void' } ), CompletionEntryMatcher( 'methodB', extra_params = { 'menu_text': 'methodB (method) Foo.methodB(): void' } ), CompletionEntryMatcher( 'methodC', extra_params = { 'menu_text': ( 'methodC (method) Foo.methodC(a: ' '{ foo: string; bar: number; }): void' ) } ), ) } ) } } ) @SharedYcmd @patch( 'ycmd.completers.typescript.' 'typescript_completer.MAX_DETAILED_COMPLETIONS', 2 ) def GetCompletions_MaxDetailedCompletion_test( app ): RunTest( app, { 'expect': { 'data': has_entries( { 'completions': all_of( contains_inanyorder( CompletionEntryMatcher( 'methodA' ), CompletionEntryMatcher( 'methodB' ), CompletionEntryMatcher( 'methodC' ), ), is_not( any_of( has_item( CompletionEntryMatcher( 'methodA', extra_params = { 'menu_text': 'methodA (method) Foo.methodA(): void' } ) ), has_item( CompletionEntryMatcher( 'methodB', extra_params = { 'menu_text': 'methodB (method) Foo.methodB(): void' } ) ), has_item( CompletionEntryMatcher( 'methodC', extra_params = { 'menu_text': ( 'methodC (method) Foo.methodC(a: ' '{ foo: string; bar: number; }): void' ) } ) ) ) ) ) } ) } } ) @SharedYcmd def GetCompletions_AfterRestart_test( app ): filepath = PathToTestFile( 'test.ts' ) app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'RestartServer' ], filetype = 'typescript', filepath = filepath ) ) completion_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = ReadFile( filepath ), force_semantic = True, line_num = 17, column_num = 6 ) response = app.post_json( '/completions', completion_data ) assert_that( response.json, has_entries( { 'completions': contains_inanyorder( CompletionEntryMatcher( 'methodA', extra_params = { 'menu_text': 'methodA (method) Foo.methodA(): void' } ), CompletionEntryMatcher( 'methodB', extra_params = { 'menu_text': 'methodB (method) Foo.methodB(): void' } ), CompletionEntryMatcher( 'methodC', extra_params = { 'menu_text': ( 'methodC (method) Foo.methodC(a: ' '{ foo: string; bar: number; }): void' ) } ), ) } ) ) @IsolatedYcmd def GetCompletions_ServerIsNotRunning_test( app ): StopCompleterServer( app, filetype = 'typescript' ) filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) # Check that sending a request to TSServer (the response is ignored) raises # the proper exception. event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) assert_that( calling( app.post_json ).with_args( '/event_notification', event_data ), raises( AppError, 'TSServer is not running.' ) ) # Check that sending a command to TSServer (the response is processed) raises # the proper exception. completion_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, force_semantic = True, line_num = 17, column_num = 6 ) assert_that( calling( app.post_json ).with_args( '/completions', completion_data ), raises( AppError, 'TSServer is not running.' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/__init__.py0000644000175000017500000000573213026170313022603 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd import handlers from ycmd.tests.test_utils import ( ClearCompletionsCache, SetUpApp, StopCompleterServer, WaitUntilCompleterServerReady ) shared_app = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() WaitUntilCompleterServerReady( shared_app, 'typescript' ) def tearDownPackage(): global shared_app StopCompleterServer( shared_app, 'typescript' ) def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state app = SetUpApp() try: test( app, *args, **kwargs ) finally: StopCompleterServer( app, 'typescript' ) handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/event_notification_test.py0000644000175000017500000001173113026170313025766 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, contains, has_entries from ycmd.tests.typescript import IsolatedYcmd, PathToTestFile from ycmd.tests.test_utils import ( BuildRequest, ClearCompletionsCache, CompletionEntryMatcher ) from ycmd.utils import ReadFile @IsolatedYcmd def EventNotification_OnBufferUnload_CloseFile_test( app ): # Open main.ts file in a buffer. main_filepath = PathToTestFile( 'buffer_unload', 'main.ts' ) main_contents = ReadFile( main_filepath ) event_data = BuildRequest( filepath = main_filepath, filetype = 'typescript', contents = main_contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) # Complete in main.ts buffer an object defined in imported.ts. completion_data = BuildRequest( filepath = main_filepath, filetype = 'typescript', contents = main_contents, line_num = 3, column_num = 10 ) response = app.post_json( '/completions', completion_data ) assert_that( response.json, has_entries( { 'completions': contains( CompletionEntryMatcher( 'method' ) ) } ) ) # FIXME: we should not have to clear the cache. ClearCompletionsCache() # Open imported.ts file in another buffer. imported_filepath = PathToTestFile( 'buffer_unload', 'imported.ts' ) imported_contents = ReadFile( imported_filepath ) event_data = BuildRequest( filepath = imported_filepath, filetype = 'typescript', contents = imported_contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) # Modify imported.ts buffer without writing the changes to disk. modified_imported_contents = imported_contents.replace( 'method', 'modified_method' ) # FIXME: TypeScript completer should not rely on the FileReadyToParse events # to synchronize the contents of dirty buffers but use instead the file_data # field of the request. event_data = BuildRequest( filepath = imported_filepath, filetype = 'typescript', contents = modified_imported_contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) # Complete at same location in main.ts buffer. imported_data = { imported_filepath: { 'filetypes': [ 'typescript' ], 'contents': modified_imported_contents } } completion_data = BuildRequest( filepath = main_filepath, filetype = 'typescript', contents = main_contents, line_num = 3, column_num = 10, file_data = imported_data ) response = app.post_json( '/completions', completion_data ) assert_that( response.json, has_entries( { 'completions': contains( CompletionEntryMatcher( 'modified_method' ) ) } ) ) # FIXME: we should not have to clear the cache. ClearCompletionsCache() # Unload imported.ts buffer. event_data = BuildRequest( filepath = imported_filepath, filetype = 'typescript', contents = imported_contents, event_name = 'BufferUnload' ) app.post_json( '/event_notification', event_data ) # Complete at same location in main.ts buffer. completion_data = BuildRequest( filepath = main_filepath, filetype = 'typescript', contents = main_contents, line_num = 3, column_num = 10 ) response = app.post_json( '/completions', completion_data ) assert_that( response.json, has_entries( { 'completions': contains( CompletionEntryMatcher( 'method' ) ) } ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/subcommands_test.py0000644000175000017500000005452313026170313024420 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa import pprint from hamcrest import ( assert_that, contains, contains_inanyorder, has_entries ) from ycmd.tests.typescript import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, ChunkMatcher, ErrorMatcher, LocationMatcher, MessageMatcher ) from ycmd.utils import ReadFile @SharedYcmd def Subcommands_GetType_Basic_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 17, column_num = 1, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', gettype_data ).json assert_that( response, MessageMatcher( 'var foo: Foo' ) ) @SharedYcmd def Subcommands_GetType_HasNoType_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 2, column_num = 1, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', gettype_data, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, 'No content available.' ) ) @SharedYcmd def Subcommands_GetDoc_Method_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetDoc' ], line_num = 34, column_num = 9, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', gettype_data ).json assert_that( response, has_entries( { 'detailed_info': '(method) Bar.testMethod(): void\n\n' 'Method documentation' } ) ) @SharedYcmd def Subcommands_GetDoc_Class_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetDoc' ], line_num = 37, column_num = 2, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', gettype_data ).json assert_that( response, has_entries( { 'detailed_info': 'class Bar\n\n' 'Class documentation\n\n' 'Multi-line' } ) ) @SharedYcmd def Subcommands_GetDoc_Class_Unicode_test( app ): filepath = PathToTestFile( 'unicode.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetDoc' ], line_num = 35, column_num = 12, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', gettype_data ).json assert_that( response, has_entries( { 'detailed_info': 'class Båøz\n\n' 'Test unicøde st††††', } ) ) @SharedYcmd def Subcommands_GoToReferences_test( app ): filepath = PathToTestFile( 'test.ts' ) file3 = PathToTestFile( 'file3.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) references_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToReferences' ], line_num = 33, column_num = 6, contents = contents, filetype = 'typescript', filepath = filepath ) expected = contains_inanyorder( has_entries( { 'description': 'var bar = new Bar();', 'line_num' : 33, 'column_num' : 5, 'filepath' : filepath } ), has_entries( { 'description': 'bar.testMethod();', 'line_num' : 34, 'column_num' : 1, 'filepath' : filepath } ), has_entries( { 'description': 'bar.nonExistingMethod();', 'line_num' : 35, 'column_num' : 1, 'filepath' : filepath } ), has_entries( { 'description': 'var bar = new Bar();', 'line_num' : 1, 'column_num' : 5, 'filepath' : file3 } ), has_entries( { 'description': 'bar.testMethod();', 'line_num' : 2, 'column_num' : 1, 'filepath' : file3 } ) ) actual = app.post_json( '/run_completer_command', references_data ).json pprint.pprint( actual ) assert_that( actual, expected ) @SharedYcmd def Subcommands_GoToReferences_Unicode_test( app ): filepath = PathToTestFile( 'unicode.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) references_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToReferences' ], line_num = 14, column_num = 3, contents = contents, filetype = 'typescript', filepath = filepath ) expected = contains_inanyorder( has_entries( { 'description': ' å: number;', 'line_num' : 14, 'column_num' : 3, 'filepath' : filepath } ), has_entries( { 'description': 'var baz = new Bår(); baz.å;', 'line_num' : 20, 'column_num' : 27, 'filepath' : filepath } ), has_entries( { 'description': 'baz.å;', 'line_num' : 23, 'column_num' : 5, 'filepath' : filepath } ), has_entries( { 'description': 'føø_long_long.å;', 'line_num' : 27, 'column_num' : 17, 'filepath' : filepath } ) ) actual = app.post_json( '/run_completer_command', references_data ).json pprint.pprint( actual ) assert_that( actual, expected ) @SharedYcmd def Subcommands_GoTo_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToDefinition' ], line_num = 34, column_num = 9, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', goto_data ).json assert_that( response, has_entries( { 'filepath': filepath, 'line_num': 30, 'column_num': 3, } ) ) @SharedYcmd def Subcommands_GoTo_Unicode_test( app ): filepath = PathToTestFile( 'unicode.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToDefinition' ], line_num = 28, column_num = 19, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', goto_data ).json assert_that( response, has_entries( { 'filepath': filepath, 'line_num': 15, 'column_num': 3, } ) ) @SharedYcmd def Subcommands_GoTo_Fail_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToDefinition' ], line_num = 35, column_num = 6, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', goto_data, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, 'Could not find definition' ) ) @SharedYcmd def Subcommands_GoToType_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToType' ], line_num = 14, column_num = 6, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', goto_data ).json assert_that( response, has_entries( { 'filepath': filepath, 'line_num': 2, 'column_num': 1, } ) ) @SharedYcmd def Subcommands_GoToType_fail_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToType' ], line_num = 39, column_num = 8, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', goto_data, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, 'Could not find type definition' ) ) @SharedYcmd def Subcommands_RefactorRename_Missing_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) request = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'RefactorRename' ], line_num = 30, column_num = 6, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', request, expect_errors = True ).json assert_that( response, ErrorMatcher( ValueError, 'Please specify a new name to rename it to.\n' 'Usage: RefactorRename ' ) ) @SharedYcmd def Subcommands_RefactorRename_NotPossible_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) request = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'RefactorRename', 'whatever' ], line_num = 35, column_num = 5, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', request, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, 'Value cannot be renamed: ' 'You cannot rename this element.' ) ) @SharedYcmd def Subcommands_RefactorRename_Simple_test( app ): filepath = PathToTestFile( 'test.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) request = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'RefactorRename', 'test' ], line_num = 2, column_num = 8, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', request ).json pprint.pprint( response, indent = 2 ) assert_that( response, has_entries ( { 'fixits': contains( has_entries( { 'chunks': contains_inanyorder( ChunkMatcher( 'test', LocationMatcher( filepath, 14, 15 ), LocationMatcher( filepath, 14, 18 ) ), ChunkMatcher( 'test', LocationMatcher( filepath, 2, 7 ), LocationMatcher( filepath, 2, 10 ) ), ), 'location': LocationMatcher( filepath, 2, 8 ) } ) ) } ) ) @SharedYcmd def Subcommands_RefactorRename_MultipleFiles_test( app ): filepath = PathToTestFile( 'test.ts' ) file2 = PathToTestFile( 'file2.ts' ) file3 = PathToTestFile( 'file3.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) request = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'RefactorRename', 'this-is-a-longer-string' ], line_num = 25, column_num = 9, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', request ).json pprint.pprint( response, indent = 2 ) assert_that( response, has_entries ( { 'fixits': contains( has_entries( { 'chunks': contains_inanyorder( ChunkMatcher( 'this-is-a-longer-string', LocationMatcher( filepath, 25, 7 ), LocationMatcher( filepath, 25, 10 ) ), ChunkMatcher( 'this-is-a-longer-string', LocationMatcher( filepath, 33, 15 ), LocationMatcher( filepath, 33, 18 ) ), ChunkMatcher( 'this-is-a-longer-string', LocationMatcher( filepath, 37, 1 ), LocationMatcher( filepath, 37, 4 ) ), ChunkMatcher( 'this-is-a-longer-string', LocationMatcher( file2, 1, 5 ), LocationMatcher( file2, 1, 8 ) ), ChunkMatcher( 'this-is-a-longer-string', LocationMatcher( file3, 1, 15 ), LocationMatcher( file3, 1, 18 ) ), ), 'location': LocationMatcher( filepath, 25, 9 ) } ) ) } ) ) @SharedYcmd def Subcommands_RefactorRename_SimpleUnicode_test( app ): filepath = PathToTestFile( 'unicode.ts' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'typescript', contents = contents, event_name = 'BufferVisit' ) app.post_json( '/event_notification', event_data ) request = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'RefactorRename', 'ø' ], line_num = 14, column_num = 3, contents = contents, filetype = 'typescript', filepath = filepath ) response = app.post_json( '/run_completer_command', request ).json pprint.pprint( response, indent = 2 ) assert_that( response, has_entries ( { 'fixits': contains( has_entries( { 'chunks': contains_inanyorder( ChunkMatcher( 'ø', LocationMatcher( filepath, 14, 3 ), LocationMatcher( filepath, 14, 5 ) ), ChunkMatcher( 'ø', LocationMatcher( filepath, 20, 27 ), LocationMatcher( filepath, 20, 29 ) ), ChunkMatcher( 'ø', LocationMatcher( filepath, 23, 5 ), LocationMatcher( filepath, 23, 7 ) ), ChunkMatcher( 'ø', LocationMatcher( filepath, 27, 17), LocationMatcher( filepath, 27, 19 ) ), ), 'location': LocationMatcher( filepath, 14, 3 ) } ) ) } ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/typescript/debug_info_test.py0000644000175000017500000000504713026170313024203 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, matches_regexp from ycmd.tests.typescript import IsolatedYcmd, SharedYcmd, StopCompleterServer from ycmd.tests.test_utils import BuildRequest, UserOption @SharedYcmd def DebugInfo_ServerIsRunning_test( app ): request_data = BuildRequest( filetype = 'typescript' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'TypeScript completer debug information:\n' ' TSServer running\n' ' TSServer process ID: \d+\n' ' TSServer executable: .+\n' ' TSServer logfile: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesExist_test( app ): with UserOption( 'server_keep_logfiles', True ): StopCompleterServer( app, filetype = 'typescript' ) request_data = BuildRequest( filetype = 'typescript' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'TypeScript completer debug information:\n' ' TSServer no longer running\n' ' TSServer executable: .+\n' ' TSServer logfile: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesDoNotExist_test( app ): with UserOption( 'server_keep_logfiles', False ): StopCompleterServer( app, filetype = 'typescript' ) request_data = BuildRequest( filetype = 'typescript' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'TypeScript completer debug information:\n' ' TSServer is not running\n' ' TSServer executable: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/request_validation_test.py0000644000175000017500000000624013026170313023572 0ustar onuronur# Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import raises, assert_that, calling from nose.tools import ok_ from ycmd.request_validation import EnsureRequestValid from ycmd.responses import ServerError def BasicData(): return { 'line_num': 1, 'column_num': 2, 'filepath': '/foo', 'file_data': { '/foo': { 'filetypes': [ 'text' ], 'contents': 'zoobar' } } } def EnsureRequestValid_AllOk_test(): ok_( EnsureRequestValid( BasicData() ) ) def EnsureRequestValid_MissingLineNum_test(): data = BasicData() del data[ 'line_num' ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*line_num.*" ) ) def EnsureRequestValid_MissingColumnNum_test(): data = BasicData() del data[ 'column_num' ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*column_num.*" ) ) def EnsureRequestValid_MissingFilepath_test(): data = BasicData() del data[ 'filepath' ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*filepath.*" ) ) def EnsureRequestValid_MissingFileData_test(): data = BasicData() del data[ 'file_data' ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*file_data.*" ) ) def EnsureRequestValid_MissingFileDataContents_test(): data = BasicData() del data[ 'file_data' ][ '/foo' ][ 'contents' ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*contents.*" ) ) def EnsureRequestValid_MissingFileDataFiletypes_test(): data = BasicData() del data[ 'file_data' ][ '/foo' ][ 'filetypes' ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*filetypes.*" ) ) def EnsureRequestValid_EmptyFileDataFiletypes_test(): data = BasicData() del data[ 'file_data' ][ '/foo' ][ 'filetypes' ][ 0 ] assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*filetypes.*" ) ) def EnsureRequestValid_MissingEntryForFileInFileData_test(): data = BasicData() data[ 'filepath' ] = '/bar' assert_that( calling( EnsureRequestValid ).with_args( data ), raises( ServerError, ".*/bar.*" ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/test_utils.py0000644000175000017500000002162613026170313021035 0ustar onuronur# Copyright (C) 2013 Google Inc. # 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library from future.utils import iteritems standard_library.install_aliases() from builtins import * # noqa from future.utils import PY2 from hamcrest import contains_string, has_entry, has_entries, assert_that from mock import patch from webtest import TestApp import bottle import contextlib import nose import functools import os import tempfile import time import stat from ycmd import handlers, user_options_store from ycmd.completers.completer import Completer from ycmd.responses import BuildCompletionData from ycmd.utils import GetCurrentDirectory, OnMac, OnWindows, ToUnicode import ycm_core try: from unittest import skipIf except ImportError: from unittest2 import skipIf Py2Only = skipIf( not PY2, 'Python 2 only' ) Py3Only = skipIf( PY2, 'Python 3 only' ) WindowsOnly = skipIf( not OnWindows(), 'Windows only' ) ClangOnly = skipIf( not ycm_core.HasClangSupport(), 'Only when Clang support available' ) MacOnly = skipIf( not OnMac(), 'Mac only' ) UnixOnly = skipIf( OnWindows(), 'Unix only' ) def BuildRequest( **kwargs ): filepath = kwargs[ 'filepath' ] if 'filepath' in kwargs else '/foo' contents = kwargs[ 'contents' ] if 'contents' in kwargs else '' filetype = kwargs[ 'filetype' ] if 'filetype' in kwargs else 'foo' request = { 'line_num': 1, 'column_num': 1, 'filepath': filepath, 'file_data': { filepath: { 'contents': contents, 'filetypes': [ filetype ] } } } for key, value in iteritems( kwargs ): if key in [ 'contents', 'filetype', 'filepath' ]: continue if key in request and isinstance( request[ key ], dict ): # allow updating the 'file_data' entry request[ key ].update( value ) else: request[ key ] = value return request def ErrorMatcher( cls, msg = None ): """ Returns a hamcrest matcher for a server exception response """ entry = { 'exception': has_entry( 'TYPE', cls.__name__ ) } if msg: entry.update( { 'message': msg } ) return has_entries( entry ) def CompletionEntryMatcher( insertion_text, extra_menu_info = None, extra_params = None ): match = { 'insertion_text': insertion_text } if extra_menu_info: match.update( { 'extra_menu_info': extra_menu_info } ) if extra_params: match.update( extra_params ) return has_entries( match ) def CompletionLocationMatcher( location_type, value ): return has_entry( 'extra_data', has_entry( 'location', has_entry( location_type, value ) ) ) def MessageMatcher( msg ): return has_entry( 'message', contains_string( msg ) ) def LocationMatcher( filepath, line_num, column_num ): return has_entries( { 'line_num': line_num, 'column_num': column_num, 'filepath': filepath } ) def ChunkMatcher( replacement_text, start, end ): return has_entries( { 'replacement_text': replacement_text, 'range': has_entries( { 'start': start, 'end': end } ) } ) def LineColMatcher( line, col ): return has_entries( { 'line_num': line, 'column_num': col } ) @contextlib.contextmanager def PatchCompleter( completer, filetype ): user_options = handlers._server_state._user_options with patch.dict( 'ycmd.handlers._server_state._filetype_completers', { filetype: completer( user_options ) } ): yield @contextlib.contextmanager def UserOption( key, value ): try: current_options = dict( user_options_store.GetAll() ) user_options = current_options.copy() user_options.update( { key: value } ) handlers.UpdateUserOptions( user_options ) yield user_options finally: handlers.UpdateUserOptions( current_options ) @contextlib.contextmanager def CurrentWorkingDirectory( path ): old_cwd = GetCurrentDirectory() os.chdir( path ) try: yield old_cwd finally: os.chdir( old_cwd ) # The "exe" suffix is needed on Windows and not harmful on other platforms. @contextlib.contextmanager def TemporaryExecutable( extension = '.exe' ): with tempfile.NamedTemporaryFile( prefix = 'Temp', suffix = extension ) as executable: os.chmod( executable.name, stat.S_IXUSR ) yield executable.name def SetUpApp(): bottle.debug( True ) handlers.SetServerStateToDefaults() return TestApp( handlers.app ) def StartCompleterServer( app, filetype, filepath = '/foo' ): app.post_json( '/run_completer_command', BuildRequest( command_arguments = [ 'RestartServer' ], filetype = filetype, filepath = filepath ) ) def StopCompleterServer( app, filetype, filepath = '/foo' ): app.post_json( '/run_completer_command', BuildRequest( command_arguments = [ 'StopServer' ], filetype = filetype, filepath = filepath ), expect_errors = True ) def WaitUntilCompleterServerReady( app, filetype ): retries = 100 while retries > 0: result = app.get( '/ready', { 'subserver': filetype } ).json if result: return time.sleep( 0.2 ) retries = retries - 1 raise RuntimeError( 'Timeout waiting for "{0}" filetype completer'.format( filetype ) ) def ClearCompletionsCache(): """Invalidates cached completions for completers stored in the server state: filetype completers and general completers (identifier, filename, and ultisnips completers). This function is used when sharing the application between tests so that no completions are cached by previous tests.""" server_state = handlers._server_state for completer in server_state.GetLoadedFiletypeCompleters(): completer._completions_cache.Invalidate() general_completer = server_state.GetGeneralCompleter() for completer in general_completer._all_completers: completer._completions_cache.Invalidate() class DummyCompleter( Completer ): def __init__( self, user_options ): super( DummyCompleter, self ).__init__( user_options ) def SupportedFiletypes( self ): return [] def ComputeCandidatesInner( self, request_data ): return [ BuildCompletionData( candidate ) for candidate in self.CandidatesList() ] # This method is here for testing purpose, so it can be mocked during tests def CandidatesList( self ): return [] def ExpectedFailure( reason, *exception_matchers ): """Defines a decorator to be attached to tests. This decorator marks the test as being known to fail, e.g. where documenting or exercising known incorrect behaviour. The parameters are: - |reason| a textual description of the reason for the known issue. This is used for the skip reason - |exception_matchers| additional arguments are hamcrest matchers to apply to the exception thrown. If the matchers don't match, then the test is marked as error, with the original exception. If the test fails (for the correct reason), then it is marked as skipped. If it fails for any other reason, it is marked as failed. If the test passes, then it is also marked as failed.""" def decorator( test ): @functools.wraps( test ) def Wrapper( *args, **kwargs ): try: test( *args, **kwargs ) except Exception as test_exception: # Ensure that we failed for the right reason test_exception_message = ToUnicode( test_exception ) try: for matcher in exception_matchers: assert_that( test_exception_message, matcher ) except AssertionError: # Failed for the wrong reason! import traceback print( 'Test failed for the wrong reason: ' + traceback.format_exc() ) # Real failure reason is the *original* exception, we're only trapping # and ignoring the exception that is expected. raise test_exception # Failed for the right reason raise nose.SkipTest( reason ) else: raise AssertionError( 'Test was expected to fail: {0}'.format( reason ) ) return Wrapper return decorator ycmd-0+20161219+git486b809.orig/ycmd/tests/python_support_test.py0000644000175000017500000001072513026170313023010 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . # Intentionally not importing unicode_literals! from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() # Intentionally not importing all builtins! import os from nose.tools import eq_ from future.utils import native import ycm_core from ycmd.tests.test_utils import ClangOnly, Py2Only, Py3Only from ycmd.utils import ToBytes, ToUnicode, OnWindows # We don't use PathToTestFile from test_utils module because this module # imports future modules that may change the path type. PATH_TO_TESTDATA = os.path.abspath( os.path.join( os.path.dirname( __file__ ), 'testdata' ) ) PATH_TO_COMPILE_COMMANDS = ( os.path.join( PATH_TO_TESTDATA, 'windows' ) if OnWindows() else os.path.join( PATH_TO_TESTDATA, 'unix' ) ) COMPILE_COMMANDS_WORKING_DIR = 'C:\\dir' if OnWindows() else '/dir' @Py2Only def GetUtf8String_Py2Str_test(): eq_( 'foo', str( ycm_core.GetUtf8String( 'foo' ) ) ) @Py3Only def GetUtf8String_Py3Bytes_test(): eq_( 'foo', str( ycm_core.GetUtf8String( b'foo' ) ) ) # No test for `bytes` from builtins because it's very difficult to make # GetUtf8String work with that and also it should never receive that type in the # first place (only py2 str/unicode and py3 bytes/str). def GetUtf8String_Unicode_test(): eq_( 'foo', str( ycm_core.GetUtf8String( u'foo' ) ) ) @ClangOnly @Py2Only def CompilationDatabase_Py2Str_test(): cc_dir = native( ToBytes( PATH_TO_COMPILE_COMMANDS ) ) cc_filename = native( ToBytes( os.path.join( COMPILE_COMMANDS_WORKING_DIR, 'example.cc' ) ) ) # Ctor reads ycmd/tests/testdata/[unix|windows]/compile_commands.json db = ycm_core.CompilationDatabase( cc_dir ) info = db.GetCompilationInfoForFile( cc_filename ) eq_( str( info.compiler_working_dir_ ), COMPILE_COMMANDS_WORKING_DIR ) eq_( str( info.compiler_flags_[ 0 ] ), '/usr/bin/clang++' ) eq_( str( info.compiler_flags_[ 1 ] ), 'example.cc' ) @ClangOnly @Py2Only def CompilationDatabase_Py2Unicode_test(): cc_dir = native( ToUnicode( PATH_TO_COMPILE_COMMANDS ) ) cc_filename = native( ToUnicode( os.path.join( COMPILE_COMMANDS_WORKING_DIR, 'example.cc' ) ) ) # Ctor reads ycmd/tests/testdata/[unix|windows]/compile_commands.json db = ycm_core.CompilationDatabase( cc_dir ) info = db.GetCompilationInfoForFile( cc_filename ) eq_( str( info.compiler_working_dir_ ), COMPILE_COMMANDS_WORKING_DIR ) eq_( str( info.compiler_flags_[ 0 ] ), '/usr/bin/clang++' ) eq_( str( info.compiler_flags_[ 1 ] ), 'example.cc' ) @ClangOnly @Py3Only def CompilationDatabase_Py3Bytes_test(): cc_dir = native( ToBytes( PATH_TO_COMPILE_COMMANDS ) ) cc_filename = native( ToBytes( os.path.join( COMPILE_COMMANDS_WORKING_DIR, 'example.cc' ) ) ) # Ctor reads ycmd/tests/testdata/[unix|windows]/compile_commands.json db = ycm_core.CompilationDatabase( cc_dir ) info = db.GetCompilationInfoForFile( cc_filename ) eq_( str( info.compiler_working_dir_ ), COMPILE_COMMANDS_WORKING_DIR ) eq_( str( info.compiler_flags_[ 0 ] ), '/usr/bin/clang++' ) eq_( str( info.compiler_flags_[ 1 ] ), 'example.cc' ) @ClangOnly def CompilationDatabase_NativeString_test(): cc_dir = PATH_TO_COMPILE_COMMANDS cc_filename = os.path.join( COMPILE_COMMANDS_WORKING_DIR, 'example.cc' ) # Ctor reads ycmd/tests/testdata/[unix|windows]/compile_commands.json db = ycm_core.CompilationDatabase( cc_dir ) info = db.GetCompilationInfoForFile( cc_filename ) eq_( str( info.compiler_working_dir_ ), COMPILE_COMMANDS_WORKING_DIR ) eq_( str( info.compiler_flags_[ 0 ] ), '/usr/bin/clang++' ) eq_( str( info.compiler_flags_[ 1 ] ), 'example.cc' ) ycmd-0+20161219+git486b809.orig/ycmd/tests/completer_test.py0000644000175000017500000000564213026170313021667 0ustar onuronur# Copyright (C) 2016 ycmd contributors. # encoding: utf-8 # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.tests.test_utils import DummyCompleter, ExpectedFailure from ycmd.user_options_store import DefaultOptions from mock import patch from nose.tools import eq_ from hamcrest import contains_string def _FilterAndSortCandidates_Match( candidates, query, expected_matches ): completer = DummyCompleter( DefaultOptions() ) matches = completer.FilterAndSortCandidates( candidates, query ) eq_( expected_matches, matches ) def FilterAndSortCandidates_OmniCompleter_List_test(): _FilterAndSortCandidates_Match( [ 'password' ], 'p', [ 'password' ] ) _FilterAndSortCandidates_Match( [ 'words' ], 'w', [ 'words' ] ) def FilterAndSortCandidates_OmniCompleter_Dictionary_test(): _FilterAndSortCandidates_Match( { 'words': [ 'password' ] }, 'p', [ 'password' ] ) _FilterAndSortCandidates_Match( { 'words': [ { 'word': 'password' } ] }, 'p', [ { 'word': 'password' } ] ) def FilterAndSortCandidates_ServerCompleter_test(): _FilterAndSortCandidates_Match( [ { 'insertion_text': 'password' } ], 'p', [ { 'insertion_text': 'password' } ] ) @ExpectedFailure( 'Filtering does not support unicode characters', contains_string( '[]' ) ) def FilterAndSortCandidates_Unicode_test(): _FilterAndSortCandidates_Match( [ { 'insertion_text': 'ø' } ], 'ø', [ { 'insertion_text': 'ø' } ] ) @patch( 'ycmd.tests.test_utils.DummyCompleter.GetSubcommandsMap', return_value = { 'Foo': '', 'StopServer': '' } ) def DefinedSubcommands_RemoveStopServerSubcommand_test( subcommands_map ): completer = DummyCompleter( DefaultOptions() ) eq_( completer.DefinedSubcommands(), [ 'Foo' ] ) ycmd-0+20161219+git486b809.orig/ycmd/tests/completer_utils_test.py0000644000175000017500000002042713026170313023105 0ustar onuronur# coding: utf-8 # # Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . # Intentionally not importing unicode_literals! from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import iteritems import re from collections import defaultdict from nose.tools import eq_, ok_ from ycmd.completers import completer_utils as cu def _ExtractPatternsFromFiletypeTriggerDict( triggerDict ): """Returns a copy of the dictionary with the _sre.SRE_Pattern instances in each set value replaced with the pattern strings. Needed for equality test of two filetype trigger dictionaries.""" copy = triggerDict.copy() for key, values in iteritems( triggerDict ): copy[ key ] = set( [ sre_pattern.pattern for sre_pattern in values ] ) return copy def FiletypeTriggerDictFromSpec_Works_test(): eq_( defaultdict( set, { 'foo': set( [ cu._PrepareTrigger( 'zoo').pattern, cu._PrepareTrigger( 'bar' ).pattern ] ), 'goo': set( [ cu._PrepareTrigger( 'moo' ).pattern ] ), 'moo': set( [ cu._PrepareTrigger( 'moo' ).pattern ] ), 'qux': set( [ cu._PrepareTrigger( 'q' ).pattern ] ) } ), _ExtractPatternsFromFiletypeTriggerDict( cu._FiletypeTriggerDictFromSpec( { 'foo': ['zoo', 'bar'], 'goo,moo': ['moo'], 'qux': ['q'] } ) ) ) def FiletypeDictUnion_Works_test(): eq_( defaultdict( set, { 'foo': set(['zoo', 'bar', 'maa']), 'goo': set(['moo']), 'bla': set(['boo']), 'qux': set(['q']) } ), cu._FiletypeDictUnion( defaultdict( set, { 'foo': set(['zoo', 'bar']), 'goo': set(['moo']), 'qux': set(['q']) } ), defaultdict( set, { 'foo': set(['maa']), 'bla': set(['boo']), 'qux': set(['q']) } ) ) ) def PrepareTrigger_UnicodeTrigger_Test(): regex = cu._PrepareTrigger( 'æ' ) eq_( regex.pattern, u'\\æ' ) def MatchesSemanticTrigger_Basic_test(): triggers = [ cu._PrepareTrigger( '.' ) ] ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 7, 7, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 6, 7, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 5, 7, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo.bar', 4, 7, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo.bar', 3, 7, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo.bar', 2, 7, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo.bar', 1, 7, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo.bar', 0, 7, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 3, 3, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 2, 3, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 1, 3, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 0, 3, triggers ) ) def MatchesSemanticTrigger_JustTrigger_test(): triggers = [ cu._PrepareTrigger( '.' ) ] ok_( not cu._MatchesSemanticTrigger( '.', 2, 2, triggers ) ) ok_( cu._MatchesSemanticTrigger( '.', 1, 1, triggers ) ) ok_( not cu._MatchesSemanticTrigger( '.', 0, 0, triggers ) ) def MatchesSemanticTrigger_TriggerBetweenWords_test(): triggers = [ cu._PrepareTrigger( '.' ) ] ok_( not cu._MatchesSemanticTrigger( 'foo . bar', 6, 9, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo . bar', 5, 9, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo . bar', 4, 9, triggers ) ) def MatchesSemanticTrigger_BadInput_test(): triggers = [ cu._PrepareTrigger( '.' ) ] ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 10, 7, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', -1, 7, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 4, -1, triggers ) ) ok_( not cu._MatchesSemanticTrigger( '', -1, 0, triggers ) ) ok_( not cu._MatchesSemanticTrigger( '', 0, 0, triggers ) ) ok_( not cu._MatchesSemanticTrigger( '', 1, 0, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 4, 7, [] ) ) def MatchesSemanticTrigger_TriggerIsWrong_test(): triggers = [ cu._PrepareTrigger( ':' ) ] ok_( not cu._MatchesSemanticTrigger( 'foo.bar', 4, 7, triggers ) ) def MatchesSemanticTrigger_LongerTrigger_test(): triggers = [ cu._PrepareTrigger( '::' ) ] ok_( not cu._MatchesSemanticTrigger( 'foo::bar', 6, 8, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo::bar', 5, 8, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo::bar', 4, 8, triggers ) ) ok_( cu._MatchesSemanticTrigger( 'foo::bar', 3, 8, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo::bar', 4, 4, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo::bar', 3, 4, triggers ) ) def MatchesSemanticTrigger_OneTriggerMatches_test(): triggers = [ cu._PrepareTrigger( '.' ), cu._PrepareTrigger( ';' ), cu._PrepareTrigger( '::' ) ] ok_( cu._MatchesSemanticTrigger( 'foo::bar', 5, 8, triggers ) ) def MatchesSemanticTrigger_RegexTrigger_test(): triggers = [ cu._PrepareTrigger( r're!\w+\.' ) ] ok_( cu._MatchesSemanticTrigger( 'foo.bar', 4, 8, triggers ) ) ok_( not cu._MatchesSemanticTrigger( 'foo . bar', 5, 8, triggers ) ) def MatchingSemanticTrigger_Basic_test(): triggers = [ cu._PrepareTrigger( '.' ), cu._PrepareTrigger( ';' ), cu._PrepareTrigger( '::' ) ] eq_( cu._MatchingSemanticTrigger( 'foo->bar', 5, 9, triggers ), None ) eq_( cu._MatchingSemanticTrigger( 'foo::bar', 5, 9, triggers ).pattern, re.escape( '::' ) ) def PreparedTriggers_Basic_test(): triggers = cu.PreparedTriggers() ok_( triggers.MatchesForFiletype( 'foo.bar', 4, 8, 'c' ) ) eq_( triggers.MatchingTriggerForFiletype( 'foo.bar', 4, 8, 'c' ).pattern, re.escape( '.' ) ) ok_( triggers.MatchesForFiletype( 'foo->bar', 5, 9, 'cpp' ) ) eq_( triggers.MatchingTriggerForFiletype( 'foo->bar', 5, 9, 'cpp' ).pattern, re.escape( '->' ) ) def PreparedTriggers_OnlySomeFiletypesSelected_test(): triggers = cu.PreparedTriggers( filetype_set = set( 'c' ) ) ok_( triggers.MatchesForFiletype( 'foo.bar', 4, 7, 'c' ) ) eq_( triggers.MatchingTriggerForFiletype( 'foo.bar', 4, 7, 'c' ).pattern, re.escape( '.' ) ) ok_( not triggers.MatchesForFiletype( 'foo->bar', 5, 8, 'cpp' ) ) eq_( triggers.MatchingTriggerForFiletype( 'foo->bar', 5, 8, 'cpp' ), None ) def PreparedTriggers_UserTriggers_test(): triggers = cu.PreparedTriggers( user_trigger_map = { 'c': ['->'] } ) ok_( triggers.MatchesForFiletype( 'foo->bar', 5, 8, 'c' ) ) eq_( triggers.MatchingTriggerForFiletype( 'foo->bar', 5, 8, 'c' ).pattern, re.escape( '->' ) ) def PreparedTriggers_ObjectiveC_test(): triggers = cu.PreparedTriggers() # Bracketed calls ok_( triggers.MatchesForFiletype( '[foo ', 5, 6, 'objc' ) ) ok_( not triggers.MatchesForFiletype( '[foo', 4, 5, 'objc' ) ) ok_( not triggers.MatchesForFiletype( '[3foo ', 6, 6, 'objc' ) ) ok_( triggers.MatchesForFiletype( '[f3oo ', 6, 6, 'objc' ) ) ok_( triggers.MatchesForFiletype( '[[foo ', 6, 6, 'objc' ) ) # Bracketless calls ok_( not triggers.MatchesForFiletype( '3foo ', 5, 5, 'objc' ) ) ok_( triggers.MatchesForFiletype( 'foo3 ', 5, 5, 'objc' ) ) ok_( triggers.MatchesForFiletype( 'foo ', 4, 4, 'objc' ) ) # Method composition ok_( triggers.MatchesForFiletype( '[NSString stringWithFormat:@"Test %@", stuff] ', 46, 46, 'objc' ) ) ok_( triggers.MatchesForFiletype( ' [NSString stringWithFormat:@"Test"] ', 39, 39, 'objc' ) ) ok_( triggers.MatchesForFiletype( ' [[NSString stringWithFormat:@"Test"] stringByAppendingString:%@] ', 68, 68, 'objc' ) ) ok_( not triggers.MatchesForFiletype( '// foo ', 8, 8, 'objc' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/shutdown_test.py0000644000175000017500000000536013026170313021545 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, equal_to from ycmd.tests.client_test import Client_test class Shutdown_test( Client_test ): @Client_test.CaptureLogfiles def FromHandlerWithoutSubserver_test( self ): self.Start() self.AssertServersAreRunning() response = self.PostRequest( 'shutdown' ) self.AssertResponse( response ) assert_that( response.json(), equal_to( True ) ) self.AssertServersShutDown( timeout = 5 ) self.AssertLogfilesAreRemoved() @Client_test.CaptureLogfiles def FromHandlerWithSubservers_test( self ): self.Start() filetypes = [ 'cs', 'go', 'javascript', 'python', 'typescript', 'rust' ] for filetype in filetypes: self.StartSubserverForFiletype( filetype ) self.AssertServersAreRunning() response = self.PostRequest( 'shutdown' ) self.AssertResponse( response ) assert_that( response.json(), equal_to( True ) ) self.AssertServersShutDown( timeout = 5 ) self.AssertLogfilesAreRemoved() @Client_test.CaptureLogfiles def FromWatchdogWithoutSubserver_test( self ): self.Start( idle_suicide_seconds = 2, check_interval_seconds = 1 ) self.AssertServersAreRunning() self.AssertServersShutDown( timeout = 5 ) self.AssertLogfilesAreRemoved() @Client_test.CaptureLogfiles def FromWatchdogWithSubservers_test( self ): self.Start( idle_suicide_seconds = 5, check_interval_seconds = 1 ) filetypes = [ 'cs', 'go', 'javascript', 'python', 'typescript', 'rust' ] for filetype in filetypes: self.StartSubserverForFiletype( filetype ) self.AssertServersAreRunning() self.AssertServersShutDown( timeout = 15 ) self.AssertLogfilesAreRemoved() ycmd-0+20161219+git486b809.orig/ycmd/tests/subcommands_test.py0000644000175000017500000000412713026170313022205 0ustar onuronur# Copyright (C) 2013 Google Inc. # 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from mock import patch from nose.tools import eq_ from ycmd.tests import SharedYcmd from ycmd.tests.test_utils import BuildRequest, DummyCompleter, PatchCompleter @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.GetSubcommandsMap', return_value = { 'A': lambda x: x, 'B': lambda x: x, 'C': lambda x: x } ) def Subcommands_Basic_test( app, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): subcommands_data = BuildRequest( completer_target = 'dummy_filetype' ) eq_( [ 'A', 'B', 'C' ], app.post_json( '/defined_subcommands', subcommands_data ).json ) @SharedYcmd @patch( 'ycmd.tests.test_utils.DummyCompleter.GetSubcommandsMap', return_value = { 'A': lambda x: x, 'B': lambda x: x, 'C': lambda x: x } ) def Subcommands_NoExplicitCompleterTargetSpecified_test( app, *args ): with PatchCompleter( DummyCompleter, 'dummy_filetype' ): subcommands_data = BuildRequest( filetype = 'dummy_filetype' ) eq_( [ 'A', 'B', 'C' ], app.post_json( '/defined_subcommands', subcommands_data ).json ) ycmd-0+20161219+git486b809.orig/ycmd/tests/python/0000755000175000017500000000000013026170313017576 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/0000755000175000017500000000000013026170313021407 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/goto_file2.py0000644000175000017500000000004213026170313024006 0ustar onuronurfrom goto_file3 import bar as foo ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/goto_file3.py0000644000175000017500000000002213026170313024005 0ustar onuronurdef bar(): pass ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/unicode.py0000644000175000017500000000006513026170313023410 0ustar onuronurdef Foo(): """aafäö""" pass Fo x = '†'.cen ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/GetDoc.py0000644000175000017500000000044213026170313023126 0ustar onuronur class TestClass: """ Class Documentation""" def TestMethod(self): """ Method Documentation """ return self.member_variable def _ModuleMethod(): """ Module method docs Are dedented, like you might expect""" pass _ModuleMethod() tc = TestClass() tc.TestMethod() ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/goto_file4.py0000644000175000017500000000003113026170313024006 0ustar onuronurfrom math import sin sin ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/goto_file1.py0000644000175000017500000000003713026170313024011 0ustar onuronurfrom goto_file2 import foo foo ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/basic.py0000644000175000017500000000012513026170313023040 0ustar onuronurclass Foo(object): def __init__(self): self.a = 1 self.b = 2 f = Foo() f. ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/goto_file5.py0000644000175000017500000000003713026170313024015 0ustar onuronurclass Foo(object): pass Bar ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/general_fallback/0000755000175000017500000000000013026170313024643 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/general_fallback/lang_python.py0000644000175000017500000000175413026170313027546 0ustar onuronurclass DoSomething: def __init__(self): self.this_is_well_known = 'too easy' # Jedi is smart enough to spot self.a_parameter = 1, but not if we just hack # it in some other method hack(self) pass def hack( obj ): obj.a_parameter = 'secret' def a_method( abc, **kwargs ): print abc obj.another_parameter = a_method def Main(): a_thing = DoSomething() # TESTCASE1: param jedi knows about # 1 2 3 4 #234567890123456789012345678901234567890123456789 print a_thing.this_is_well_known # TESTCASE2: param jedi does not know about # 1 2 3 4 #234567890123456789012345678901234567890123456789 print a_thing.a_parameter # TESTCASE3: method jedi does not know about # 1 2 3 4 #234567890123456789012345678901234567890123456789 a_thing.another_parameter( 'test' ) # to ensure we can run this script to test the code actually makes sense! if __name__ == "__main__": Main() ycmd-0+20161219+git486b809.orig/ycmd/tests/python/testdata/goto_references.py0000644000175000017500000000005113026170313025126 0ustar onuronurdef f(): pass a = f() b = f() c = f() ycmd-0+20161219+git486b809.orig/ycmd/tests/python/get_completions_test.py0000644000175000017500000001270213026170313024404 0ustar onuronur# coding: utf-8 # # Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_ from hamcrest import ( assert_that, has_item, has_items, has_entry, has_entries, contains, empty, contains_string ) import requests from ycmd.utils import ReadFile from ycmd.tests.python import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, CompletionLocationMatcher ) @SharedYcmd def GetCompletions_Basic_test( app ): filepath = PathToTestFile( 'basic.py' ) completion_data = BuildRequest( filepath = filepath, filetype = 'python', contents = ReadFile( filepath ), line_num = 7, column_num = 3) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( 'a' ), CompletionEntryMatcher( 'b' ), CompletionLocationMatcher( 'line_num', 3 ), CompletionLocationMatcher( 'line_num', 4 ), CompletionLocationMatcher( 'column_num', 10 ), CompletionLocationMatcher( 'filepath', filepath ) ) ) @SharedYcmd def GetCompletions_UnicodeDescription_test( app ): filepath = PathToTestFile( 'unicode.py' ) completion_data = BuildRequest( filepath = filepath, filetype = 'python', contents = ReadFile( filepath ), force_semantic = True, line_num = 5, column_num = 3) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_item( has_entry( 'detailed_info', contains_string( u'aafäö' ) ) ) ) def RunTest( app, test ): """ Method to run a simple completion test and verify the result test is a dictionary containing: 'request': kwargs for BuildRequest 'expect': { 'response': server response code (e.g. httplib.OK) 'data': matcher for the server response json } """ contents = ReadFile( test[ 'request' ][ 'filepath' ] ) def CombineRequest( request, data ): kw = request request.update( data ) return BuildRequest( **kw ) app.post_json( '/event_notification', CombineRequest( test[ 'request' ], { 'event_name': 'FileReadyToParse', 'contents': contents, } ) ) # We ignore errors here and we check the response code ourself. # This is to allow testing of requests returning errors. response = app.post_json( '/completions', CombineRequest( test[ 'request' ], { 'contents': contents } ), expect_errors = True ) eq_( response.status_code, test[ 'expect' ][ 'response' ] ) assert_that( response.json, test[ 'expect' ][ 'data' ] ) @SharedYcmd def GetCompletions_NoSuggestions_Fallback_test( app ): # Python completer doesn't raise NO_COMPLETIONS_MESSAGE, so this is a # different code path to the Clang completer cases # TESTCASE2 (general_fallback/lang_python.py) RunTest( app, { 'description': 'param jedi does not know about (id). query="a_p"', 'request': { 'filetype' : 'python', 'filepath' : PathToTestFile( 'general_fallback', 'lang_python.py' ), 'line_num' : 28, 'column_num': 20, 'force_semantic': False, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'a_parameter', '[ID]' ), CompletionEntryMatcher( 'another_parameter', '[ID]' ), ), 'errors': empty(), } ) }, } ) @SharedYcmd def GetCompletions_Unicode_InLine_test( app ): RunTest( app, { 'description': 'return completions for strings with multi-byte chars', 'request': { 'filetype' : 'python', 'filepath' : PathToTestFile( 'unicode.py' ), 'line_num' : 7, 'column_num': 14 }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'center', 'function: builtins.str.center' ) ), 'errors': empty(), } ) }, } ) ycmd-0+20161219+git486b809.orig/ycmd/tests/python/__init__.py0000644000175000017500000000613413026170313021713 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd import handlers from ycmd.tests.test_utils import ( ClearCompletionsCache, SetUpApp, StopCompleterServer, WaitUntilCompleterServerReady ) shared_app = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() WaitUntilCompleterServerReady( shared_app, 'python' ) def tearDownPackage(): """Cleans up the tests using the SharedYcmd decorator in this package. It is executed once after running all the tests in the package.""" global shared_app StopCompleterServer( shared_app, 'python' ) def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state app = SetUpApp() try: test( app, *args, **kwargs ) finally: StopCompleterServer( app, 'python' ) handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/python/user_defined_python_test.py0000644000175000017500000001236613026170313025254 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest.core.base_matcher import BaseMatcher from hamcrest import assert_that, has_item, contains, equal_to, is_not # noqa from mock import patch import sys from ycmd import utils from ycmd.completers.python.jedi_completer import BINARY_NOT_FOUND_MESSAGE from ycmd.tests.python import IsolatedYcmd from ycmd.tests.test_utils import BuildRequest, ErrorMatcher, UserOption class CalledWith( BaseMatcher ): def __init__( self, python ): self._python = python def _extract_python( self, popen ): def safe_first( l, default ): return next( iter( l ), default ) call = popen.call_args if not call: return None # The python that SafePopen used is inside a `call` object which contains: # - a tuple of the given positional arguments # - kwargs # call( ( ['python', 'arg1', 'arg2' ], ... ), kwargs ) args, kwargs = call return safe_first( safe_first( args, [ None ] ), None ) def _matches( self, popen ): executable = self._extract_python( popen ) return executable == self._python def describe_to( self, description ): description.append_description_of( self._python ) def describe_mismatch( self, item, description ): python = self._extract_python( item ) if python: description.append_description_of( python ) else: description.append_text( 'not called' ) def was_called_with_python( python ): return CalledWith( python ) @IsolatedYcmd @patch( 'ycmd.utils.SafePopen' ) def UserDefinedPython_WithoutAnyOption_DefaultToYcmdPython_test( app, *args ): app.get( '/ready', { 'subserver': 'python' } ) assert_that( utils.SafePopen, was_called_with_python( sys.executable ) ) @IsolatedYcmd @patch( 'ycmd.utils.SafePopen' ) @patch( 'ycmd.utils.FindExecutable', return_value = None ) def UserDefinedPython_WhenNonExistentPythonIsGiven_ReturnAnError_test( app, *args ): python = '/non/existing/path/python' with UserOption( 'python_binary_path', python ): response = app.get( '/ready', { 'subserver': 'python' }, expect_errors = True ).json msg = BINARY_NOT_FOUND_MESSAGE.format( python ) assert_that( response, ErrorMatcher( RuntimeError, msg ) ) utils.SafePopen.assert_not_called() @IsolatedYcmd @patch( 'ycmd.utils.SafePopen' ) @patch( 'ycmd.utils.FindExecutable', side_effect = lambda x: x ) def UserDefinedPython_WhenExistingPythonIsGiven_ThatIsUsed_test( app, *args ): python = '/existing/python' with UserOption( 'python_binary_path', python ): app.get( '/ready', { 'subserver': 'python' } ).json assert_that( utils.SafePopen, was_called_with_python( python ) ) @IsolatedYcmd @patch( 'ycmd.utils.SafePopen' ) @patch( 'ycmd.utils.FindExecutable', side_effect = lambda x: x ) def UserDefinedPython_RestartServerWithoutArguments_WillReuseTheLastPython_test( app, *args ): request = BuildRequest( filetype = 'python', command_arguments = [ 'RestartServer' ] ) app.post_json( '/run_completer_command', request ) assert_that( utils.SafePopen, was_called_with_python( sys.executable ) ) @IsolatedYcmd @patch( 'ycmd.utils.SafePopen' ) @patch( 'ycmd.utils.FindExecutable', side_effect = lambda x: x ) def UserDefinedPython_RestartServerWithArgument_WillUseTheSpecifiedPython_test( app, *args ): python = '/existing/python' request = BuildRequest( filetype = 'python', command_arguments = [ 'RestartServer', python ] ) app.post_json( '/run_completer_command', request ) assert_that( utils.SafePopen, was_called_with_python( python ) ) @IsolatedYcmd @patch( 'ycmd.utils.SafePopen' ) @patch( 'ycmd.utils.FindExecutable', return_value = None ) def UserDefinedPython_RestartServerWithNonExistingPythonArgument_test( app, *args ): python = '/non/existing/python' request = BuildRequest( filetype = 'python', command_arguments = [ 'RestartServer', python ] ) response = app.post_json( '/run_completer_command', request, expect_errors = True ).json msg = BINARY_NOT_FOUND_MESSAGE.format( python ) assert_that( response, ErrorMatcher( RuntimeError, msg ) ) assert_that( utils.SafePopen, was_called_with_python( sys.executable ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/python/subcommands_test.py0000644000175000017500000001522413026170313023526 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that from nose.tools import eq_ import os.path from ycmd.utils import ReadFile from ycmd.tests.python import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, ErrorMatcher @SharedYcmd def RunGoToTest( app, test ): filepath = PathToTestFile( test[ 'request' ][ 'filename' ] ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoTo' ], line_num = test[ 'request' ][ 'line_num' ], contents = ReadFile( filepath ), filetype = 'python', filepath = filepath ) eq_( test[ 'response' ], app.post_json( '/run_completer_command', goto_data ).json ) def Subcommands_GoTo_test(): # Tests taken from https://github.com/Valloric/YouCompleteMe/issues/1236 tests = [ { 'request': { 'filename': 'goto_file1.py', 'line_num': 2 }, 'response': { 'filepath': PathToTestFile( 'goto_file3.py' ), 'line_num': 1, 'column_num': 5 } }, { 'request': { 'filename': 'goto_file4.py', 'line_num': 2 }, 'response': { 'filepath': PathToTestFile( 'goto_file4.py' ), 'line_num': 1, 'column_num': 18 } } ] for test in tests: yield RunGoToTest, test @SharedYcmd def RunGoToTest_Variation_ZeroBasedLineAndColumn( app, test ): # Example taken directly from jedi docs # http://jedi.jedidjah.ch/en/latest/docs/plugin-api.html#examples contents = """ def my_func(): print 'called' alias = my_func my_list = [1, None, alias] inception = my_list[2] inception() """ goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = test[ 'command_arguments' ], line_num = 9, contents = contents, filetype = 'python', filepath = '/foo.py' ) eq_( test[ 'response' ], app.post_json( '/run_completer_command', goto_data ).json ) def Subcommands_GoTo_Variation_ZeroBasedLineAndColumn_test(): tests = [ { 'command_arguments': [ 'GoToDefinition' ], 'response': { 'filepath': os.path.abspath( '/foo.py' ), 'line_num': 2, 'column_num': 5 } }, { 'command_arguments': [ 'GoToDeclaration' ], 'response': { 'filepath': os.path.abspath( '/foo.py' ), 'line_num': 7, 'column_num': 1 } } ] for test in tests: yield RunGoToTest_Variation_ZeroBasedLineAndColumn, test @SharedYcmd def Subcommands_GoToDefinition_NotFound_test( app ): filepath = PathToTestFile( 'goto_file5.py' ) goto_data = BuildRequest( command_arguments = [ 'GoToDefinition' ], line_num = 4, contents = ReadFile( filepath ), filetype = 'python', filepath = filepath ) response = app.post_json( '/run_completer_command', goto_data, expect_errors = True ).json assert_that( response, ErrorMatcher( RuntimeError, "Can\'t jump to definition." ) ) @SharedYcmd def Subcommands_GetDoc_Method_test( app ): # Testcase1 filepath = PathToTestFile( 'GetDoc.py' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'python', line_num = 17, column_num = 9, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json eq_( response, { 'detailed_info': '_ModuleMethod()\n\n' 'Module method docs\n' 'Are dedented, like you might expect', } ) @SharedYcmd def Subcommands_GetDoc_Class_test( app ): # Testcase1 filepath = PathToTestFile( 'GetDoc.py' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'python', line_num = 19, column_num = 2, contents = contents, command_arguments = [ 'GetDoc' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json eq_( response, { 'detailed_info': 'Class Documentation', } ) @SharedYcmd def Subcommands_GoToReferences_test( app ): filepath = PathToTestFile( 'goto_references.py' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'python', line_num = 4, column_num = 5, contents = contents, command_arguments = [ 'GoToReferences' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data ).json eq_( response, [ { 'filepath': PathToTestFile( 'goto_references.py' ), 'column_num': 5, 'description': 'def f', 'line_num': 1 }, { 'filepath': PathToTestFile( 'goto_references.py' ), 'column_num': 5, 'description': 'a = f()', 'line_num': 4 }, { 'filepath': PathToTestFile( 'goto_references.py' ), 'column_num': 5, 'description': 'b = f()', 'line_num': 5 }, { 'filepath': PathToTestFile( 'goto_references.py' ), 'column_num': 5, 'description': 'c = f()', 'line_num': 6 } ] ) ycmd-0+20161219+git486b809.orig/ycmd/tests/python/debug_info_test.py0000644000175000017500000000543113026170313023313 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, matches_regexp from ycmd.tests.python import IsolatedYcmd, SharedYcmd from ycmd.tests.test_utils import BuildRequest, StopCompleterServer, UserOption @SharedYcmd def DebugInfo_ServerIsRunning_test( app ): request_data = BuildRequest( filetype = 'python' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Python completer debug information:\n' ' JediHTTP running at: http://127.0.0.1:\d+\n' ' JediHTTP process ID: \d+\n' ' JediHTTP executable: .+\n' ' JediHTTP logfiles:\n' ' .+\n' ' .+\n' ' Python interpreter: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesExist_test( app ): with UserOption( 'server_keep_logfiles', True ): StopCompleterServer( app, 'python' ) request_data = BuildRequest( filetype = 'python' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Python completer debug information:\n' ' JediHTTP no longer running\n' ' JediHTTP executable: .+\n' ' JediHTTP logfiles:\n' ' .+\n' ' .+\n' ' Python interpreter: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesDoNotExist_test( app ): with UserOption( 'server_keep_logfiles', False ): StopCompleterServer( app, 'python' ) request_data = BuildRequest( filetype = 'python' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Python completer debug information:\n' ' JediHTTP is not running\n' ' JediHTTP executable: .+\n' ' Python interpreter: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/go/0000755000175000017500000000000013026170313016662 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/0000755000175000017500000000000013026170313020473 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/test.go0000644000175000017500000000017713026170313022006 0ustar onuronur// Package testdata is dummy data for gocode completion test. package testdata import ( "log" ) func Hello() { log.Logge } ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/unicode.go0000644000175000017500000000033613026170313022452 0ustar onuronurpackage unicode import ( "fmt" ) type Test struct { Unicøde int } func main() { const test = `unicøde`; fmt.prf const test2 = `†es†`; fmt.erro å_test := Test{ Unicøde: 10, } å_test. } ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/test2.go0000644000175000017500000000045313026170313022065 0ustar onuronur// Package testdata is a test input for gocode completions. package testdata import "log" func LogSomeStuff() { log.Print("Line 7: Astrid was born on Jan 30") log.Print("Line 8: pɹɐɥ sı ǝpoɔıun") log.Print("Line 9: Karl was born on Jan 10") log.Printf("log prefix: %s", log.Prefix()) } ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/gocode_output_offset_121.json0000644000175000017500000000044713026170313026204 0ustar onuronur[2, [{"class": "func", "name": "Prefix", "type": "func() string"}, {"class": "func", "name": "Print", "type": "func(v ...interface{})"}, {"class": "func", "name": "Printf", "type": "func(format string, v ...interface{})"}, {"class": "func", "name": "Println", "type": "func(v ...interface{})"}]]ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/goto.go0000644000175000017500000000010313026170313021764 0ustar onuronurpackage main func dummy() { } func main() { dummy() //GoTo }ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/gocode_output_offset_292.json0000644000175000017500000000010313026170313026202 0ustar onuronur[5, [{"class": "func", "name": "Prefix", "type": "func() string"}]]ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/gocode_dontpanic_output_offset_10.json0000644000175000017500000000007313026170313030153 0ustar onuronur[0, [{"class": "PANIC", "name": "PANIC", "type": "PANIC"}]]ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/win.go0000644000175000017500000000007213026170313021616 0ustar onuronurpackage main func foo() {} func main() { foo() } ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/dontpanic.go0000644000175000017500000000052313026170313023001 0ustar onuronur// Binary dontpanic has a syntax error which causes a PANIC in gocode. We // don't use this in any test, just the related gocode json output, it just // lives here to document how to make gocode panic. Don't panic, and always // bring a towel. package main import { // <-- should be (, not { "fmt" "net/http" } func main() { http. } ycmd-0+20161219+git486b809.orig/ycmd/tests/go/testdata/gocode_output_offset_215.json0000644000175000017500000000035113026170313026202 0ustar onuronur[3, [{"class": "func", "name": "Print", "type": "func(v ...interface{})"}, {"class": "func", "name": "Printf", "type": "func(format string, v ...interface{})"}, {"class": "func", "name": "Println", "type": "func(v ...interface{})"}]]ycmd-0+20161219+git486b809.orig/ycmd/tests/go/get_completions_test.py0000644000175000017500000000601213026170313023465 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, has_item, has_items from ycmd.tests.go import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, CompletionEntryMatcher from ycmd.utils import ReadFile @SharedYcmd def GetCompletions_Basic_test( app ): filepath = PathToTestFile( 'test.go' ) completion_data = BuildRequest( filepath = filepath, filetype = 'go', contents = ReadFile( filepath ), force_semantic = True, line_num = 9, column_num = 11 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_item( CompletionEntryMatcher( u'Logger' ) ) ) @SharedYcmd def GetCompletions_Unicode_InLine_test( app ): filepath = PathToTestFile( 'unicode.go' ) completion_data = BuildRequest( filepath = filepath, filetype = 'go', contents = ReadFile( filepath ), line_num = 7, column_num = 37 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( u'Printf' ), CompletionEntryMatcher( u'Fprintf' ), CompletionEntryMatcher( u'Sprintf' ) ) ) @SharedYcmd def GetCompletions_Unicode_Identifier_test( app ): filepath = PathToTestFile( 'unicode.go' ) completion_data = BuildRequest( filepath = filepath, filetype = 'go', contents = ReadFile( filepath ), line_num = 13, column_num = 13 ) results = app.post_json( '/completions', completion_data ).json[ 'completions' ] assert_that( results, has_items( CompletionEntryMatcher( u'Unicøde' ) ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/go/__init__.py0000644000175000017500000000570213026170313020777 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import functools import os from ycmd import handlers from ycmd.tests.test_utils import ( ClearCompletionsCache, SetUpApp, StopCompleterServer, WaitUntilCompleterServerReady ) shared_app = None def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() WaitUntilCompleterServerReady( shared_app, 'go' ) def tearDownPackage(): global shared_app StopCompleterServer( shared_app, 'go' ) def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state app = SetUpApp() try: test( app, *args, **kwargs ) finally: StopCompleterServer( app, 'go' ) handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/go/go_completer_test.py0000644000175000017500000001574413026170313022765 0ustar onuronur# coding: utf-8 # # Copyright (C) 2015 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, calling, raises from mock import patch from nose.tools import eq_ import functools import os from ycmd.completers.go.go_completer import ( _ComputeOffset, GoCompleter, GO_BINARIES, FindBinary ) from ycmd.request_wrap import RequestWrap from ycmd import user_options_store from ycmd.utils import ReadFile, ToBytes TEST_DIR = os.path.dirname( os.path.abspath( __file__ ) ) DATA_DIR = os.path.join( TEST_DIR, 'testdata' ) PATH_TO_TEST_FILE = os.path.join( DATA_DIR, 'test2.go' ) # Use test file as dummy binary DUMMY_BINARY = PATH_TO_TEST_FILE PATH_TO_POS121_RES = os.path.join( DATA_DIR, 'gocode_output_offset_121.json' ) PATH_TO_POS215_RES = os.path.join( DATA_DIR, 'gocode_output_offset_215.json' ) PATH_TO_POS292_RES = os.path.join( DATA_DIR, 'gocode_output_offset_292.json' ) # Gocode output when a parsing error causes an internal panic. PATH_TO_PANIC_OUTPUT_RES = os.path.join( DATA_DIR, 'gocode_dontpanic_output_offset_10.json' ) REQUEST_DATA = { 'line_num': 1, 'filepath' : PATH_TO_TEST_FILE, 'file_data' : { PATH_TO_TEST_FILE : { 'filetypes' : [ 'go' ] } } } def BuildRequest( line_num, column_num ): request = REQUEST_DATA.copy() request[ 'line_num' ] = line_num request[ 'column_num' ] = column_num request[ 'file_data' ][ PATH_TO_TEST_FILE ][ 'contents' ] = ReadFile( PATH_TO_TEST_FILE ) return RequestWrap( request ) def SetUpGoCompleter( test ): @functools.wraps( test ) def Wrapper( *args, **kwargs ): user_options = user_options_store.DefaultOptions() user_options[ 'gocode_binary_path' ] = DUMMY_BINARY with patch( 'ycmd.utils.SafePopen' ): completer = GoCompleter( user_options ) return test( completer, *args, **kwargs ) return Wrapper def FindGoCodeBinary_test(): user_options = user_options_store.DefaultOptions() eq_( GO_BINARIES.get( "gocode" ), FindBinary( "gocode", user_options ) ) user_options[ 'gocode_binary_path' ] = DUMMY_BINARY eq_( DUMMY_BINARY, FindBinary( "gocode", user_options ) ) user_options[ 'gocode_binary_path' ] = DATA_DIR eq_( None, FindBinary( "gocode", user_options ) ) def ComputeOffset_OutOfBoundsOffset_test(): assert_that( calling( _ComputeOffset ).with_args( 'test', 2, 1 ), raises( RuntimeError, 'Go completer could not compute byte offset ' 'corresponding to line 2 and column 1.' ) ) # Test line-col to offset in the file before any unicode occurrences. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = ReadFile( PATH_TO_POS215_RES ) ) def ComputeCandidatesInner_BeforeUnicode_test( completer, execute_command ): # Col 8 corresponds to cursor at log.Pr^int("Line 7 ... completer.ComputeCandidatesInner( BuildRequest( 7, 8 ) ) execute_command.assert_called_once_with( [ DUMMY_BINARY, '-sock', 'tcp', '-addr', completer._gocode_address, '-f=json', 'autocomplete', PATH_TO_TEST_FILE, '119' ], contents = ToBytes( ReadFile( PATH_TO_TEST_FILE ) ) ) # Test line-col to offset in the file after a unicode occurrences. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = ReadFile( PATH_TO_POS215_RES ) ) def ComputeCandidatesInner_AfterUnicode_test( completer, execute_command ): # Col 9 corresponds to cursor at log.Pri^nt("Line 7 ... completer.ComputeCandidatesInner( BuildRequest( 9, 9 ) ) execute_command.assert_called_once_with( [ DUMMY_BINARY, '-sock', 'tcp', '-addr', completer._gocode_address, '-f=json', 'autocomplete', PATH_TO_TEST_FILE, '212' ], contents = ToBytes( ReadFile( PATH_TO_TEST_FILE ) ) ) # Test end to end parsing of completed results. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = ReadFile( PATH_TO_POS292_RES ) ) def ComputeCandidatesInner_test( completer, execute_command ): # Col 40 corresponds to cursor at ..., log.Prefi^x ... result = completer.ComputeCandidatesInner( BuildRequest( 10, 40 ) ) execute_command.assert_called_once_with( [ DUMMY_BINARY, '-sock', 'tcp', '-addr', completer._gocode_address, '-f=json', 'autocomplete', PATH_TO_TEST_FILE, '287' ], contents = ToBytes( ReadFile( PATH_TO_TEST_FILE ) ) ) eq_( result, [ { 'menu_text': u'Prefix', 'insertion_text': u'Prefix', 'extra_menu_info': u'func() string', 'detailed_info': u'Prefix func() string func', 'kind': u'func' } ] ) # Test Gocode failure. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = '' ) def ComputeCandidatesInner_GoCodeFailure_test( completer, *args ): assert_that( calling( completer.ComputeCandidatesInner ).with_args( BuildRequest( 1, 1 ) ), raises( RuntimeError, 'Gocode returned invalid JSON response.' ) ) # Test JSON parsing failure. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = "{this isn't parseable" ) def ComputeCandidatesInner_ParseFailure_test( completer, *args ): assert_that( calling( completer.ComputeCandidatesInner ).with_args( BuildRequest( 1, 1 ) ), raises( RuntimeError, 'Gocode returned invalid JSON response.' ) ) # Test empty results error. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = '[]' ) def ComputeCandidatesInner_NoResultsFailure_test( completer, *args ): assert_that( calling( completer.ComputeCandidatesInner ).with_args( BuildRequest( 1, 1 ) ), raises( RuntimeError, 'No completions found.' ) ) # Test panic error. @SetUpGoCompleter @patch( 'ycmd.completers.go.go_completer.GoCompleter._ExecuteCommand', return_value = ReadFile( PATH_TO_PANIC_OUTPUT_RES ) ) def ComputeCandidatesInner_GoCodePanic_test( completer, *args ): assert_that( calling( completer.ComputeCandidatesInner ).with_args( BuildRequest( 1, 1 ) ), raises( RuntimeError, 'Gocode panicked trying to find completions, ' 'you likely have a syntax error.' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/go/subcommands_test.py0000644000175000017500000001035513026170313022612 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, has_entries from nose.tools import eq_ from pprint import pformat import requests from ycmd.tests.go import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, ErrorMatcher from ycmd.utils import ReadFile @SharedYcmd def Subcommands_DefinedSubcommands_test( app ): subcommands_data = BuildRequest( completer_target = 'go' ) eq_( sorted( [ 'RestartServer', 'GoTo', 'GoToDefinition', 'GoToDeclaration' ] ), app.post_json( '/defined_subcommands', subcommands_data ).json ) def RunTest( app, test ): contents = ReadFile( test[ 'request' ][ 'filepath' ] ) def CombineRequest( request, data ): kw = request request.update( data ) return BuildRequest( **kw ) # We ignore errors here and check the response code ourself. # This is to allow testing of requests returning errors. response = app.post_json( '/run_completer_command', CombineRequest( test[ 'request' ], { 'completer_target': 'filetype_default', 'contents': contents, 'filetype': 'go', 'command_arguments': ( [ test[ 'request' ][ 'command' ] ] + test[ 'request' ].get( 'arguments', [] ) ) } ), expect_errors = True ) print( 'completer response: {0}'.format( pformat( response.json ) ) ) eq_( response.status_code, test[ 'expect' ][ 'response' ] ) assert_that( response.json, test[ 'expect' ][ 'data' ] ) @SharedYcmd def Subcommands_GoTo_Basic( app, goto_command ): RunTest( app, { 'description': goto_command + ' works within file', 'request': { 'command': goto_command, 'line_num': 8, 'column_num': 8, 'filepath': PathToTestFile( 'goto.go' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'filepath': PathToTestFile( 'goto.go' ), 'line_num': 3, 'column_num': 6, } ) } } ) def Subcommands_GoTo_Basic_test(): for command in [ 'GoTo', 'GoToDefinition', 'GoToDeclaration' ]: yield Subcommands_GoTo_Basic, command @SharedYcmd def Subcommands_GoTo_Keyword( app, goto_command ): RunTest( app, { 'description': goto_command + ' can\'t jump on keyword', 'request': { 'command': goto_command, 'line_num': 3, 'column_num': 3, 'filepath': PathToTestFile( 'goto.go' ), }, 'expect': { 'response': requests.codes.internal_server_error, 'data': ErrorMatcher( RuntimeError, 'Can\'t find a definition.' ) } } ) def Subcommands_GoTo_Keyword_test(): for command in [ 'GoTo', 'GoToDefinition', 'GoToDeclaration' ]: yield Subcommands_GoTo_Keyword, command @SharedYcmd def Subcommands_GoTo_WindowsNewlines( app, goto_command ): RunTest( app, { 'description': goto_command + ' works with Windows newlines', 'request': { 'command': goto_command, 'line_num': 4, 'column_num': 7, 'filepath': PathToTestFile( 'win.go' ), }, 'expect': { 'response': requests.codes.ok, 'data': has_entries( { 'filepath': PathToTestFile( 'win.go' ), 'line_num': 2, 'column_num': 6, } ) } } ) def Subcommands_GoTo_WindowsNewlines_test(): for command in [ 'GoTo', 'GoToDefinition', 'GoToDeclaration' ]: yield Subcommands_GoTo_WindowsNewlines, command ycmd-0+20161219+git486b809.orig/ycmd/tests/go/debug_info_test.py0000644000175000017500000000533513026170313022402 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, matches_regexp from ycmd.tests.go import IsolatedYcmd, SharedYcmd from ycmd.tests.test_utils import BuildRequest, StopCompleterServer, UserOption @SharedYcmd def DebugInfo_ServerIsRunning_test( app ): request_data = BuildRequest( filetype = 'go' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Go completer debug information:\n' ' Gocode running at: http://127.0.0.1:\d+\n' ' Gocode process ID: \d+\n' ' Gocode executable: .+\n' ' Gocode logfiles:\n' ' .+\n' ' .+\n' ' Godef executable: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesExist_test( app ): with UserOption( 'server_keep_logfiles', True ): StopCompleterServer( app, 'go' ) request_data = BuildRequest( filetype = 'go' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Go completer debug information:\n' ' Gocode no longer running\n' ' Gocode executable: .+\n' ' Gocode logfiles:\n' ' .+\n' ' .+\n' ' Godef executable: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesDoNotExist_test( app ): with UserOption( 'server_keep_logfiles', False ): StopCompleterServer( app, 'go' ) request_data = BuildRequest( filetype = 'go' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'Go completer debug information:\n' ' Gocode is not running\n' ' Gocode executable: .+\n' ' Godef executable: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/identifier_completer_test.py0000644000175000017500000001442613026170313024071 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os from nose.tools import eq_ from ycmd.user_options_store import DefaultOptions from ycmd.completers.all import identifier_completer as ic from ycmd.completers.all.identifier_completer import IdentifierCompleter from ycmd.request_wrap import RequestWrap from ycmd.tests import PathToTestFile from ycmd.tests.test_utils import BuildRequest def BuildRequestWrap( contents, column_num, line_num = 1 ): return RequestWrap( BuildRequest( column_num = column_num, line_num = line_num, contents = contents ) ) def GetCursorIdentifier_StartOfLine_test(): eq_( 'foo', ic._GetCursorIdentifier( BuildRequestWrap( 'foo', 1 ) ) ) eq_( 'fooBar', ic._GetCursorIdentifier( BuildRequestWrap( 'fooBar', 1 ) ) ) def GetCursorIdentifier_EndOfLine_test(): eq_( 'foo', ic._GetCursorIdentifier( BuildRequestWrap( 'foo', 3 ) ) ) def GetCursorIdentifier_PastEndOfLine_test(): eq_( '', ic._GetCursorIdentifier( BuildRequestWrap( 'foo', 11 ) ) ) def GetCursorIdentifier_NegativeColumn_test(): eq_( 'foo', ic._GetCursorIdentifier( BuildRequestWrap( 'foo', -10 ) ) ) def GetCursorIdentifier_StartOfLine_StopsAtNonIdentifierChar_test(): eq_( 'foo', ic._GetCursorIdentifier( BuildRequestWrap( 'foo(goo)', 1 ) ) ) def GetCursorIdentifier_AtNonIdentifier_test(): eq_( 'goo', ic._GetCursorIdentifier( BuildRequestWrap( 'foo(goo)', 4 ) ) ) def GetCursorIdentifier_WalksForwardForIdentifier_test(): eq_( 'foo', ic._GetCursorIdentifier( BuildRequestWrap( ' foo', 1 ) ) ) def GetCursorIdentifier_FindsNothingForward_test(): eq_( '', ic._GetCursorIdentifier( BuildRequestWrap( 'foo ()***()', 5 ) ) ) def GetCursorIdentifier_SingleCharIdentifier_test(): eq_( 'f', ic._GetCursorIdentifier( BuildRequestWrap( ' f ', 1 ) ) ) def GetCursorIdentifier_StartsInMiddleOfIdentifier_test(): eq_( 'foobar', ic._GetCursorIdentifier( BuildRequestWrap( 'foobar', 4 ) ) ) def GetCursorIdentifier_LineEmpty_test(): eq_( '', ic._GetCursorIdentifier( BuildRequestWrap( '', 12 ) ) ) def PreviousIdentifier_Simple_test(): eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo', 4 ) ) ) def PreviousIdentifier_WholeIdentShouldBeBeforeColumn_test(): eq_( '', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foobar', column_num = 4 ) ) ) def PreviousIdentifier_DoNotWrap_test(): eq_( '', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foobar\n bar', column_num = 4 ) ) ) def PreviousIdentifier_IgnoreForwardIdents_test(): eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo bar zoo', 4 ) ) ) def PreviousIdentifier_IgnoreTooSmallIdent_test(): eq_( '', ic._PreviousIdentifier( 4, BuildRequestWrap( 'foo', 4 ) ) ) def PreviousIdentifier_IgnoreTooSmallIdent_DontContinueLooking_test(): eq_( '', ic._PreviousIdentifier( 4, BuildRequestWrap( 'abcde foo', 10 ) ) ) def PreviousIdentifier_WhitespaceAfterIdent_test(): eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo ', 6 ) ) ) def PreviousIdentifier_JunkAfterIdent_test(): eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo ;;()** ', 13 ) ) ) def PreviousIdentifier_IdentInMiddleOfJunk_test(): eq_( 'aa', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo ;;(aa)** ', 13 ) ) ) def PreviousIdentifier_IdentOnPreviousLine_test(): eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo\n ', column_num = 3, line_num = 2 ) ) ) eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo\n', column_num = 1, line_num = 2 ) ) ) def PreviousIdentifier_IdentOnPreviousLine_JunkAfterIdent_test(): eq_( 'foo', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foo **;()\n ', column_num = 3, line_num = 2 ) ) ) def PreviousIdentifier_NoGoodIdentFound_test(): eq_( '', ic._PreviousIdentifier( 5, BuildRequestWrap( 'foo\n ', column_num = 2, line_num = 2 ) ) ) def FilterUnchangedTagFiles_NoFiles_test(): ident_completer = IdentifierCompleter( DefaultOptions() ) eq_( [], list( ident_completer._FilterUnchangedTagFiles( [] ) ) ) def FilterUnchangedTagFiles_SkipBadFiles_test(): ident_completer = IdentifierCompleter( DefaultOptions() ) eq_( [], list( ident_completer._FilterUnchangedTagFiles( [ '/some/tags' ] ) ) ) def FilterUnchangedTagFiles_KeepGoodFiles_test(): ident_completer = IdentifierCompleter( DefaultOptions() ) tag_file = PathToTestFile( 'basic.tags' ) eq_( [ tag_file ], list( ident_completer._FilterUnchangedTagFiles( [ tag_file ] ) ) ) def FilterUnchangedTagFiles_SkipUnchangesFiles_test(): ident_completer = IdentifierCompleter( DefaultOptions() ) # simulate an already open tags file that didn't change in the meantime. tag_file = PathToTestFile( 'basic.tags' ) ident_completer._tags_file_last_mtime[ tag_file ] = os.path.getmtime( tag_file ) eq_( [], list( ident_completer._FilterUnchangedTagFiles( [ tag_file ] ) ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/0000755000175000017500000000000013026170313016662 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/0000755000175000017500000000000013026170313020473 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/0000755000175000017500000000000013026170313021643 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/GotoTestCase.cs0000644000175000017500000000146113026170313024540 0ustar onuronurusing System; namespace testy { class GotoTestCase { static void Main (string[] args) { MainClass.Main(new String[0]); } static void ImplementionTest(IGotoTest test) { test.DoSomething(); } static void InterfaceOnlyTest(IGotoTestWithoutImpl test) { test.DoSomething(); } static void MultipleImplementionTest(IGotoTestMultiple test) { test.DoSomething(); } } interface IGotoTest { void DoSomething(); } class GotoTestImpl : IGotoTest { public void DoSomething() { } } interface IGotoTestWithoutImpl { void DoSomething(); } interface IGotoTestMultiple { void DoSomething(); } class GotoTestMultipleImplOne : IGotoTestMultiple { public void DoSomething() { } } class GotoTestMultipleImplTwo : IGotoTestMultiple { public void DoSomething() { } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/testy.userprefs0000644000175000017500000000100213026170313024744 0ustar onuronur ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/GetTypeTestCase.cs0000644000175000017500000000034613026170313025212 0ustar onuronurnamespace testy { public class GetTypeTestCase { public GetTypeTestCase() { var str = ""; str.EndsWith("A"); } /// These docs are not shown in GetType private int an_int_with_docs; } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/GetDocTestCase.cs0000644000175000017500000000156113026170313024776 0ustar onuronur/** * testy is a namespace for testing */ namespace testy { /** * Tests the GetDoc subcommands */ public class GetDocTestCase { /** * Constructor */ public GetDocTestCase() { this.an_int = 1; } /** * Very important method. * * With multiple lines of commentary * And Format- * -ting */ public int DoATest() { return an_int; } /// an integer, or something private int an_int; /// Use this for testing private static void DoTesting() { GetDocTestCase tc; tc.DoATest(); } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/Properties/0000755000175000017500000000000013026170313023777 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/Properties/AssemblyInfo.cs0000644000175000017500000000172513026170313026726 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/testy.sln0000644000175000017500000000150413026170313023531 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy.csproj EndGlobalSection EndGlobal ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/Program.cs0000644000175000017500000000021013026170313023572 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { int 九 = 9; Console. } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/Unicode.cs0000644000175000017500000000253313026170313023563 0ustar onuronur/** * testy is a namespace for testing */ namespace testy { /** * Tests the GetDoc subcommands */ public class Unicøde { /** * Constructor */ public Unicøde () { this.an_int = 1; } /** * Very important methød. * * With multiple lines of commentary * And Format- * -ting */ public int DoATest() { return an_int; } /// an integer, or something private int an_int; private int øøø; private Unicøde a_unicøde; private static void DoSomething( Unicøde unicode ) { } /// Use this for testing private static void DoTesting() { Unicøde tc; tc.DoATest(); Unicøde øø; øø. DoSomething( a_unicøde ); } interface Bøøm { void Båm(); } public class BøømBøøm : Bøøm { public void Båm() { } } public class BåmBåm : Bøøm { public void Båm() { } } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/ImportTest.cs0000644000175000017500000000020013026170313024274 0ustar onuronurusing System; namespace testy { public class ImportTest { public static void Main (string[] args) { new Date } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/DiagnosticRange.cs0000644000175000017500000000006113026170313025230 0ustar onuronurpublic class Class { public int attribute; } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/ContinuousTest.cs0000644000175000017500000000021513026170313025176 0ustar onuronurusing System; namespace testy { public class ContinuousTest { public static void Main (string[] args) { var test = String } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/FixItTestCase.cs0000644000175000017500000000074513026170313024657 0ustar onuronurusing Microsoft.CSharp; using System; using System.Text; namespace testy { public class FixItTestCase { public FixItTestCase() { var str = ""; str.EndsWith("A"); var i = 5; const int j = i + 5; } public int One() { var self = this; return self.GetHashCode(); } public int Two() { var self = this; return self.GetHashCode(); } } } ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy/testy.csproj0000644000175000017500000000352213026170313024237 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/0000755000175000017500000000000013026170313025531 5ustar onuronur././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/Properties/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172513026170313031446 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/Program.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017013026170313031437 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/testy.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317113026170313031443 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/Properties/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172513026170313031446 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000021700000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/Program.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017013026170313031437 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/testy.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317113026170313031443 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/.ycm_extra_conf.pyycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000036713026170313031447 0ustar onuronur import os def CSharpSolutionFile( path, **kwargs ): #remove '.ycm_extra_conf.py' and 'extra-conf-abs' from filename location=os.path.dirname( __file__ ) location=os.path.dirname( location ) return os.path.join( location, 'testy2.sln' ) ././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy2.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152013026170313031437 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy1.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152013026170313031437 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/Properties/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172513026170313031446 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000021700000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/testy2.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000151213026170313031440 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000021700000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/Program.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017013026170313031437 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/testy.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317113026170313031443 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/.ycm_extra_conf.pyycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000010213026170313031432 0ustar onuronur def CSharpSolutionFile( path, **kwargs ): return "testy2.sln" ././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy2.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152013026170313031437 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy2.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152013026170313031437 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000017700000000000011610 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000022700000000000011604 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/.ycm_extra_conf.pyycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000010213026170313031432 0ustar onuronur def CSharpSolutionFile( path, **kwargs ): return "nosuch.sln" ././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/Properties/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000013026170313031437 5ustar onuronur././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172513026170313031446 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000021700000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/Program.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017013026170313031437 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/testy.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317113026170313031443 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy2.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152013026170313031437 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000015400000000000011603 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000013026170313031407 5ustar onuronur././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000013026170313031407 5ustar onuronur././@LongLink0000644000000000000000000000017500000000000011606 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/Properties/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000013026170313031407 5ustar onuronur././@LongLink0000644000000000000000000000021400000000000011600 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000172513026170313031416 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000017400000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/Program.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000017013026170313031407 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/testy.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000317113026170313031413 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000013026170313031407 5ustar onuronur././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/Properties/ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000013026170313031407 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000172513026170313031416 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000020000000000000011573 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/Program.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000017013026170313031407 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/testy.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000317113026170313031413 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy2.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000152013026170313031407 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000152013026170313031407 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = testy/testy.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000021200000000000011576 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/solution-named-like-folder.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000152413026170313031413 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testy", "testy/testy.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = not-testy/testy.csproj EndGlobalSection EndGlobal ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/0000755000175000017500000000000013026170313034612 5ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/Properties/0000755000175000017500000000000013026170313036746 5ustar onuronur././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/Properties/AssemblyInfo.csycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/Properties/0000644000175000017500000000172513026170313036755 0ustar onuronurusing System.Reflection; using System.Runtime.CompilerServices; // Information about this assembly is defined by the following attributes. // Change them to the values specific to your project. [assembly: AssemblyTitle ("testy")] [assembly: AssemblyDescription ("")] [assembly: AssemblyConfiguration ("")] [assembly: AssemblyCompany ("")] [assembly: AssemblyProduct ("")] [assembly: AssemblyCopyright ("valloric")] [assembly: AssemblyTrademark ("")] [assembly: AssemblyCulture ("")] // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. [assembly: AssemblyVersion ("1.0.*")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/a project.userprefsycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/a project.u0000644000175000017500000000100213026170313036640 0ustar onuronur ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/Program.cs0000644000175000017500000000017013026170313036546 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/a project.slnycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/a project.s0000644000175000017500000000152013026170313036643 0ustar onuronur Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "a project", "a project.csproj", "{0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.ActiveCfg = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Debug|x86.Build.0 = Debug|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.ActiveCfg = Release|x86 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = a project.csproj EndGlobalSection EndGlobal ././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/a project.csprojycmd-0+20161219+git486b809.orig/ycmd/tests/cs/testdata/неприличное слово/a project.c0000644000175000017500000000317513026170313036633 0ustar onuronur Debug x86 10.0.0 2.0 {0C99F719-E00E-4CCD-AB9F-FEFBCD97C51F} Exe testy testy true full false bin\Debug DEBUG; prompt 4 true x86 full true bin\Release prompt 4 true x86 ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/get_completions_test.py0000644000175000017500000004160113026170313023470 0ustar onuronur# coding: utf-8 # # Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, calling, empty, greater_than, has_item, has_items, has_entries, raises ) from nose.tools import eq_ from webtest import AppError from ycmd.tests.cs import PathToTestFile, SharedYcmd, WrapOmniSharpServer from ycmd.tests.test_utils import BuildRequest, CompletionEntryMatcher from ycmd.utils import ReadFile @SharedYcmd def GetCompletions_Basic_test( app ): filepath = PathToTestFile( 'testy', 'Program.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 10, column_num = 12 ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'CursorLeft' ), CompletionEntryMatcher( 'CursorSize' ) ) ) eq_( 12, response_data[ 'completion_start_column' ] ) @SharedYcmd def GetCompletions_Unicode_test( app ): filepath = PathToTestFile( 'testy', 'Unicode.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 43, column_num = 26 ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'DoATest()' ), CompletionEntryMatcher( 'an_int' ), CompletionEntryMatcher( 'a_unicøde' ), CompletionEntryMatcher( 'øøø' ) ) ) eq_( 26, response_data[ 'completion_start_column' ] ) @SharedYcmd def GetCompletions_MultipleSolution_test( app ): filepaths = [ PathToTestFile( 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'testy', 'Program.cs' ) ] lines = [ 10, 9 ] for filepath, line in zip( filepaths, lines ): with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = line, column_num = 12 ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'CursorLeft' ), CompletionEntryMatcher( 'CursorSize' ) ) ) eq_( 12, response_data[ 'completion_start_column' ] ) @SharedYcmd def GetCompletions_PathWithSpace_test( app ): filepath = PathToTestFile( u'неприличное слово', 'Program.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 12 ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'CursorLeft' ), CompletionEntryMatcher( 'CursorSize' ) ) ) eq_( 12, response_data[ 'completion_start_column' ] ) @SharedYcmd def GetCompletions_HasBothImportsAndNonImport_test( app ): filepath = PathToTestFile( 'testy', 'ImportTest.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 12, force_semantic = True, query = 'Date' ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'DateTime' ), CompletionEntryMatcher( 'DateTimeStyles' ) ) ) @SharedYcmd def GetCompletions_ImportsOrderedAfter_test( app ): filepath = PathToTestFile( 'testy', 'ImportTest.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 12, force_semantic = True, query = 'Date' ) response_data = app.post_json( '/completions', completion_data ).json min_import_index = min( loc for loc, val in enumerate( response_data[ 'completions' ] ) if val[ 'extra_data' ][ 'required_namespace_import' ] ) max_nonimport_index = max( loc for loc, val in enumerate( response_data[ 'completions' ] ) if not val[ 'extra_data' ][ 'required_namespace_import' ] ) assert_that( min_import_index, greater_than( max_nonimport_index ) ), @SharedYcmd def GetCompletions_ForcedReturnsResults_test( app ): filepath = PathToTestFile( 'testy', 'ContinuousTest.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 21, force_semantic = True, query = 'Date' ) response_data = app.post_json( '/completions', completion_data ).json assert_that( response_data[ 'completions' ], has_items( CompletionEntryMatcher( 'String' ), CompletionEntryMatcher( 'StringBuilder' ) ) ) @SharedYcmd def GetCompletions_NonForcedReturnsNoResults_test( app ): filepath = PathToTestFile( 'testy', 'ContinuousTest.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 21, force_semantic = False, query = 'Date' ) results = app.post_json( '/completions', completion_data ).json # There are no semantic completions. However, we fall back to identifier # completer in this case. assert_that( results, has_entries( { 'completions': has_item( has_entries( { 'insertion_text' : 'String', 'extra_menu_info': '[ID]', } ) ), 'errors': empty(), } ) ) @SharedYcmd def GetCompletions_ForcedDividesCache_test( app ): filepath = PathToTestFile( 'testy', 'ContinuousTest.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 21, force_semantic = True, query = 'Date' ) results = app.post_json( '/completions', completion_data ).json assert_that( results[ 'completions' ], not( empty() ) ) assert_that( results[ 'errors' ], empty() ) completion_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 9, column_num = 21, force_semantic = False, query = 'Date' ) results = app.post_json( '/completions', completion_data ).json # There are no semantic completions. However, we fall back to identifier # completer in this case. assert_that( results, has_entries( { 'completions': has_item( has_entries( { 'insertion_text' : 'String', 'extra_menu_info': '[ID]', } ) ), 'errors': empty(), } ) ) @SharedYcmd def GetCompletions_ReloadSolution_Basic_test( app ): filepath = PathToTestFile( 'testy', 'Program.cs' ) with WrapOmniSharpServer( app, filepath ): result = app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'ReloadSolution' ], filepath = filepath, filetype = 'cs' ) ).json eq_( result, True ) @SharedYcmd def GetCompletions_ReloadSolution_MultipleSolution_test( app ): filepaths = [ PathToTestFile( 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'testy', 'Program.cs' ) ] for filepath in filepaths: with WrapOmniSharpServer( app, filepath ): result = app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'ReloadSolution' ], filepath = filepath, filetype = 'cs' ) ).json eq_( result, True ) def SolutionSelectCheck( app, sourcefile, reference_solution, extra_conf_store = None ): # reusable test: verify that the correct solution (reference_solution) is # detected for a given source file (and optionally a given extra_conf) if extra_conf_store: app.post_json( '/load_extra_conf_file', { 'filepath': extra_conf_store } ) result = app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'SolutionFile' ], filepath = sourcefile, filetype = 'cs' ) ).json # Now that cleanup is done, verify solution file eq_( reference_solution, result) @SharedYcmd def GetCompletions_UsesSubfolderHint_test( app ): SolutionSelectCheck( app, PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'testy.sln' ) ) @SharedYcmd def GetCompletions_UsesSuperfolderHint_test( app ): SolutionSelectCheck( app, PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'not-testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'solution-named-like-folder.sln' ) ) @SharedYcmd def GetCompletions_ExtraConfStoreAbsolute_test( app ): SolutionSelectCheck( app, PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-abs', 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'testy2.sln' ), PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-abs', '.ycm_extra_conf.py' ) ) @SharedYcmd def GetCompletions_ExtraConfStoreRelative_test( app ): SolutionSelectCheck( app, PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-rel', 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-rel', 'testy2.sln' ), PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-rel', '.ycm_extra_conf.py' ) ) @SharedYcmd def GetCompletions_ExtraConfStoreNonexisting_test( app ): SolutionSelectCheck( app, PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-bad', 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-bad', 'testy2.sln' ), PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'extra-conf-bad', 'testy', '.ycm_extra_conf.py' ) ) @SharedYcmd def GetCompletions_DoesntStartWithAmbiguousMultipleSolutions_test( app ): filepath = PathToTestFile( 'testy-multiple-solutions', 'solution-not-named-like-folder', 'testy', 'Program.cs' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) assert_that( calling( app.post_json ).with_args( '/event_notification', event_data ), raises( AppError, 'Autodetection of solution file failed' ), "The Omnisharp server started, despite us not being able to find a " "suitable solution file to feed it. Did you fiddle with the solution " "finding code in cs_completer.py? Hopefully you've enhanced it: you need " "to update this test then :)" ) ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/__init__.py0000644000175000017500000000720413026170313020776 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from contextlib import contextmanager import functools import os from ycmd import handlers from ycmd.tests.test_utils import ( ClearCompletionsCache, SetUpApp, StartCompleterServer, StopCompleterServer, WaitUntilCompleterServerReady ) shared_app = None shared_filepaths = [] def PathToTestFile( *args ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'testdata', *args ) def setUpPackage(): """Initializes the ycmd server as a WebTest application that will be shared by all tests using the SharedYcmd decorator in this package. Additional configuration that is common to these tests, like starting a semantic subserver, should be done here.""" global shared_app shared_app = SetUpApp() shared_app.post_json( '/ignore_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) def tearDownPackage(): """Cleans up the tests using the SharedYcmd decorator in this package. It is executed once after running all the tests in the package.""" global shared_app, shared_filepaths for filepath in shared_filepaths: StopCompleterServer( shared_app, 'cs', filepath ) @contextmanager def WrapOmniSharpServer( app, filepath ): global shared_filepaths if filepath not in shared_filepaths: StartCompleterServer( app, 'cs', filepath ) shared_filepaths.append( filepath ) WaitUntilCompleterServerReady( app, 'cs' ) yield def SharedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes the shared ycmd application as a parameter. Do NOT attach it to test generators but directly to the yielded tests.""" global shared_app @functools.wraps( test ) def Wrapper( *args, **kwargs ): ClearCompletionsCache() return test( shared_app, *args, **kwargs ) return Wrapper def IsolatedYcmd( test ): """Defines a decorator to be attached to tests of this package. This decorator passes a unique ycmd application as a parameter. It should be used on tests that change the server state in a irreversible way (ex: a semantic subserver is stopped or restarted) or expect a clean state (ex: no semantic subserver started, no .ycm_extra_conf.py loaded, etc). Do NOT attach it to test generators but directly to the yielded tests.""" @functools.wraps( test ) def Wrapper( *args, **kwargs ): old_server_state = handlers._server_state try: app = SetUpApp() app.post_json( '/ignore_extra_conf_file', { 'filepath': PathToTestFile( '.ycm_extra_conf.py' ) } ) test( app, *args, **kwargs ) finally: handlers._server_state = old_server_state return Wrapper ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/diagnostics_test.py0000644000175000017500000001537713026170313022617 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import ( assert_that, contains, contains_string, equal_to, has_entries, has_entry ) from ycmd.tests.cs import PathToTestFile, SharedYcmd, WrapOmniSharpServer from ycmd.tests.test_utils import BuildRequest from ycmd.utils import ReadFile @SharedYcmd def Diagnostics_Basic_test( app ): filepath = PathToTestFile( 'testy', 'Program.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, event_name = 'FileReadyToParse', filetype = 'cs', contents = contents ) app.post_json( '/event_notification', event_data ) diag_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, line_num = 11, column_num = 2 ) results = app.post_json( '/detailed_diagnostic', diag_data ).json assert_that( results, has_entry( 'message', contains_string( "Unexpected symbol `}'', expecting identifier" ) ) ) @SharedYcmd def Diagnostics_ZeroBasedLineAndColumn_test( app ): filepath = PathToTestFile( 'testy', 'Program.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) results = {} for _ in ( 0, 1 ): # First call always returns blank for some reason event_data = BuildRequest( filepath = filepath, event_name = 'FileReadyToParse', filetype = 'cs', contents = contents ) results = app.post_json( '/event_notification', event_data ).json assert_that( results, contains( has_entries( { 'kind': equal_to( 'ERROR' ), 'text': contains_string( "Unexpected symbol `}'', expecting identifier" ), 'location': has_entries( { 'line_num': 11, 'column_num': 2 } ), 'location_extent': has_entries( { 'start': has_entries( { 'line_num': 11, 'column_num': 2, } ), 'end': has_entries( { 'line_num': 11, 'column_num': 2, } ), } ) } ) ) ) @SharedYcmd def Diagnostics_WithRange_test( app ): filepath = PathToTestFile( 'testy', 'DiagnosticRange.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) results = {} for _ in ( 0, 1 ): # First call always returns blank for some reason event_data = BuildRequest( filepath = filepath, event_name = 'FileReadyToParse', filetype = 'cs', contents = contents ) results = app.post_json( '/event_notification', event_data ).json assert_that( results, contains( has_entries( { 'kind': equal_to( 'WARNING' ), 'text': contains_string( "Name should have prefix '_'" ), 'location': has_entries( { 'line_num': 3, 'column_num': 16 } ), 'location_extent': has_entries( { 'start': has_entries( { 'line_num': 3, 'column_num': 16, } ), 'end': has_entries( { 'line_num': 3, 'column_num': 25, } ), } ) } ) ) ) @SharedYcmd def Diagnostics_MultipleSolution_test( app ): filepaths = [ PathToTestFile( 'testy', 'Program.cs' ), PathToTestFile( 'testy-multiple-solutions', 'solution-named-like-folder', 'testy', 'Program.cs' ) ] lines = [ 11, 10 ] for filepath, line in zip( filepaths, lines ): with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) results = {} for _ in ( 0, 1 ): # First call always returns blank for some reason event_data = BuildRequest( filepath = filepath, event_name = 'FileReadyToParse', filetype = 'cs', contents = contents ) results = app.post_json( '/event_notification', event_data ).json assert_that( results, contains( has_entries( { 'kind': equal_to( 'ERROR' ), 'text': contains_string( "Unexpected symbol `}'', " "expecting identifier" ), 'location': has_entries( { 'line_num': line, 'column_num': 2 } ), 'location_extent': has_entries( { 'start': has_entries( { 'line_num': line, 'column_num': 2, } ), 'end': has_entries( { 'line_num': line, 'column_num': 2, } ), } ) } ) ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/subcommands_test.py0000644000175000017500000004607513026170313022622 0ustar onuronur# Copyright (C) 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from nose.tools import eq_, ok_ from webtest import AppError from hamcrest import assert_that, has_entries, contains import pprint import re import os.path from ycmd.tests.cs import ( IsolatedYcmd, PathToTestFile, SharedYcmd, WrapOmniSharpServer ) from ycmd.tests.test_utils import ( BuildRequest, ChunkMatcher, LocationMatcher, StopCompleterServer, UserOption, WaitUntilCompleterServerReady ) from ycmd.utils import ReadFile @SharedYcmd def Subcommands_GoTo_Basic_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoTo' ], line_num = 9, column_num = 15, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { 'filepath': PathToTestFile( 'testy', 'Program.cs' ), 'line_num': 7, 'column_num': 3 }, app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GoTo_Unicode_test( app ): filepath = PathToTestFile( 'testy', 'Unicode.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoTo' ], line_num = 45, column_num = 43, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { 'filepath': PathToTestFile( 'testy', 'Unicode.cs' ), 'line_num': 30, 'column_num': 37 }, app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GoToImplementation_Basic_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementation' ], line_num = 13, column_num = 13, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { 'filepath': PathToTestFile( 'testy', 'GotoTestCase.cs' ), 'line_num': 30, 'column_num': 3 }, app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GoToImplementation_NoImplementation_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementation' ], line_num = 17, column_num = 13, contents = contents, filetype = 'cs', filepath = filepath ) try: app.post_json( '/run_completer_command', goto_data ).json raise Exception("Expected a 'No implementations found' error") except AppError as e: if 'No implementations found' in str(e): pass else: raise @SharedYcmd def Subcommands_CsCompleter_InvalidLocation_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementation' ], line_num = 2, column_num = 1, contents = contents, filetype = 'cs', filepath = filepath ) try: app.post_json( '/run_completer_command', goto_data ).json raise Exception( 'Expected a "Can\\\'t jump to implementation" error' ) except AppError as e: if 'Can\\\'t jump to implementation' in str(e): pass else: raise @SharedYcmd def Subcommands_GoToImplementationElseDeclaration_NoImplementation_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementationElseDeclaration' ], line_num = 17, column_num = 13, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { 'filepath': PathToTestFile( 'testy', 'GotoTestCase.cs' ), 'line_num': 35, 'column_num': 3 }, app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GoToImplementationElseDeclaration_SingleImplementation_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementationElseDeclaration' ], line_num = 13, column_num = 13, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { 'filepath': PathToTestFile( 'testy', 'GotoTestCase.cs' ), 'line_num': 30, 'column_num': 3 }, app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GoToImplementationElseDeclaration_MultipleImplementations_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementationElseDeclaration' ], line_num = 21, column_num = 13, contents = contents, filetype = 'cs', filepath = filepath ) eq_( [ { 'filepath': PathToTestFile( 'testy', 'GotoTestCase.cs' ), 'line_num': 43, 'column_num': 3 }, { 'filepath': PathToTestFile( 'testy', 'GotoTestCase.cs' ), 'line_num': 48, 'column_num': 3 } ], app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GetToImplementation_Unicode_test( app ): filepath = PathToTestFile( 'testy', 'Unicode.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToImplementation' ], line_num = 48, column_num = 44, contents = contents, filetype = 'cs', filepath = filepath ) eq_( [ { 'filepath': PathToTestFile( 'testy', 'Unicode.cs' ), 'line_num': 49, 'column_num': 54 }, { 'filepath': PathToTestFile( 'testy', 'Unicode.cs' ), 'line_num': 50, 'column_num': 50 } ], app.post_json( '/run_completer_command', goto_data ).json ) @SharedYcmd def Subcommands_GetType_EmptyMessage_test( app ): filepath = PathToTestFile( 'testy', 'GetTypeTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 1, column_num = 1, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { u'message': u"" }, app.post_json( '/run_completer_command', gettype_data ).json ) @SharedYcmd def Subcommands_GetType_VariableDeclaration_test( app ): filepath = PathToTestFile( 'testy', 'GetTypeTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 4, column_num = 5, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { u'message': u"string" }, app.post_json( '/run_completer_command', gettype_data ).json ) @SharedYcmd def Subcommands_GetType_VariableUsage_test( app ): filepath = PathToTestFile( 'testy', 'GetTypeTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 5, column_num = 5, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { u'message': u"string str" }, app.post_json( '/run_completer_command', gettype_data ).json ) @SharedYcmd def Subcommands_GetType_Constant_test( app ): filepath = PathToTestFile( 'testy', 'GetTypeTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 4, column_num = 14, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { u'message': u"System.String" }, app.post_json( '/run_completer_command', gettype_data ).json ) @SharedYcmd def Subcommands_GetType_DocsIgnored_test( app ): filepath = PathToTestFile( 'testy', 'GetTypeTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) gettype_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetType' ], line_num = 9, column_num = 34, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { u'message': u"int GetTypeTestCase.an_int_with_docs;", }, app.post_json( '/run_completer_command', gettype_data ).json ) @SharedYcmd def Subcommands_GetDoc_Variable_test( app ): filepath = PathToTestFile( 'testy', 'GetDocTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) getdoc_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetDoc' ], line_num = 13, column_num = 28, contents = contents, filetype = 'cs', filepath = filepath ) eq_( { 'detailed_info': 'int GetDocTestCase.an_int;\n' 'an integer, or something', }, app.post_json( '/run_completer_command', getdoc_data ).json ) @SharedYcmd def Subcommands_GetDoc_Function_test( app ): filepath = PathToTestFile( 'testy', 'GetDocTestCase.cs' ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) getdoc_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GetDoc' ], line_num = 33, column_num = 27, contents = contents, filetype = 'cs', filepath = filepath ) # It seems that Omnisharp server eats newlines eq_( { 'detailed_info': 'int GetDocTestCase.DoATest();\n' ' Very important method. With multiple lines of ' 'commentary And Format- -ting', }, app.post_json( '/run_completer_command', getdoc_data ).json ) def RunFixItTest( app, line, column, result_matcher, filepath = [ 'testy', 'FixItTestCase.cs' ] ): filepath = PathToTestFile( *filepath ) with WrapOmniSharpServer( app, filepath ): contents = ReadFile( filepath ) fixit_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'FixIt' ], line_num = line, column_num = column, contents = contents, filetype = 'cs', filepath = filepath ) response = app.post_json( '/run_completer_command', fixit_data ).json pprint.pprint( response ) assert_that( response, result_matcher ) @SharedYcmd def Subcommands_FixIt_RemoveSingleLine_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 11, 1, has_entries( { 'fixits': contains( has_entries( { 'location': LocationMatcher( filepath, 11, 1 ), 'chunks': contains( ChunkMatcher( '', LocationMatcher( filepath, 10, 20 ), LocationMatcher( filepath, 11, 30 ) ) ) } ) ) } ) ) @SharedYcmd def Subcommands_FixIt_MultipleLines_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 19, 1, has_entries( { 'fixits': contains( has_entries ( { 'location': LocationMatcher( filepath, 19, 1 ), 'chunks': contains( ChunkMatcher( 'return On', LocationMatcher( filepath, 20, 13 ), LocationMatcher( filepath, 21, 35 ) ) ) } ) ) } ) ) @SharedYcmd def Subcommands_FixIt_SpanFileEdge_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 1, 1, has_entries( { 'fixits': contains( has_entries ( { 'location': LocationMatcher( filepath, 1, 1 ), 'chunks': contains( ChunkMatcher( 'System', LocationMatcher( filepath, 1, 7 ), LocationMatcher( filepath, 3, 18 ) ) ) } ) ) } ) ) @SharedYcmd def Subcommands_FixIt_AddTextInLine_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 9, 1, has_entries( { 'fixits': contains( has_entries ( { 'location': LocationMatcher( filepath, 9, 1 ), 'chunks': contains( ChunkMatcher( ', StringComparison.Ordinal', LocationMatcher( filepath, 9, 29 ), LocationMatcher( filepath, 9, 29 ) ) ) } ) ) } ) ) @SharedYcmd def Subcommands_FixIt_ReplaceTextInLine_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 10, 1, has_entries( { 'fixits': contains( has_entries ( { 'location': LocationMatcher( filepath, 10, 1 ), 'chunks': contains( ChunkMatcher( 'const int', LocationMatcher( filepath, 10, 13 ), LocationMatcher( filepath, 10, 16 ) ) ) } ) ) } ) ) @SharedYcmd def Subcommands_FixIt_Unicode_test( app ): filepath = PathToTestFile( 'testy', 'Unicode.cs' ) RunFixItTest( app, 30, 54, has_entries( { 'fixits': contains( has_entries ( { 'location': LocationMatcher( filepath, 30, 54 ), 'chunks': contains( ChunkMatcher( ' readonly', LocationMatcher( filepath, 30, 44 ), LocationMatcher( filepath, 30, 44 ) ) ) } ) ) } ), filepath = [ 'testy', 'Unicode.cs' ] ) @IsolatedYcmd def Subcommands_StopServer_NoErrorIfNotStarted_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) StopCompleterServer( app, 'cs', filepath ) # Success = no raise @IsolatedYcmd def StopServer_KeepLogFiles( app, keeping_log_files ): with UserOption( 'server_keep_logfiles', keeping_log_files ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) WaitUntilCompleterServerReady( app, 'cs' ) event_data = BuildRequest( filetype = 'cs', filepath = filepath ) debuginfo = app.post_json( '/debug_info', event_data ).json log_files_match = re.search( '^ OmniSharp logfiles:\n' ' (.*)\n' ' (.*)', debuginfo, re.MULTILINE ) stdout_logfiles_location = log_files_match.group( 1 ) stderr_logfiles_location = log_files_match.group( 2 ) try: ok_( os.path.exists(stdout_logfiles_location ), "Logfile should exist at {0}".format( stdout_logfiles_location ) ) ok_( os.path.exists( stderr_logfiles_location ), "Logfile should exist at {0}".format( stderr_logfiles_location ) ) finally: StopCompleterServer( app, 'cs', filepath ) if keeping_log_files: ok_( os.path.exists( stdout_logfiles_location ), "Logfile should still exist at " "{0}".format( stdout_logfiles_location ) ) ok_( os.path.exists( stderr_logfiles_location ), "Logfile should still exist at " "{0}".format( stderr_logfiles_location ) ) else: ok_( not os.path.exists( stdout_logfiles_location ), "Logfile should no longer exist at " "{0}".format( stdout_logfiles_location ) ) ok_( not os.path.exists( stderr_logfiles_location ), "Logfile should no longer exist at " "{0}".format( stderr_logfiles_location ) ) def Subcommands_StopServer_KeepLogFiles_test(): yield StopServer_KeepLogFiles, True yield StopServer_KeepLogFiles, False ycmd-0+20161219+git486b809.orig/ycmd/tests/cs/debug_info_test.py0000644000175000017500000001120013026170313022366 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, matches_regexp from ycmd.tests.cs import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, StopCompleterServer, UserOption, WaitUntilCompleterServerReady ) from ycmd.utils import ReadFile @SharedYcmd def DebugInfo_ServerIsRunning_test( app ): filepath = PathToTestFile( 'testy', 'Program.cs' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) WaitUntilCompleterServerReady( app, 'cs' ) request_data = BuildRequest( filepath = filepath, filetype = 'cs' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'C# completer debug information:\n' ' OmniSharp running at: http://localhost:\d+\n' ' OmniSharp process ID: \d+\n' ' OmniSharp executable: .+\n' ' OmniSharp logfiles:\n' ' .+\n' ' .+\n' ' OmniSharp solution: .+' ) ) @SharedYcmd def DebugInfo_ServerIsNotRunning_NoSolution_test( app ): request_data = BuildRequest( filetype = 'cs' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'C# completer debug information:\n' ' OmniSharp not running\n' ' OmniSharp executable: .+\n' ' OmniSharp solution: not found' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesExist_test( app ): with UserOption( 'server_keep_logfiles', True ): filepath = PathToTestFile( 'testy', 'Program.cs' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) WaitUntilCompleterServerReady( app, 'cs' ) StopCompleterServer( app, 'cs', filepath ) request_data = BuildRequest( filepath = filepath, filetype = 'cs' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'C# completer debug information:\n' ' OmniSharp no longer running\n' ' OmniSharp executable: .+\n' ' OmniSharp logfiles:\n' ' .+\n' ' .+\n' ' OmniSharp solution: .+' ) ) @IsolatedYcmd def DebugInfo_ServerIsNotRunning_LogfilesDoNotExist_test( app ): with UserOption( 'server_keep_logfiles', False ): filepath = PathToTestFile( 'testy', 'Program.cs' ) contents = ReadFile( filepath ) event_data = BuildRequest( filepath = filepath, filetype = 'cs', contents = contents, event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ) WaitUntilCompleterServerReady( app, 'cs' ) StopCompleterServer( app, 'cs', filepath ) request_data = BuildRequest( filepath = filepath, filetype = 'cs' ) assert_that( app.post_json( '/debug_info', request_data ).json, matches_regexp( 'C# completer debug information:\n' ' OmniSharp is not running\n' ' OmniSharp executable: .+\n' ' OmniSharp solution: .+' ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/misc_handlers_test.py0000644000175000017500000000723313026170313022506 0ustar onuronur# Copyright (C) 2013 Google Inc. # 2015 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from hamcrest import assert_that, contains, empty, equal_to, has_entries import requests from ycmd.tests import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, DummyCompleter, PatchCompleter @SharedYcmd def MiscHandlers_SemanticCompletionAvailable_test( app ): with PatchCompleter( DummyCompleter, filetype = 'dummy_filetype' ): request_data = BuildRequest( filetype = 'dummy_filetype' ) assert_that( app.post_json( '/semantic_completion_available', request_data ).json, equal_to( True ) ) @SharedYcmd def MiscHandlers_EventNotification_AlwaysJsonResponse_test( app ): event_data = BuildRequest( contents = 'foo foogoo ba', event_name = 'FileReadyToParse' ) assert_that( app.post_json( '/event_notification', event_data ).json, empty() ) @SharedYcmd def MiscHandlers_EventNotification_ReturnJsonOnBigFileError_test( app ): # We generate a content greater than Bottle.MEMFILE_MAX, which is set to 10MB. contents = "foo " * 5000000 event_data = BuildRequest( contents = contents, event_name = 'FileReadyToParse' ) response = app.post_json( '/event_notification', event_data, expect_errors = True ) assert_that( response.status_code, equal_to( requests.codes.request_entity_too_large ) ) assert_that( response.json, has_entries( { 'traceback': None, 'message': 'None', 'exception': None } ) ) @SharedYcmd def MiscHandlers_FilterAndSortCandidates_Basic_test( app ): candidate1 = { 'prop1': 'aoo', 'prop2': 'bar' } candidate2 = { 'prop1': 'bfo', 'prop2': 'zoo' } candidate3 = { 'prop1': 'cfo', 'prop2': 'moo' } data = { 'candidates': [ candidate3, candidate1, candidate2 ], 'sort_property': 'prop1', 'query': 'fo' } response_data = app.post_json( '/filter_and_sort_candidates', data ).json assert_that( response_data, contains( candidate2, candidate3 ) ) @SharedYcmd def MiscHandlers_LoadExtraConfFile_AlwaysJsonResponse_test( app ): filepath = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) extra_conf_data = BuildRequest( filepath = filepath ) assert_that( app.post_json( '/load_extra_conf_file', extra_conf_data ).json, equal_to( True ) ) @SharedYcmd def MiscHandlers_IgnoreExtraConfFile_AlwaysJsonResponse_test( app ): filepath = PathToTestFile( 'extra_conf', 'project', '.ycm_extra_conf.py' ) extra_conf_data = BuildRequest( filepath = filepath ) assert_that( app.post_json( '/ignore_extra_conf_file', extra_conf_data ).json, equal_to( True ) ) ycmd-0+20161219+git486b809.orig/ycmd/tests/hmac_utils_test.py0000644000175000017500000000757213026170313022031 0ustar onuronur# Copyright (C) 2016 ycmd contributors. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . # Intentionally not importing unicode_literals! from __future__ import division from __future__ import print_function from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from binascii import hexlify from nose.tools import eq_, ok_ from hamcrest import raises, assert_that, calling from ycmd import hmac_utils as hu from ycmd.tests.test_utils import Py2Only def CreateHmac_ArgsNotBytes_test(): assert_that( calling( hu.CreateHmac ).with_args( u'foo', bytes( b'foo' ) ), raises( TypeError, '.*content*' ) ) assert_that( calling( hu.CreateHmac ).with_args( bytes( b'foo' ), u'foo' ), raises( TypeError, '.*hmac_secret*' ) ) def CreateHmac_WithBytes_test(): # Test vectors from Wikipedia (HMAC_SHA256): https://goo.gl/cvX0Tn eq_( hexlify( hu.CreateHmac( bytes( b'The quick brown fox jumps over the lazy dog' ), bytes( b'key' ) ) ), bytes( b'f7bc83f430538424b13298e6aa6fb143' b'ef4d59a14946175997479dbc2d1a3cd8' ) ) @Py2Only def CreateHmac_WithPy2Str_test(): # Test vectors from Wikipedia (HMAC_SHA256): https://goo.gl/cvX0Tn eq_( hexlify( hu.CreateHmac( 'The quick brown fox jumps over the lazy dog', 'key' ) ), 'f7bc83f430538424b13298e6aa6fb143' 'ef4d59a14946175997479dbc2d1a3cd8' ) def CreateRequestHmac_ArgsNotBytes_test(): assert_that( calling( hu.CreateRequestHmac ).with_args( u'foo', bytes( b'foo' ), bytes( b'foo' ), bytes( b'foo' ) ), raises( TypeError, '.*method*' ) ) assert_that( calling( hu.CreateRequestHmac ).with_args( bytes( b'foo' ), u'foo', bytes( b'foo' ), bytes( b'foo' ) ), raises( TypeError, '.*path*' ) ) assert_that( calling( hu.CreateRequestHmac ).with_args( bytes( b'foo' ), bytes( b'foo' ), u'foo', bytes( b'foo' ) ), raises( TypeError, '.*body*' ) ) assert_that( calling( hu.CreateRequestHmac ).with_args( bytes( b'foo' ), bytes( b'foo' ), bytes( b'foo' ), u'foo' ), raises( TypeError, '.*hmac_secret*' ) ) def CreateRequestHmac_WithBytes_test(): eq_( hexlify( hu.CreateRequestHmac( bytes( b'GET' ), bytes( b'/foo' ), bytes( b'body' ), bytes( b'key' ) ) ), bytes( b'bfbb6bc7a2b3eca2a78f4e7ec8a7dfa7' b'e58bb8974166eaf20e0224d999894b34' ) ) @Py2Only def CreateRequestHmac_WithPy2Str_test(): eq_( hexlify( hu.CreateRequestHmac( 'GET', '/foo', 'body', 'key' ) ), 'bfbb6bc7a2b3eca2a78f4e7ec8a7dfa7' 'e58bb8974166eaf20e0224d999894b34' ) def SecureBytesEqual_Basic_test(): ok_( hu.SecureBytesEqual( bytes( b'foo' ), bytes( b'foo' ) ) ) ok_( not hu.SecureBytesEqual( bytes( b'foo' ), bytes( b'fo' ) ) ) ok_( not hu.SecureBytesEqual( bytes( b'foo' ), bytes( b'goo' ) ) ) def SecureBytesEqual_Empty_test(): ok_( hu.SecureBytesEqual( bytes(), bytes() ) ) def SecureBytesEqual_ExceptionOnUnicode_test(): assert_that( calling( hu.SecureBytesEqual ).with_args( u'foo', u'foo' ), raises( TypeError, '.*inputs must be bytes.*' ) ) @Py2Only def SecureBytesEqual_ExceptionOnPy2Str_test(): assert_that( calling( hu.SecureBytesEqual ).with_args( 'foo', 'foo' ), raises( TypeError, '.*inputs must be bytes.*' ) ) ycmd-0+20161219+git486b809.orig/ycmd/__init__.py0000644000175000017500000000000013026170313017212 0ustar onuronurycmd-0+20161219+git486b809.orig/ycmd/handlers.py0000644000175000017500000002412213026170313017266 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function from __future__ import division from future import standard_library standard_library.install_aliases() from builtins import * # noqa import bottle import json import logging import time import traceback from bottle import request from threading import Thread import ycm_core from ycmd import extra_conf_store, hmac_plugin, server_state, user_options_store from ycmd.responses import BuildExceptionResponse, BuildCompletionResponse from ycmd.request_wrap import RequestWrap from ycmd.bottle_utils import SetResponseHeader from ycmd.completers.completer_utils import FilterAndSortCandidatesWrap # num bytes for the request body buffer; request.json only works if the request # size is less than this bottle.Request.MEMFILE_MAX = 10 * 1024 * 1024 _server_state = None _hmac_secret = bytes() _logger = logging.getLogger( __name__ ) app = bottle.Bottle() wsgi_server = None @app.post( '/event_notification' ) def EventNotification(): _logger.info( 'Received event notification' ) request_data = RequestWrap( request.json ) event_name = request_data[ 'event_name' ] _logger.debug( 'Event name: %s', event_name ) event_handler = 'On' + event_name getattr( _server_state.GetGeneralCompleter(), event_handler )( request_data ) filetypes = request_data[ 'filetypes' ] response_data = None if _server_state.FiletypeCompletionUsable( filetypes ): response_data = getattr( _server_state.GetFiletypeCompleter( filetypes ), event_handler )( request_data ) if response_data: return _JsonResponse( response_data ) return _JsonResponse( {} ) @app.post( '/run_completer_command' ) def RunCompleterCommand(): _logger.info( 'Received command request' ) request_data = RequestWrap( request.json ) completer = _GetCompleterForRequestData( request_data ) return _JsonResponse( completer.OnUserCommand( request_data[ 'command_arguments' ], request_data ) ) @app.post( '/completions' ) def GetCompletions(): _logger.info( 'Received completion request' ) request_data = RequestWrap( request.json ) ( do_filetype_completion, forced_filetype_completion ) = ( _server_state.ShouldUseFiletypeCompleter( request_data ) ) _logger.debug( 'Using filetype completion: %s', do_filetype_completion ) errors = None completions = None if do_filetype_completion: try: completions = ( _server_state.GetFiletypeCompleter( request_data[ 'filetypes' ] ) .ComputeCandidates( request_data ) ) except Exception as exception: if forced_filetype_completion: # user explicitly asked for semantic completion, so just pass the error # back raise else: # store the error to be returned with results from the identifier # completer stack = traceback.format_exc() _logger.error( 'Exception from semantic completer (using general): ' + "".join( stack ) ) errors = [ BuildExceptionResponse( exception, stack ) ] if not completions and not forced_filetype_completion: completions = ( _server_state.GetGeneralCompleter() .ComputeCandidates( request_data ) ) return _JsonResponse( BuildCompletionResponse( completions if completions else [], request_data.CompletionStartColumn(), errors = errors ) ) @app.post( '/filter_and_sort_candidates' ) def FilterAndSortCandidates(): _logger.info( 'Received filter & sort request' ) # Not using RequestWrap because no need and the requests coming in aren't like # the usual requests we handle. request_data = request.json return _JsonResponse( FilterAndSortCandidatesWrap( request_data[ 'candidates'], request_data[ 'sort_property' ], request_data[ 'query' ] ) ) @app.get( '/healthy' ) def GetHealthy(): _logger.info( 'Received health request' ) if request.query.include_subservers: cs_completer = _server_state.GetFiletypeCompleter( ['cs'] ) return _JsonResponse( cs_completer.ServerIsHealthy() ) return _JsonResponse( True ) @app.get( '/ready' ) def GetReady(): _logger.info( 'Received ready request' ) if request.query.subserver: filetype = request.query.subserver return _JsonResponse( _IsSubserverReady( filetype ) ) if request.query.include_subservers: return _JsonResponse( _IsSubserverReady( 'cs' ) ) return _JsonResponse( True ) def _IsSubserverReady( filetype ): completer = _server_state.GetFiletypeCompleter( [filetype] ) return completer.ServerIsReady() @app.post( '/semantic_completion_available' ) def FiletypeCompletionAvailable(): _logger.info( 'Received filetype completion available request' ) return _JsonResponse( _server_state.FiletypeCompletionAvailable( RequestWrap( request.json )[ 'filetypes' ] ) ) @app.post( '/defined_subcommands' ) def DefinedSubcommands(): _logger.info( 'Received defined subcommands request' ) completer = _GetCompleterForRequestData( RequestWrap( request.json ) ) return _JsonResponse( completer.DefinedSubcommands() ) @app.post( '/detailed_diagnostic' ) def GetDetailedDiagnostic(): _logger.info( 'Received detailed diagnostic request' ) request_data = RequestWrap( request.json ) completer = _GetCompleterForRequestData( request_data ) return _JsonResponse( completer.GetDetailedDiagnostic( request_data ) ) @app.post( '/load_extra_conf_file' ) def LoadExtraConfFile(): _logger.info( 'Received extra conf load request' ) request_data = RequestWrap( request.json, validate = False ) extra_conf_store.Load( request_data[ 'filepath' ], force = True ) return _JsonResponse( True ) @app.post( '/ignore_extra_conf_file' ) def IgnoreExtraConfFile(): _logger.info( 'Received extra conf ignore request' ) request_data = RequestWrap( request.json, validate = False ) extra_conf_store.Disable( request_data[ 'filepath' ] ) return _JsonResponse( True ) @app.post( '/debug_info' ) def DebugInfo(): _logger.info( 'Received debug info request' ) output = [] has_clang_support = ycm_core.HasClangSupport() output.append( 'Server has Clang support compiled in: {0}'.format( has_clang_support ) ) if has_clang_support: output.append( 'Clang version: ' + ycm_core.ClangVersion() ) request_data = RequestWrap( request.json ) try: output.append( _GetCompleterForRequestData( request_data ).DebugInfo( request_data ) ) except Exception: _logger.debug( 'Exception in debug info request: ' + traceback.format_exc() ) return _JsonResponse( '\n'.join( output ) ) @app.post( '/shutdown' ) def Shutdown(): _logger.info( 'Received shutdown request' ) ServerShutdown() return _JsonResponse( True ) # The type of the param is Bottle.HTTPError def ErrorHandler( httperror ): body = _JsonResponse( BuildExceptionResponse( httperror.exception, httperror.traceback ) ) hmac_plugin.SetHmacHeader( body, _hmac_secret ) return body # For every error Bottle encounters it will use this as the default handler app.default_error_handler = ErrorHandler def _JsonResponse( data ): SetResponseHeader( 'Content-Type', 'application/json' ) return json.dumps( data, default = _UniversalSerialize ) def _UniversalSerialize( obj ): try: serialized = obj.__dict__.copy() serialized[ 'TYPE' ] = type( obj ).__name__ return serialized except AttributeError: return str( obj ) def _GetCompleterForRequestData( request_data ): completer_target = request_data.get( 'completer_target', None ) if completer_target == 'identifier': return _server_state.GetGeneralCompleter().GetIdentifierCompleter() elif completer_target == 'filetype_default' or not completer_target: return _server_state.GetFiletypeCompleter( request_data[ 'filetypes' ] ) else: return _server_state.GetFiletypeCompleter( [ completer_target ] ) def ServerShutdown(): def Terminator(): if wsgi_server: wsgi_server.Shutdown() # Use a separate thread to let the server send the response before shutting # down. terminator = Thread( target = Terminator ) terminator.daemon = True terminator.start() def ServerCleanup(): if _server_state: _server_state.Shutdown() extra_conf_store.Shutdown() def SetHmacSecret( hmac_secret ): global _hmac_secret _hmac_secret = hmac_secret def UpdateUserOptions( options ): global _server_state if not options: return # This should never be passed in, but let's try to remove it just in case. options.pop( 'hmac_secret', None ) user_options_store.SetAll( options ) _server_state = server_state.ServerState( options ) def SetServerStateToDefaults(): global _server_state, _logger _logger = logging.getLogger( __name__ ) user_options_store.LoadDefaults() _server_state = server_state.ServerState( user_options_store.GetAll() ) extra_conf_store.Reset() def KeepSubserversAlive( check_interval_seconds ): def Keepalive( check_interval_seconds ): while True: time.sleep( check_interval_seconds ) _logger.debug( 'Keeping subservers alive' ) loaded_completers = _server_state.GetLoadedFiletypeCompleters() for completer in loaded_completers: completer.ServerIsHealthy() keepalive = Thread( target = Keepalive, args = ( check_interval_seconds, ) ) keepalive.daemon = True keepalive.start() ycmd-0+20161219+git486b809.orig/ycmd/identifier_utils.py0000644000175000017500000001327613026170313021040 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import re COMMENT_AND_STRING_REGEX = re.compile( "//.*?$" # Anything following '//' "|" "#.*?$" # Anything following '#' "|" "/\*(?:\n|.)*?\*/" # C-style comments, '/* ... */' "|" # Python-style multi-line single-quote string "'''(?:\n|.)*?'''" "|" # Python-style multi-line double-quote string '"""(?:\n|.)*?"""' "|" # Anything inside single quotes, '...', but mind: # 1. that the starting single quote is not escaped # 2. the escaped slash (\\) # 3. the escaped single quote inside the string r"(?='\"}{\.]*", re.UNICODE ), # Spec: http://cran.r-project.org/doc/manuals/r-release/R-lang.pdf # Section 10.3.2. # Can be any sequence of '.', '_' and alphanum BUT can't start with: # - '.' followed by digit # - digit # - '_' 'r': re.compile( r"(?!(?:\.\d|\d|_))[\.\w]+", re.UNICODE ), # Spec: http://clojure.org/reader # Section: Symbols 'clojure': re.compile( r"[-\*\+!_\?:\.a-zA-Z][-\*\+!_\?:\.\w]*/?[-\*\+!_\?:\.\w]*", re.UNICODE ), # Spec: http://www.haskell.org/onlinereport/lexemes.html # Section 2.4 'haskell': re.compile( r"[_a-zA-Z][\w']+", re.UNICODE ), # Spec: ? # Labels like \label{fig:foobar} are very common 'tex': re.compile( r"[_a-zA-Z:-]+", re.UNICODE ), # Spec: http://doc.perl6.org/language/syntax 'perl6': re.compile( r"[_a-zA-Z](?:\w|[-'](?=[_a-zA-Z]))*", re.UNICODE ), } FILETYPE_TO_IDENTIFIER_REGEX[ 'typescript' ] = ( FILETYPE_TO_IDENTIFIER_REGEX[ 'javascript' ] ) FILETYPE_TO_IDENTIFIER_REGEX[ 'scss' ] = FILETYPE_TO_IDENTIFIER_REGEX[ 'css' ] FILETYPE_TO_IDENTIFIER_REGEX[ 'sass' ] = FILETYPE_TO_IDENTIFIER_REGEX[ 'css' ] FILETYPE_TO_IDENTIFIER_REGEX[ 'less' ] = FILETYPE_TO_IDENTIFIER_REGEX[ 'css' ] FILETYPE_TO_IDENTIFIER_REGEX[ 'elisp' ] = ( FILETYPE_TO_IDENTIFIER_REGEX[ 'clojure' ] ) FILETYPE_TO_IDENTIFIER_REGEX[ 'lisp' ] = ( FILETYPE_TO_IDENTIFIER_REGEX[ 'clojure' ] ) def IdentifierRegexForFiletype( filetype ): return FILETYPE_TO_IDENTIFIER_REGEX.get( filetype, DEFAULT_IDENTIFIER_REGEX ) def RemoveIdentifierFreeText( text ): return COMMENT_AND_STRING_REGEX.sub( '', text ) def ExtractIdentifiersFromText( text, filetype = None ): return re.findall( IdentifierRegexForFiletype( filetype ), text ) def IsIdentifier( text, filetype = None ): if not text: return False regex = IdentifierRegexForFiletype( filetype ) match = regex.match( text ) return match and match.end() == len( text ) # index is 0-based and EXCLUSIVE, so ("foo.", 3) -> 0 # Works with both unicode and str objects. # Returns the index on bad input. def StartOfLongestIdentifierEndingAtIndex( text, index, filetype = None ): if not text or index < 1 or index > len( text ): return index for i in range( index ): if IsIdentifier( text[ i : index ], filetype ): return i return index # If the index is not on a valid identifer, it searches forward until a valid # identifier is found. Returns the identifier. def IdentifierAtIndex( text, index, filetype = None ): if index > len( text ): return '' for match in IdentifierRegexForFiletype( filetype ).finditer( text ): if match.end() > index: return match.group() return '' ycmd-0+20161219+git486b809.orig/ycmd/user_options_store.py0000644000175000017500000000275413026170313021442 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import json import os from frozendict import frozendict from ycmd.utils import ReadFile _USER_OPTIONS = {} def SetAll( new_options ): global _USER_OPTIONS _USER_OPTIONS = frozendict( new_options ) def GetAll(): return _USER_OPTIONS def Value( key ): return _USER_OPTIONS[ key ] def LoadDefaults(): SetAll( DefaultOptions() ) def DefaultOptions(): settings_path = os.path.join( os.path.dirname( os.path.abspath( __file__ ) ), 'default_settings.json' ) options = json.loads( ReadFile( settings_path ) ) options.pop( 'hmac_secret', None ) return options ycmd-0+20161219+git486b809.orig/ycmd/watchdog_plugin.py0000644000175000017500000000715613026170313020654 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import time import copy import logging from threading import Thread, Lock from ycmd.handlers import ServerShutdown _logger = logging.getLogger( __name__ ) # This class implements the Bottle plugin API: # http://bottlepy.org/docs/dev/plugindev.html # # The idea here is to decorate every route handler automatically so that on # every request, we log when the request was made. Then a watchdog thread checks # every check_interval_seconds whether the server has been idle for a time # greater that the passed-in idle_suicide_seconds. If it has, we kill the # server. # # We want to do this so that if something goes bonkers in Vim and the server # never gets killed by the client, we don't end up with lots of zombie servers. class WatchdogPlugin( object ): name = 'watchdog' api = 2 def __init__( self, idle_suicide_seconds, check_interval_seconds ): self._check_interval_seconds = check_interval_seconds self._idle_suicide_seconds = idle_suicide_seconds # No need for a lock on wakeup time since only the watchdog thread ever # reads or sets it. self._last_wakeup_time = time.time() self._last_request_time = time.time() self._last_request_time_lock = Lock() if idle_suicide_seconds <= 0: return self._watchdog_thread = Thread( target = self._WatchdogMain ) self._watchdog_thread.daemon = True self._watchdog_thread.start() def _GetLastRequestTime( self ): with self._last_request_time_lock: return copy.deepcopy( self._last_request_time ) def _SetLastRequestTime( self, new_value ): with self._last_request_time_lock: self._last_request_time = new_value def _TimeSinceLastRequest( self ): return time.time() - self._GetLastRequestTime() def _TimeSinceLastWakeup( self ): return time.time() - self._last_wakeup_time def _UpdateLastWakeupTime( self ): self._last_wakeup_time = time.time() def _WatchdogMain( self ): while True: time.sleep( self._check_interval_seconds ) # We make sure we don't terminate if we skipped a wakeup time. If we # skipped a check, that means the machine probably went to sleep and the # client might still actually be up. In such cases, we give it one more # wait interval to contact us before we die. if (self._TimeSinceLastRequest() > self._idle_suicide_seconds and self._TimeSinceLastWakeup() < 2 * self._check_interval_seconds): _logger.info( 'Shutting down server due to inactivity' ) ServerShutdown() self._UpdateLastWakeupTime() def __call__( self, callback ): def wrapper( *args, **kwargs ): self._SetLastRequestTime( time.time() ) return callback( *args, **kwargs ) return wrapper ycmd-0+20161219+git486b809.orig/ycmd/wsgi_server.py0000644000175000017500000000442413026170313020030 0ustar onuronur# Copyright (C) 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import listvalues from waitress.server import TcpWSGIServer import select class StoppableWSGIServer( TcpWSGIServer ): """StoppableWSGIServer is a subclass of the TcpWSGIServer Waitress server with a shutdown method. It is based on StopableWSGIServer class from webtest: https://github.com/Pylons/webtest/blob/master/webtest/http.py""" shutdown_requested = False def Run( self ): """Wrapper of TcpWSGIServer run method. It prevents a traceback from asyncore.""" # Message for compatibility with clients who expect the output from # waitress.serve here print( 'serving on http://{0}:{1}'.format( self.effective_host, self.effective_port ) ) try: self.run() except select.error: if not self.shutdown_requested: raise def Shutdown( self ): """Properly shutdown the server.""" self.shutdown_requested = True # Shutdown waitress threads. self.task_dispatcher.shutdown() # Close asyncore channels. # We don't use itervalues here because _map is modified while looping # through it. # NOTE: _map is an attribute from the asyncore.dispatcher class, which is a # base class of TcpWSGIServer. This may change in future versions of # waitress so extra care should be taken when updating waitress. for channel in listvalues( self._map ): channel.close() ycmd-0+20161219+git486b809.orig/ycmd/bottle_utils.py0000644000175000017500000000345713026170313020207 0ustar onuronur# Copyright (C) 2016 ycmd contributors. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import PY2 from ycmd.utils import ToBytes, ToUnicode import bottle # Bottle.py is stupid when it comes to bytes vs unicode so we have to carefully # conform to its stupidity when setting headers. # Bottle docs state that the response.headers dict-like object stores keys and # values as bytes on py2 and unicode on py3. What it _actually_ does is store # keys in this variable state while values are always unicode (on both py2 and # py3). # Both the documented and actual behavior are dumb and cause needless problems. # Bottle should just consistently store unicode objects on both Python versions, # making life easier for codebases that work across versions, thus preventing # tracebacks in the depths of WSGI server frameworks. def SetResponseHeader( name, value ): name = ToBytes( name ) if PY2 else ToUnicode( name ) bottle.response.set_header( name, ToUnicode( value ) ) ycmd-0+20161219+git486b809.orig/ycmd/request_validation.py0000644000175000017500000000506613026170313021376 0ustar onuronur# Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.responses import ServerError # Throws an exception if request doesn't have all the required fields. # TODO: Accept a request_type param so that we can also verify missing # command_arguments and completer_target fields if necessary. def EnsureRequestValid( request_json ): required_fields = set( [ 'line_num', 'column_num', 'filepath', 'file_data' ] ) missing = set( x for x in required_fields if x not in request_json ) if 'filepath' not in missing and 'file_data' not in missing: missing.update( _MissingFieldsForFileData( request_json ) ) if not missing: return True message = '\n'.join( _FieldMissingMessage( field ) for field in missing ) raise ServerError( message ) def _FieldMissingMessage( field ): return 'Request missing required field: {0}'.format( field ) def _FilepathInFileDataSpec( request_json ): return 'file_data["{0}"]'.format( request_json[ 'filepath' ] ) def _SingleFileDataFieldSpec( request_json, field ): return '{0}["{1}"]'.format( _FilepathInFileDataSpec( request_json ), field ) def _MissingFieldsForFileData( request_json ): missing = set() data_for_file = request_json[ 'file_data' ].get( request_json[ 'filepath' ] ) if data_for_file: required_data = [ 'filetypes', 'contents' ] for required in required_data: if required not in data_for_file: missing.add( _SingleFileDataFieldSpec( request_json, required ) ) filetypes = data_for_file.get( 'filetypes', [] ) if not filetypes: missing.add( '{0}[0]'.format( _SingleFileDataFieldSpec( request_json, 'filetypes' ) ) ) else: missing.add( _FilepathInFileDataSpec( request_json ) ) return missing ycmd-0+20161219+git486b809.orig/ycmd/utils.py0000644000175000017500000003536113026170313016635 0ustar onuronur# encoding: utf-8 # # Copyright (C) 2011, 2012 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from future.utils import PY2, native import os import socket import subprocess import sys import tempfile import time # Creation flag to disable creating a console window on Windows. See # https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx CREATE_NO_WINDOW = 0x08000000 EXECUTABLE_FILE_MASK = os.F_OK | os.X_OK # Python 3 complains on the common open(path).read() idiom because the file # doesn't get closed. So, a helper func. # Also, all files we read are UTF-8. def ReadFile( filepath ): with open( filepath, encoding = 'utf8' ) as f: return f.read() # Returns a file object that can be used to replace sys.stdout or sys.stderr def OpenForStdHandle( filepath ): # Need to open the file in binary mode on py2 because of bytes vs unicode. # If we open in text mode (default), then third-party code that uses `print` # (we're replacing sys.stdout!) with an `str` object on py2 will cause # tracebacks because text mode insists on unicode objects. (Don't forget, # `open` is actually `io.open` because of future builtins.) # Since this function is used for logging purposes, we don't want the output # to be delayed. This means no buffering for binary mode and line buffering # for text mode. See https://docs.python.org/2/library/io.html#io.open if PY2: return open( filepath, mode = 'wb', buffering = 0 ) return open( filepath, mode = 'w', buffering = 1 ) def CreateLogfile( prefix = '' ): with tempfile.NamedTemporaryFile( prefix = prefix, suffix = '.log', delete = False ) as logfile: return logfile.name # Given an object, returns a str object that's utf-8 encoded. This is meant to # be used exclusively when producing strings to be passed to the C++ Python # plugins. For other code, you likely want to use ToBytes below. def ToCppStringCompatible( value ): if isinstance( value, str ): return native( value.encode( 'utf8' ) ) if isinstance( value, bytes ): return native( value ) return native( str( value ).encode( 'utf8' ) ) # Returns a unicode type; either the new python-future str type or the real # unicode type. The difference shouldn't matter. def ToUnicode( value ): if not value: return str() if isinstance( value, str ): return value if isinstance( value, bytes ): # All incoming text should be utf8 return str( value, 'utf8' ) return str( value ) # When lines is an iterable of all strings or all bytes, equivalent to # '\n'.join( ToUnicode( lines ) ) # but faster on large inputs. def JoinLinesAsUnicode( lines ): try: first = next( iter( lines ) ) except StopIteration: return str() if isinstance( first, str ): return ToUnicode( '\n'.join( lines ) ) if isinstance( first, bytes ): return ToUnicode( b'\n'.join( lines ) ) raise ValueError( 'lines must contain either strings or bytes.' ) # Consistently returns the new bytes() type from python-future. Assumes incoming # strings are either UTF-8 or unicode (which is converted to UTF-8). def ToBytes( value ): if not value: return bytes() # This is tricky. On py2, the bytes type from builtins (from python-future) is # a subclass of str. So all of the following are true: # isinstance(str(), bytes) # isinstance(bytes(), str) # But they don't behave the same in one important aspect: iterating over a # bytes instance yields ints, while iterating over a (raw, py2) str yields # chars. We want consistent behavior so we force the use of bytes(). if type( value ) == bytes: return value # This is meant to catch Python 2's native str type. if isinstance( value, bytes ): return bytes( value, encoding = 'utf8' ) if isinstance( value, str ): # On py2, with `from builtins import *` imported, the following is true: # # bytes(str(u'abc'), 'utf8') == b"b'abc'" # # Obviously this is a bug in python-future. So we work around it. Also filed # upstream at: https://github.com/PythonCharmers/python-future/issues/193 # We can't just return value.encode( 'utf8' ) on both py2 & py3 because on # py2 that *sometimes* returns the built-in str type instead of the newbytes # type from python-future. if PY2: return bytes( value.encode( 'utf8' ), encoding = 'utf8' ) else: return bytes( value, encoding = 'utf8' ) # This is meant to catch `int` and similar non-string/bytes types. return ToBytes( str( value ) ) def ByteOffsetToCodepointOffset( line_value, byte_offset ): """The API calls for byte offsets into the UTF-8 encoded version of the buffer. However, ycmd internally uses unicode strings. This means that when we need to walk 'characters' within the buffer, such as when checking for semantic triggers and similar, we must use codepoint offets, rather than byte offsets. This method converts the |byte_offset|, which is a utf-8 byte offset, into a codepoint offset in the unicode string |line_value|.""" byte_line_value = ToBytes( line_value ) return len( ToUnicode( byte_line_value[ : byte_offset - 1 ] ) ) + 1 def CodepointOffsetToByteOffset( unicode_line_value, codepoint_offset ): """The API calls for byte offsets into the UTF-8 encoded version of the buffer. However, ycmd internally uses unicode strings. This means that when we need to walk 'characters' within the buffer, such as when checking for semantic triggers and similar, we must use codepoint offets, rather than byte offsets. This method converts the |codepoint_offset| which is a unicode codepoint offset into an byte offset into the utf-8 encoded bytes version of |unicode_line_value|.""" # Should be a no-op, but in case someone passes a bytes instance. unicode_line_value = ToUnicode( unicode_line_value ) return len( ToBytes( unicode_line_value[ : codepoint_offset - 1 ] ) ) + 1 def GetUnusedLocalhostPort(): sock = socket.socket() # This tells the OS to give us any free port in the range [1024 - 65535] sock.bind( ( '', 0 ) ) port = sock.getsockname()[ 1 ] sock.close() return port def RemoveIfExists( filename ): try: os.remove( filename ) except OSError: pass def PathToFirstExistingExecutable( executable_name_list ): for executable_name in executable_name_list: path = FindExecutable( executable_name ) if path: return path return None def _GetWindowsExecutable( filename ): def _GetPossibleWindowsExecutable( filename ): pathext = [ ext.lower() for ext in os.environ.get( 'PATHEXT', '' ).split( os.pathsep ) ] base, extension = os.path.splitext( filename ) if extension.lower() in pathext: return [ filename ] else: return [ base + ext for ext in pathext ] for exe in _GetPossibleWindowsExecutable( filename ): if os.path.isfile( exe ): return exe return None # Check that a given file can be accessed as an executable file, so controlling # the access mask on Unix and if has a valid extension on Windows. It returns # the path to the executable or None if no executable was found. def GetExecutable( filename ): if OnWindows(): return _GetWindowsExecutable( filename ) if ( os.path.isfile( filename ) and os.access( filename, EXECUTABLE_FILE_MASK ) ): return filename return None # Adapted from https://hg.python.org/cpython/file/3.5/Lib/shutil.py#l1081 # to be backward compatible with Python2 and more consistent to our codebase. def FindExecutable( executable ): # If we're given a path with a directory part, look it up directly rather # than referring to PATH directories. This includes checking relative to the # current directory, e.g. ./script if os.path.dirname( executable ): return GetExecutable( executable ) paths = os.environ[ 'PATH' ].split( os.pathsep ) if OnWindows(): # The current directory takes precedence on Windows. curdir = os.path.abspath( os.curdir ) if curdir not in paths: paths.insert( 0, curdir ) for path in paths: exe = GetExecutable( os.path.join( path, executable ) ) if exe: return exe return None def ExecutableName( executable ): return executable + ( '.exe' if OnWindows() else '' ) def OnWindows(): return sys.platform == 'win32' def OnCygwin(): return sys.platform == 'cygwin' def OnMac(): return sys.platform == 'darwin' def ProcessIsRunning( handle ): return handle is not None and handle.poll() is None def WaitUntilProcessIsTerminated( handle, timeout = 5 ): expiration = time.time() + timeout while True: if time.time() > expiration: raise RuntimeError( 'Waited process to terminate for {0} seconds, ' 'aborting.'.format( timeout ) ) if not ProcessIsRunning( handle ): return time.sleep( 0.1 ) def CloseStandardStreams( handle ): if not handle: return for stream in [ handle.stdin, handle.stdout, handle.stderr ]: if stream: stream.close() def PathsToAllParentFolders( path ): folder = os.path.normpath( path ) if os.path.isdir( folder ): yield folder while True: parent = os.path.dirname( folder ) if parent == folder: break folder = parent yield folder def ForceSemanticCompletion( request_data ): return ( 'force_semantic' in request_data and bool( request_data[ 'force_semantic' ] ) ) # A wrapper for subprocess.Popen that fixes quirks on Windows. def SafePopen( args, **kwargs ): if OnWindows(): # We need this to start the server otherwise bad things happen. # See issue #637. if kwargs.get( 'stdin_windows' ) is subprocess.PIPE: kwargs[ 'stdin' ] = subprocess.PIPE # Do not create a console window kwargs[ 'creationflags' ] = CREATE_NO_WINDOW # Python 2 fails to spawn a process from a command containing unicode # characters on Windows. See https://bugs.python.org/issue19264 and # http://bugs.python.org/issue1759845. # Since paths are likely to contains such characters, we convert them to # short ones to obtain paths with only ascii characters. if PY2: args = ConvertArgsToShortPath( args ) kwargs.pop( 'stdin_windows', None ) return subprocess.Popen( args, **kwargs ) # We need to convert environment variables to native strings on Windows and # Python 2 to prevent a TypeError when passing them to a subprocess. def SetEnviron( environ, variable, value ): if OnWindows() and PY2: environ[ native( ToBytes( variable ) ) ] = native( ToBytes( value ) ) else: environ[ variable ] = value # Convert paths in arguments command to short path ones def ConvertArgsToShortPath( args ): def ConvertIfPath( arg ): if os.path.exists( arg ): return GetShortPathName( arg ) return arg if isinstance( args, str ) or isinstance( args, bytes ): return ConvertIfPath( args ) return [ ConvertIfPath( arg ) for arg in args ] # Get the Windows short path name. # Based on http://stackoverflow.com/a/23598461/200291 def GetShortPathName( path ): if not OnWindows(): return path from ctypes import windll, wintypes, create_unicode_buffer # Set the GetShortPathNameW prototype _GetShortPathNameW = windll.kernel32.GetShortPathNameW _GetShortPathNameW.argtypes = [ wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD] _GetShortPathNameW.restype = wintypes.DWORD output_buf_size = 0 while True: output_buf = create_unicode_buffer( output_buf_size ) needed = _GetShortPathNameW( path, output_buf, output_buf_size ) if output_buf_size >= needed: return output_buf.value else: output_buf_size = needed # Shim for imp.load_source so that it works on both Py2 & Py3. See upstream # Python docs for info on what this does. def LoadPythonSource( name, pathname ): if PY2: import imp return imp.load_source( name, pathname ) else: import importlib return importlib.machinery.SourceFileLoader( name, pathname ).load_module() def SplitLines( contents ): """Return a list of each of the lines in the unicode string |contents|. Behaviour is equivalent to str.splitlines with the following exceptions: - empty strings are returned as [ '' ] - a trailing newline is not ignored (i.e. SplitLines( '\n' ) returns [ '', '' ], not [ '' ]""" # We often want to get a list representation of a buffer such that we can # index all of the 'lines' within it. Python provides str.splitlines for this # purpose, but its documented behaviors for empty strings and strings ending # with a newline character are not compatible with this. As a result, we write # our own wrapper to provide a splitlines implementation which returns the # actual list of indexable lines in a buffer, where a line may have 0 # characters. # # NOTE: str.split( '\n' ) actually gives this behaviour, except it does not # work when running on a unix-like system and reading a file with Windows line # endings. # ''.splitlines() returns [], but we want [ '' ] if contents == '': return [ '' ] lines = contents.splitlines() # '\n'.splitlines() returns [ '' ]. We want [ '', '' ]. # '\n\n\n'.splitlines() returns [ '', '', '' ]. We want [ '', '', '', '' ]. # # So we re-instate the empty entry at the end if the original string ends # with a newline. Universal newlines recognise the following as # line-terminators: # - '\n' # - '\r\n' # - '\r' # # Importantly, notice that \r\n also ends with \n # if contents.endswith( '\r' ) or contents.endswith( '\n' ): lines.append( '' ) return lines def GetCurrentDirectory(): """Returns the current directory as an unicode object. If the current directory does not exist anymore, returns the temporary folder instead.""" try: if PY2: return os.getcwdu() return os.getcwd() # os.getcwdu throws an OSError exception when the current directory has been # deleted while os.getcwd throws a FileNotFoundError, which is a subclass of # OSError. except OSError: return tempfile.gettempdir() ycmd-0+20161219+git486b809.orig/ycmd/request_wrap.py0000644000175000017500000001332513026170313020212 0ustar onuronur# encoding: utf8 # # Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa from ycmd.utils import ( ByteOffsetToCodepointOffset, CodepointOffsetToByteOffset, ToUnicode, ToBytes, SplitLines ) from ycmd.identifier_utils import StartOfLongestIdentifierEndingAtIndex from ycmd.request_validation import EnsureRequestValid # TODO: Change the custom computed (and other) keys to be actual properties on # the object. class RequestWrap( object ): def __init__( self, request, validate = True ): if validate: EnsureRequestValid( request ) self._request = request self._computed_key = { # Unicode string representation of the current line 'line_value': self._CurrentLine, # The calculated start column, as a codepoint offset into the # unicode string line_value 'start_codepoint': self.CompletionStartCodepoint, # The 'column_num' as a unicode codepoint offset 'column_codepoint': (lambda: ByteOffsetToCodepointOffset( self[ 'line_bytes' ], self[ 'column_num' ] ) ), # Bytes string representation of the current line 'line_bytes': lambda: ToBytes( self[ 'line_value' ] ), # The calculated start column, as a byte offset into the UTF-8 encoded # bytes returned by line_bytes 'start_column': self.CompletionStartColumn, # Note: column_num is the byte offset into the UTF-8 encoded bytes # returned by line_bytes # unicode string representation of the 'query' after the beginning # of the identifier to be completed 'query': self._Query, 'filetypes': self._Filetypes, 'first_filetype': self._FirstFiletype, } self._cached_computed = {} def __getitem__( self, key ): if key in self._cached_computed: return self._cached_computed[ key ] if key in self._computed_key: value = self._computed_key[ key ]() self._cached_computed[ key ] = value return value return self._request[ key ] def __contains__( self, key ): return key in self._computed_key or key in self._request def get( self, key, default = None ): try: return self[ key ] except KeyError: return default def _CurrentLine( self ): current_file = self._request[ 'filepath' ] contents = self._request[ 'file_data' ][ current_file ][ 'contents' ] return SplitLines( contents )[ self._request[ 'line_num' ] - 1 ] def CompletionStartColumn( self ): return CompletionStartColumn( self[ 'line_value' ], self[ 'column_num' ], self[ 'first_filetype' ] ) def CompletionStartCodepoint( self ): return CompletionStartCodepoint( self[ 'line_value' ], self[ 'column_num' ], self[ 'first_filetype' ] ) def _Query( self ): return self[ 'line_value' ][ self[ 'start_codepoint' ] - 1 : self[ 'column_codepoint' ] - 1 ] def _FirstFiletype( self ): try: return self[ 'filetypes' ][ 0 ] except (KeyError, IndexError): return None def _Filetypes( self ): path = self[ 'filepath' ] return self[ 'file_data' ][ path ][ 'filetypes' ] def CompletionStartColumn( line_value, column_num, filetype ): """Returns the 1-based byte index where the completion query should start. So if the user enters: foo.bar^ with the cursor being at the location of the caret (so the character *AFTER* 'r'), then the starting column would be the index of the letter 'b'. NOTE: if the line contains multi-byte characters, then the result is not the 'character' index (see CompletionStartCodepoint for that), and therefore it is not safe to perform any character-relevant arithmetic on the result of this method.""" return CodepointOffsetToByteOffset( ToUnicode( line_value ), CompletionStartCodepoint( line_value, column_num, filetype ) ) def CompletionStartCodepoint( line_value, column_num, filetype ): """Returns the 1-based codepoint index where the completion query should start. So if the user enters: ƒøø.∫å®^ with the cursor being at the location of the caret (so the character *AFTER* '®'), then the starting column would be the index of the character '∫' (i.e. 5, not its byte index).""" # NOTE: column_num and other numbers on the wire are byte indices, but we need # to walk codepoints for identifier checks. codepoint_column_num = ByteOffsetToCodepointOffset( line_value, column_num ) unicode_line_value = ToUnicode( line_value ) # -1 and then +1 to account for difference betwen 0-based and 1-based # indices/columns codepoint_start_column = StartOfLongestIdentifierEndingAtIndex( unicode_line_value, codepoint_column_num - 1, filetype ) + 1 return codepoint_start_column ycmd-0+20161219+git486b809.orig/ycmd/server_utils.py0000644000175000017500000001556513026170313020227 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import # No other imports from `future` because this module is loaded before we have # put our submodules in sys.path import io import logging import os import re import sys CORE_MISSING_ERROR_REGEX = re.compile( "No module named '?ycm_core'?" ) CORE_PYTHON2_ERROR_REGEX = re.compile( 'dynamic module does not define (?:init|module export) ' 'function \(PyInit_ycm_core\)|' 'Module use of python2[0-9].dll conflicts with this version of Python\.$' ) CORE_PYTHON3_ERROR_REGEX = re.compile( 'dynamic module does not define init function \(initycm_core\)|' 'Module use of python3[0-9].dll conflicts with this version of Python\.$' ) CORE_MISSING_MESSAGE = ( 'ycm_core library not detected; you need to compile it by running the ' 'build.py script. See the documentation for more details.' ) CORE_PYTHON2_MESSAGE = ( 'ycm_core library compiled for Python 2 but loaded in Python 3.' ) CORE_PYTHON3_MESSAGE = ( 'ycm_core library compiled for Python 3 but loaded in Python 2.' ) CORE_OUTDATED_MESSAGE = ( 'ycm_core library too old; PLEASE RECOMPILE by running the build.py script. ' 'See the documentation for more details.' ) # Exit statuses returned by the CompatibleWithCurrentCore function: # - CORE_COMPATIBLE_STATUS: ycm_core is compatible; # - CORE_UNEXPECTED_STATUS: unexpected error while loading ycm_core; # - CORE_MISSING_STATUS : ycm_core is missing; # - CORE_PYTHON2_STATUS : ycm_core is compiled with Python 2 but loaded with # Python 3; # - CORE_PYTHON3_STATUS : ycm_core is compiled with Python 3 but loaded with # Python 2; # - CORE_OUTDATED_STATUS : ycm_core version is outdated. # Values 1 and 2 are not used because 1 is for general errors and 2 has often a # special meaning for Unix programs. See # https://docs.python.org/2/library/sys.html#sys.exit CORE_COMPATIBLE_STATUS = 0 CORE_UNEXPECTED_STATUS = 3 CORE_MISSING_STATUS = 4 CORE_PYTHON2_STATUS = 5 CORE_PYTHON3_STATUS = 6 CORE_OUTDATED_STATUS = 7 VERSION_FILENAME = 'CORE_VERSION' DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) ) DIR_PACKAGES_REGEX = re.compile( '(site|dist)-packages$' ) _logger = logging.getLogger( __name__ ) def ExpectedCoreVersion(): filepath = os.path.join( DIR_OF_CURRENT_SCRIPT, '..', VERSION_FILENAME ) with io.open( filepath, encoding = 'utf8' ) as f: return int( f.read() ) def ImportCore(): """Imports and returns the ycm_core module. This function exists for easily mocking this import in tests.""" import ycm_core as ycm_core return ycm_core def CompatibleWithCurrentCore(): """Checks if ycm_core library is compatible and returns with an exit status.""" try: ycm_core = ImportCore() except ImportError as error: message = str( error ) if CORE_MISSING_ERROR_REGEX.match( message ): _logger.exception( CORE_MISSING_MESSAGE ) return CORE_MISSING_STATUS if CORE_PYTHON2_ERROR_REGEX.match( message ): _logger.exception( CORE_PYTHON2_MESSAGE ) return CORE_PYTHON2_STATUS if CORE_PYTHON3_ERROR_REGEX.match( message ): _logger.exception( CORE_PYTHON3_MESSAGE ) return CORE_PYTHON3_STATUS _logger.exception( message ) return CORE_UNEXPECTED_STATUS try: current_core_version = ycm_core.YcmCoreVersion() except AttributeError: _logger.exception( CORE_OUTDATED_MESSAGE ) return CORE_OUTDATED_STATUS if ExpectedCoreVersion() != current_core_version: _logger.error( CORE_OUTDATED_MESSAGE ) return CORE_OUTDATED_STATUS return CORE_COMPATIBLE_STATUS def SetUpPythonPath(): sys.path.insert( 0, os.path.join( DIR_OF_CURRENT_SCRIPT, '..' ) ) AddNearestThirdPartyFoldersToSysPath( __file__ ) def AncestorFolders( path ): folder = os.path.normpath( path ) while True: parent = os.path.dirname( folder ) if parent == folder: break folder = parent yield folder def PathToNearestThirdPartyFolder( path ): for folder in AncestorFolders( path ): path_to_third_party = os.path.join( folder, 'third_party' ) if os.path.isdir( path_to_third_party ): return path_to_third_party return None def IsStandardLibraryFolder( path ): return os.path.isfile( os.path.join( path, 'os.py' ) ) def IsVirtualEnvLibraryFolder( path ): return os.path.isfile( os.path.join( path, 'orig-prefix.txt' ) ) def GetStandardLibraryIndexInSysPath(): for path in sys.path: if ( IsStandardLibraryFolder( path ) and not IsVirtualEnvLibraryFolder( path ) ): return sys.path.index( path ) raise RuntimeError( 'Could not find standard library path in Python path.' ) def AddNearestThirdPartyFoldersToSysPath( filepath ): path_to_third_party = PathToNearestThirdPartyFolder( filepath ) if not path_to_third_party: raise RuntimeError( 'No third_party folder found for: {0}'.format( filepath ) ) # NOTE: Any hacks for loading modules that can't be imported without custom # logic need to be reproduced in run_tests.py as well. for folder in os.listdir( path_to_third_party ): # python-future needs special handling. Not only does it store the modules # under its 'src' folder, but SOME of its modules are only meant to be # accessible under py2, not py3. This is because these modules (like # `queue`) are implementations of modules present in the py3 standard # library. Furthermore, we need to be sure that they are not overridden by # already installed packages (for example, the 'builtins' module from # 'pies2overrides' or a different version of 'python-future'). To work # around these issues, we place the python-future just after the Python # standard library so that its modules can be overridden by standard # modules but not by installed packages. if folder == 'python-future': folder = os.path.join( folder, 'src' ) sys.path.insert( GetStandardLibraryIndexInSysPath() + 1, os.path.realpath( os.path.join( path_to_third_party, folder ) ) ) continue sys.path.insert( 0, os.path.realpath( os.path.join( path_to_third_party, folder ) ) ) ycmd-0+20161219+git486b809.orig/ycmd/hmac_plugin.py0000644000175000017500000000655013026170313017761 0ustar onuronur# Copyright (C) 2014 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import logging import requests from urllib.parse import urlparse from base64 import b64decode, b64encode from bottle import request, abort from ycmd import hmac_utils from ycmd.utils import ToBytes from ycmd.bottle_utils import SetResponseHeader _HMAC_HEADER = 'x-ycm-hmac' _HOST_HEADER = 'host' # This class implements the Bottle plugin API: # http://bottlepy.org/docs/dev/plugindev.html # # We want to ensure that every request coming in has a valid HMAC set in the # x-ycm-hmac header and that every response coming out sets such a valid header. # This is to prevent security issues with possible remote code execution. # The x-ycm-hmac value is encoded as base64 during transport instead of sent raw # because https://tools.ietf.org/html/rfc5987 says header values must be in the # ISO-8859-1 character set. class HmacPlugin( object ): name = 'hmac' api = 2 def __init__( self, hmac_secret ): self._hmac_secret = hmac_secret self._logger = logging.getLogger( __name__ ) def __call__( self, callback ): def wrapper( *args, **kwargs ): if not HostHeaderCorrect( request ): self._logger.info( 'Dropping request with bad Host header.' ) abort( requests.codes.unauthorized, 'Unauthorized, received bad Host header.' ) return body = ToBytes( request.body.read() ) if not RequestAuthenticated( request.method, request.path, body, self._hmac_secret ): self._logger.info( 'Dropping request with bad HMAC.' ) abort( requests.codes.unauthorized, 'Unauthorized, received bad HMAC.' ) return body = callback( *args, **kwargs ) SetHmacHeader( body, self._hmac_secret ) return body return wrapper def HostHeaderCorrect( request ): host = urlparse( 'http://' + request.headers[ _HOST_HEADER ] ).hostname return host == '127.0.0.1' or host == 'localhost' def RequestAuthenticated( method, path, body, hmac_secret ): if _HMAC_HEADER not in request.headers: return False return hmac_utils.SecureBytesEqual( hmac_utils.CreateRequestHmac( ToBytes( method ), ToBytes( path ), ToBytes( body ), ToBytes( hmac_secret ) ), ToBytes( b64decode( request.headers[ _HMAC_HEADER ] ) ) ) def SetHmacHeader( body, hmac_secret ): value = b64encode( hmac_utils.CreateHmac( ToBytes( body ), ToBytes( hmac_secret ) ) ) SetResponseHeader( _HMAC_HEADER, value ) ycmd-0+20161219+git486b809.orig/ycmd/extra_conf_store.py0000644000175000017500000001730713026170313021041 0ustar onuronur# Copyright (C) 2011-2012 Google Inc. # 2016 ycmd contributors # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . # NOTE: This module is used as a Singleton from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os import random import string import sys import logging from threading import Lock from ycmd import user_options_store from ycmd.responses import UnknownExtraConf, YCM_EXTRA_CONF_FILENAME from ycmd.utils import LoadPythonSource, PathsToAllParentFolders from fnmatch import fnmatch _logger = logging.getLogger( __name__ ) # Singleton variables _module_for_module_file = {} _module_for_module_file_lock = Lock() _module_file_for_source_file = {} _module_file_for_source_file_lock = Lock() def Reset(): global _module_for_module_file, _module_file_for_source_file _module_for_module_file = {} _module_file_for_source_file = {} def ModuleForSourceFile( filename ): return Load( ModuleFileForSourceFile( filename ) ) def ModuleFileForSourceFile( filename ): """This will try all files returned by _ExtraConfModuleSourceFilesForFile in order and return the filename of the first module that was allowed to load. If no module was found or allowed to load, None is returned.""" with _module_file_for_source_file_lock: if filename not in _module_file_for_source_file: for module_file in _ExtraConfModuleSourceFilesForFile( filename ): if Load( module_file ): _module_file_for_source_file[ filename ] = module_file break return _module_file_for_source_file.setdefault( filename ) def CallGlobalExtraConfYcmCorePreloadIfExists(): _CallGlobalExtraConfMethod( 'YcmCorePreload' ) def Shutdown(): # VimClose is for the sake of backwards compatibility; it's a no-op when it # doesn't exist. _CallGlobalExtraConfMethod( 'VimClose' ) _CallGlobalExtraConfMethod( 'Shutdown' ) def _CallGlobalExtraConfMethod( function_name ): global_ycm_extra_conf = _GlobalYcmExtraConfFileLocation() if not ( global_ycm_extra_conf and os.path.exists( global_ycm_extra_conf ) ): _logger.debug( 'No global extra conf, ' 'not calling method {0}'.format( function_name ) ) return try: module = Load( global_ycm_extra_conf, force = True ) except Exception: _logger.exception( 'Error occurred while loading ' 'global extra conf {0}'.format( global_ycm_extra_conf ) ) return if not module or not hasattr( module, function_name ): _logger.debug( 'Global extra conf not loaded or no function ' + function_name ) return try: _logger.info( 'Calling global extra conf method {0} ' 'on conf file {1}'.format( function_name, global_ycm_extra_conf ) ) getattr( module, function_name )() except Exception: _logger.exception( 'Error occurred while calling global extra conf method {0} ' 'on conf file {1}'.format( function_name, global_ycm_extra_conf ) ) def Disable( module_file ): """Disables the loading of a module for the current session.""" with _module_for_module_file_lock: _module_for_module_file[ module_file ] = None def _ShouldLoad( module_file ): """Checks if a module is safe to be loaded. By default this will try to decide using a white-/blacklist and ask the user for confirmation as a fallback.""" if ( module_file == _GlobalYcmExtraConfFileLocation() or not user_options_store.Value( 'confirm_extra_conf' ) ): return True globlist = user_options_store.Value( 'extra_conf_globlist' ) for glob in globlist: is_blacklisted = glob[0] == '!' if _MatchesGlobPattern( module_file, glob.lstrip('!') ): return not is_blacklisted raise UnknownExtraConf( module_file ) def Load( module_file, force = False ): """Load and return the module contained in a file. Using force = True the module will be loaded regardless of the criteria in _ShouldLoad. This will return None if the module was not allowed to be loaded.""" if not module_file: return None with _module_for_module_file_lock: if module_file in _module_for_module_file: return _module_for_module_file[ module_file ] if not force and not _ShouldLoad( module_file ): Disable( module_file ) return None # This has to be here because a long time ago, the ycm_extra_conf.py files # used to import clang_helpers.py from the cpp folder. This is not needed # anymore, but there are a lot of old ycm_extra_conf.py files that we don't # want to break. sys.path.insert( 0, _PathToCppCompleterFolder() ) # By default, the Python interpreter compiles source files into bytecode to # load them faster next time they are run. These *.pyc files are generated # along the source files prior to Python 3.2 or in a __pycache__ folder for # newer versions. We disable the generation of these files when loading # ycm_extra_conf.py files as users do not want them inside their projects. # The drawback is negligible since ycm_extra_conf.py files are generally small # files thus really fast to compile and only loaded once by editing session. old_dont_write_bytecode = sys.dont_write_bytecode sys.dont_write_bytecode = True try: module = LoadPythonSource( _RandomName(), module_file ) finally: sys.dont_write_bytecode = old_dont_write_bytecode del sys.path[ 0 ] with _module_for_module_file_lock: _module_for_module_file[ module_file ] = module return module def _MatchesGlobPattern( filename, glob ): """Returns true if a filename matches a given pattern. A '~' in glob will be expanded to the home directory and checking will be performed using absolute paths. See the documentation of fnmatch for the supported patterns.""" abspath = os.path.abspath( filename ) return fnmatch( abspath, os.path.abspath( os.path.expanduser( glob ) ) ) def _ExtraConfModuleSourceFilesForFile( filename ): """For a given filename, search all parent folders for YCM_EXTRA_CONF_FILENAME files that will compute the flags necessary to compile the file. If _GlobalYcmExtraConfFileLocation() exists it is returned as a fallback.""" for folder in PathsToAllParentFolders( filename ): candidate = os.path.join( folder, YCM_EXTRA_CONF_FILENAME ) if os.path.exists( candidate ): yield candidate global_ycm_extra_conf = _GlobalYcmExtraConfFileLocation() if ( global_ycm_extra_conf and os.path.exists( global_ycm_extra_conf ) ): yield global_ycm_extra_conf def _PathToCppCompleterFolder(): """Returns the path to the 'cpp' completer folder. This is necessary because ycm_extra_conf files need it on the path.""" return os.path.join( _DirectoryOfThisScript(), 'completers', 'cpp' ) def _DirectoryOfThisScript(): return os.path.dirname( os.path.abspath( __file__ ) ) def _RandomName(): """Generates a random module name.""" return ''.join( random.choice( string.ascii_lowercase ) for x in range( 15 ) ) def _GlobalYcmExtraConfFileLocation(): return os.path.expanduser( user_options_store.Value( 'global_ycm_extra_conf' ) ) ycmd-0+20161219+git486b809.orig/ycmd/default_settings.json0000644000175000017500000000221313026170313021350 0ustar onuronur{ "filepath_completion_use_working_dir": 0, "auto_trigger": 1, "min_num_of_chars_for_completion": 2, "min_num_identifier_candidate_chars": 0, "semantic_triggers": {}, "filetype_specific_completion_to_disable": { "gitcommit": 1 }, "seed_identifiers_with_syntax": 0, "collect_identifiers_from_comments_and_strings": 0, "collect_identifiers_from_tags_files": 0, "max_num_identifier_candidates": 10, "extra_conf_globlist": [], "global_ycm_extra_conf": "", "confirm_extra_conf": 1, "complete_in_comments": 0, "complete_in_strings": 1, "max_diagnostics_to_display": 30, "filetype_whitelist": { "*": 1 }, "filetype_blacklist": { "tagbar": 1, "qf": 1, "notes": 1, "markdown": 1, "netrw": 1, "unite": 1, "text": 1, "vimwiki": 1, "pandoc": 1, "infolog": 1, "mail": 1 }, "auto_start_csharp_server": 1, "auto_stop_csharp_server": 1, "use_ultisnips_completer": 1, "csharp_server_port": 0, "hmac_secret": "", "server_keep_logfiles": 0, "gocode_binary_path": "", "godef_binary_path": "", "rust_src_path": "", "racerd_binary_path": "", "python_binary_path": "" } ycmd-0+20161219+git486b809.orig/ycmd/server_state.py0000644000175000017500000001166013026170313020177 0ustar onuronur# Copyright (C) 2013 Google Inc. # # This file is part of ycmd. # # ycmd 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. # # ycmd 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 ycmd. If not, see . from __future__ import unicode_literals from __future__ import print_function from __future__ import division from __future__ import absolute_import from future import standard_library standard_library.install_aliases() from builtins import * # noqa import os import threading import logging from future.utils import itervalues from ycmd.utils import ForceSemanticCompletion, LoadPythonSource from ycmd.completers.general.general_completer_store import ( GeneralCompleterStore ) from ycmd.completers.completer_utils import PathToFiletypeCompleterPluginLoader _logger = logging.getLogger( __name__ ) class ServerState( object ): def __init__( self, user_options ): self._user_options = user_options self._filetype_completers = dict() self._filetype_completers_lock = threading.Lock() self._gencomp = GeneralCompleterStore( self._user_options ) @property def user_options( self ): return self._user_options def Shutdown( self ): with self._filetype_completers_lock: for completer in self._filetype_completers.values(): if completer: completer.Shutdown() self._gencomp.Shutdown() def _GetFiletypeCompleterForFiletype( self, filetype ): with self._filetype_completers_lock: try: return self._filetype_completers[ filetype ] except KeyError: pass module_path = PathToFiletypeCompleterPluginLoader( filetype ) completer = None supported_filetypes = set( [ filetype ] ) if os.path.exists( module_path ): module = LoadPythonSource( filetype, module_path ) completer = module.GetCompleter( self._user_options ) if completer: supported_filetypes.update( completer.SupportedFiletypes() ) for supported_filetype in supported_filetypes: self._filetype_completers[ supported_filetype ] = completer return completer def GetFiletypeCompleter( self, current_filetypes ): completers = [ self._GetFiletypeCompleterForFiletype( filetype ) for filetype in current_filetypes ] for completer in completers: if completer: return completer raise ValueError( 'No semantic completer exists for filetypes: {0}'.format( current_filetypes ) ) def GetLoadedFiletypeCompleters( self ): with self._filetype_completers_lock: return set( [ completer for completer in itervalues( self._filetype_completers ) if completer ] ) def FiletypeCompletionAvailable( self, filetypes ): try: self.GetFiletypeCompleter( filetypes ) return True except Exception as e: _logger.exception( e ) return False def FiletypeCompletionUsable( self, filetypes ): return ( self.CurrentFiletypeCompletionEnabled( filetypes ) and self.FiletypeCompletionAvailable( filetypes ) ) def ShouldUseFiletypeCompleter( self, request_data ): """ Determines whether or not the semantic completer should be called, and returns an indication of the reason why. Specifically, returns a tuple: ( should_use_completer_now, was_semantic_completion_forced ), where: - should_use_completer_now: if True, the semantic engine should be used - was_semantic_completion_forced: if True, the user requested "forced" semantic completion was_semantic_completion_forced is always False if should_use_completer_now is False """ filetypes = request_data[ 'filetypes' ] if self.FiletypeCompletionUsable( filetypes ): if ForceSemanticCompletion( request_data ): # use semantic, and it was forced return ( True, True ) else: # was not forced. check the conditions for triggering return ( self.GetFiletypeCompleter( filetypes ).ShouldUseNow( request_data ), False ) # don't use semantic, ignore whether or not the user requested forced # completion return ( False, False ) def GetGeneralCompleter( self ): return self._gencomp def CurrentFiletypeCompletionEnabled( self, current_filetypes ): filetype_to_disable = self._user_options[ 'filetype_specific_completion_to_disable' ] if '*' in filetype_to_disable: return False else: return not all([ x in filetype_to_disable for x in current_filetypes ]) ycmd-0+20161219+git486b809.orig/vagrant_bootstrap.sh0000644000175000017500000001124313026170313020253 0ustar onuronur#!/usr/bin/env bash # # Don't forget, this file needs to be idempotent, i.e. running it multiple times # in a row leaves the system in the same state as if it were run only once. ####################### # ENV VAR SETUP ####################### # Makes apt-get STFU about pointless nonsense export DEBIAN_FRONTEND=noninteractive # For pyenv Python building export CFLAGS='-O2' # In order to work with ycmd, python *must* be built as a shared library. This # is set via the PYTHON_CONFIGURE_OPTS option. export PYTHON_CONFIGURE_OPTS='--enable-shared' ####################### # APT-GET INSTALL ####################### apt-get update apt-get -yqq dist-upgrade apt-get install -yqq python-dev apt-get install -yqq python-setuptools apt-get install -yqq python3 apt-get install -yqq python3-dev apt-get install -yqq python3-setuptools apt-get install -yqq build-essential apt-get install -yqq ninja-build apt-get install -yqq cmake apt-get install -yqq git apt-get install -yqq golang apt-get install -yqq mono-complete apt-get install -yqq astyle # These two are for pyopenssl apt-get install -yqq libffi-dev apt-get install -yqq libssl-dev # These are Python build deps (though it depends on Python version). We need # them because pyenv builds Python. apt-get install -yqq libssl-dev apt-get install -yqq zlib1g-dev apt-get install -yqq libbz2-dev apt-get install -yqq libreadline-dev apt-get install -yqq libsqlite3-dev apt-get install -yqq wget apt-get install -yqq curl apt-get install -yqq llvm apt-get install -yqq libncurses5-dev apt-get install -yqq libncursesw5-dev ####################### # PIP SETUP ####################### curl -sOL https://bootstrap.pypa.io/get-pip.py python get-pip.py ####################### # PYTHON LIBS ####################### # We intentionally do NOT install the deps from test_requirements.txt into the # system Python because that should help prevent accidental use of system Python # during development. All dev work should happen with pyenv. # This is needed to prevent InsecurePlatformWarning from showing up AFTER this # stuff is installed. pip install --upgrade pyopenssl ndg-httpsclient pyasn1 ####################### # NODEJS SETUP & LIBS ####################### apt-get install -yqq nodejs # Needed so that the node binary is named 'node' and not 'nodejs'; necessary # because of scripts that call 'node'. apt-get install -yqq nodejs-legacy apt-get install -yqq npm npm install -g typescript ####################### # RUST SETUP ####################### # multirust installation echo "Installing multirust" curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh \ | sh -s -- --yes >/dev/null 2>&1 # Needs to run as vagrant user otherwise it only sets up a Rust toolchain for # root, which doesn't do us any good. su - vagrant -c "multirust default stable 2>/dev/null" ####################### # PYENV SETUP ####################### git clone https://github.com/yyuu/pyenv.git /home/vagrant/.pyenv # Sourcing .profile to determine has provisioning already been done. If it has, # then we don't re-add setup code. source /home/vagrant/.profile if [ -z "$PROVISIONING_DONE" ]; then echo 'export PROVISIONING_DONE=true' >> /home/vagrant/.profile echo 'export PYENV_ROOT="/home/vagrant/.pyenv"' >> /home/vagrant/.profile echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> /home/vagrant/.profile echo 'eval "$(pyenv init -)"' >> /home/vagrant/.profile echo 'cd /vagrant' >> /home/vagrant/.profile # In case we just created the file. chown vagrant:vagrant /home/vagrant/.profile # We need the newly-added commands from .profile in the current shell to run # pyenv. source /home/vagrant/.profile pyenv install 2.6.6 pyenv install 3.3.0 pyenv rehash # Avoid relying on the system python at all. Devs using some other # python is perfectly fine, but let's use a supported version by default. echo 'pyenv global 2.6.6' >> /home/vagrant/.profile fi # This installs libs in the pyenv Pythons in case the developer wants to run # ycmd manually. NOTE: We use the latest lib versions here, not the versions # that are used as submodules! pyenv global 2.6.6 pip install -r /vagrant/test_requirements.txt pip install -r /vagrant/examples/requirements.txt pip install requests pip install argparse pip install bottle pip install waitress pip install ipdb pip install ipdbplugin pip install httpie pip install coveralls pyenv global 3.3.0 pip install -r /vagrant/test_requirements.txt pip install -r /vagrant/examples/requirements.txt pip install requests pip install argparse pip install bottle pip install waitress pip install ipdb pip install ipdbplugin pip install httpie pip install coveralls pyenv global system chown -R vagrant:vagrant /home/vagrant/.pyenv ycmd-0+20161219+git486b809.orig/style_format.sh0000755000175000017500000000077513026170313017237 0ustar onuronur#!/bin/bash astyle \ --style=attach \ --indent=spaces=2 \ --indent-switches \ --indent-col1-comments \ --indent-preprocessor \ --max-instatement-indent=80 \ --break-blocks \ --pad-oper \ --pad-paren-in \ --pad-header \ --keep-one-line-blocks \ --convert-tabs \ --align-pointer=name \ --align-reference=name \ --suffix=none \ --lineend=linux \ --recursive \ --exclude=gmock \ --exclude=testdata \ --exclude=ycm_core.cpp \ --exclude=CustomAssert.h \ --exclude=CustomAssert.cpp \ "cpp/ycm/*.cpp" \ "cpp/ycm/*.h" ycmd-0+20161219+git486b809.orig/test_requirements.txt0000644000175000017500000000075013026170313020504 0ustar onuronur# Flake8 3.x dropped support of Python 2.6 and 3.3 flake8 < 3.0.0; python_version == '2.6' or python_version == '3.3' flake8 >= 3.0.0; python_version == '2.7' or python_version > '3.3' mock >= 1.3.0 nose >= 1.3.7 PyHamcrest >= 1.8.5 WebTest >= 2.0.20 ordereddict >= 1.1 nose-exclude >= 0.4.1 unittest2 >= 1.1.0 psutil >= 3.3.0 # This needs to be kept in sync with submodule checkout in third_party future == 0.15.2 coverage >= 4.2