ycmd-0+20160327+gitc3e6904.orig/0000700000175000017500000000000012677434542014237 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/run_tests.py0000755000175000017500000001601512677434535016661 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( '--arch', type = int, choices = [ 32, 64 ], help = 'Force architecture to 32 or 64 bits on ' 'Windows (default: python interpreter architecture).' ) 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.' ) 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.arch: build_cmd.extend( [ '--arch', str( args.arch ) ] ) 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-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() 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+20160327+gitc3e6904.orig/DEV_SETUP.md0000644000175000017500000000213612677434535016175 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. [vagrant]: https://www.vagrantup.com/ ycmd-0+20160327+gitc3e6904.orig/tox.ini0000644000175000017500000000027412677434535015571 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+20160327+gitc3e6904.orig/Vagrantfile0000644000175000017500000000125112677434535016437 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 end ycmd-0+20160327+gitc3e6904.orig/CORE_VERSION0000644000175000017500000000000312677434535016124 0ustar onuronur20 ycmd-0+20160327+gitc3e6904.orig/.coveragerc0000644000175000017500000000006012677434535016370 0ustar onuronur[report] omit = */tests/* */__init__.py ycmd-0+20160327+gitc3e6904.orig/COPYING.txt0000644000175000017500000010451312677434535016130 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+20160327+gitc3e6904.orig/third_party/0000755000175000017500000000000012677434535016604 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/tern_runtime/0000755000175000017500000000000012677434535021317 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/tern_runtime/package.json0000644000175000017500000000020312677434535023600 0ustar onuronur{ "description": "ycmd tern runtime area with required tern version and plugins", "dependencies": { "tern": "0.17.0" } } ycmd-0+20160327+gitc3e6904.orig/third_party/waitress/0000755000175000017500000000000012677434535020445 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/OmniSharpServer/0000755000175000017500000000000012677434535021673 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/argparse/0000755000175000017500000000000012677434535020410 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/bottle/0000755000175000017500000000000012677434535020075 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/0000755000175000017500000000000012677434542020155 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/tox.ini0000644000175000017500000000042612677434540021470 0ustar onuronur[tox] envlist = py26, py27, py33 skipsdist = True [testenv] deps = -r{toxinidir}/test_requirements.txt commands = nosetests -v flake8 --select=F,C9 --max-complexity=10 --exclude=fixtures jedihttp tests [testenv:py26] deps = {[testenv]deps} unittest2 ordereddict ycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/LICENSE0000644000175000017500000002613612677434540021170 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/0000755000175000017500000000000012677434540021766 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/0000755000175000017500000000000012677434540023130 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/end_to_end_test.py0000644000175000017500000001234712677434540026646 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/__init__.py0000644000175000017500000000000012677434540025227 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/utils.py0000644000175000017500000001114112677434540024640 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( filename ): dir_of_current_script = os.path.dirname( os.path.abspath( __file__ ) ) return os.path.join( dir_of_current_script, 'fixtures', filename ) # 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/fixtures/0000755000175000017500000000000012677434540025001 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/fixtures/basic.py0000644000175000017500000000012512677434540026432 0ustar onuronurclass Foo(object): def __init__(self): self.a = 1 self.b = 2 f = Foo() f. ycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/fixtures/usages.py0000644000175000017500000000016312677434540026642 0ustar onuronurdef f(): """ Module method docs Are dedented, like you might expect""" return 1 a = f() b = f() c = f() ycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/fixtures/goto.py0000644000175000017500000000044512677434540026326 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/fixtures/py3.py0000644000175000017500000000061112677434540026064 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/tests/handlers_test.py0000644000175000017500000001714012677434540026344 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( { 'description': 'def f', 'line': 1, 'in_builtin_module': False, 'column': 4, 'is_keyword': False, 'module_path': filepath, 'docstring': 'f()\n\nModule method docs\nAre ' 'dedented, like you might expect' }, { 'description': 'class C', 'line': 6, 'in_builtin_module': False, 'column': 6, 'is_keyword': False, 'module_path': filepath, 'docstring': 'Class Documentation' } ) ) 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( { 'in_builtin_module': False, 'is_keyword': False, 'module_path': filepath, 'column': 0, 'line': 18, 'description': 'inception = _list[ 2 ]', 'docstring': '' } ) ) 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( { 'description': 'def f', 'in_builtin_module': False, 'is_keyword': False, 'module_path': filepath, 'column': 4, 'line': 1, 'docstring': 'f()\n\nModule method docs\nAre dedented, like you might expect' }, { 'description': 'a = f()', 'in_builtin_module': False, 'is_keyword': False, 'module_path': filepath, 'column': 4, 'line': 6, 'docstring': '' }, { 'description': 'b = f()', 'in_builtin_module': False, 'is_keyword': False, 'module_path': filepath, 'column': 4, 'line': 7, 'docstring': '' }, { 'description': 'c = f()', 'in_builtin_module': False, 'is_keyword': False, 'module_path': filepath, 'column': 4, 'line': 8, 'docstring': '' } ) ) @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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/__init__.py0000644000175000017500000000000012677434540024065 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/handlers.py0000644000175000017500000000755612677434540024155 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 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__ ) @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' ) script = _GetJediScript( request.json ) return _JsonResponse( { 'completions': [ { 'name': completion.name, 'description': completion.description, 'docstring': completion.docstring(), 'module_path': completion.module_path, 'line': completion.line, 'column': completion.column } for completion in script.completions() ] } ) @app.post( '/gotodefinition' ) def gotodefinition(): logger.debug( 'received /gotodefinition request' ) script = _GetJediScript( request.json ) return _JsonResponse( _FormatDefinitions( script.goto_definitions() ) ) @app.post( '/gotoassignment' ) def gotoassignments(): logger.debug( 'received /gotoassignment request' ) script = _GetJediScript( request.json ) return _JsonResponse( _FormatDefinitions( script.goto_assignments() ) ) @app.post( '/usages' ) def usages(): logger.debug( 'received /usages request' ) script = _GetJediScript( request.json ) return _JsonResponse( _FormatDefinitions( script.usages() ) ) def _FormatDefinitions( definitions ): return { 'definitions': [ { 'module_path': definition.module_path, 'line': definition.line, 'column': definition.column, 'in_builtin_module': definition.in_builtin_module(), 'is_keyword': definition.is_keyword, 'description': definition.description, 'docstring': definition.docstring() } 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/compatibility.py0000644000175000017500000000407412677434540025216 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/utils.py0000644000175000017500000000173112677434540023502 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/hmac_plugin.py0000644000175000017500000000457012677434540024634 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp/hmaclib.py0000644000175000017500000000613712677434540023746 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+20160327+gitc3e6904.orig/third_party/JediHTTP/.travis.yml0000644000175000017500000000212212677434540022261 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 - 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 before_install: git submodule update --init --recursive install: ./travis/install.sh script: ./travis/run.sh notifications: email: false ycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/appveyor.yml0000644000175000017500000000360012677434540022542 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" 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+20160327+gitc3e6904.orig/third_party/JediHTTP/README.md0000644000175000017500000001237412677434540021441 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. #### `--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" } ``` 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+20160327+gitc3e6904.orig/third_party/JediHTTP/travis/0000755000175000017500000000000012677434540021463 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/travis/run.sh0000755000175000017500000000121712677434540022627 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+20160327+gitc3e6904.orig/third_party/JediHTTP/travis/install.sh0000755000175000017500000000263112677434540023472 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+20160327+gitc3e6904.orig/third_party/JediHTTP/jedihttp.py0000644000175000017500000000406512677434540022345 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 sys import os import json 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( '--hmac-file-secret', type = str, help = 'file containing hmac secret' ) return parser.parse_args() 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() 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+20160327+gitc3e6904.orig/third_party/JediHTTP/vendor/0000755000175000017500000000000012677434540021450 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/vendor/waitress/0000755000175000017500000000000012677434540023311 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/vendor/argparse/0000755000175000017500000000000012677434540023254 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/vendor/bottle/0000755000175000017500000000000012677434540022741 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/vendor/jedi/0000755000175000017500000000000012677434540022363 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/test_requirements.txt0000644000175000017500000000011112677434540024467 0ustar onuronurflake8>=2.0 nose>=1.3.0 WebTest>=2.0.0 PyHamcrest>=1.8.0 requests>=2.8.1 ycmd-0+20160327+gitc3e6904.orig/third_party/JediHTTP/NOTICE0000644000175000017500000000156112677434540021062 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+20160327+gitc3e6904.orig/third_party/python-future/0000755000175000017500000000000012677434535021435 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/godef/0000755000175000017500000000000012677434535017670 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/gocode/0000755000175000017500000000000012677434535020044 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/racerd/0000755000175000017500000000000012677434535020044 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/requests/0000755000175000017500000000000012677434535020457 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/0000755000175000017500000000000012677434542020751 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/README.txt0000644000175000017500000000207212677434537022454 0ustar onuronur========== frozendict ========== ``frozendict`` is an immutable wrapper around dictionaries that implements the complete mapping interface. It can be used as a drop-in replacement for dictionaries where immutability is desired. Of course, this is ``python``, and you can still poke around the object's internals if you want. The ``frozendict`` constructor mimics ``dict``, and all of the expected interfaces (``iter``, ``len``, ``repr``, ``hash``, ``getitem``) are provided. Note that a ``frozendict`` does not guarantee the immutability of its values, so the utility of ``hash`` method is restricted by usage. The only difference is that the ``copy()`` method of ``frozendict`` takes variable keyword arguments, which will be present as key/value pairs in the new, immutable copy. Example shell usage:: from frozendict import frozendict fd = frozendict({ 'hello': 'World' }) print fd # print fd['hello'] # 'World' print fd.copy(another='key/value') # ycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/setup.py0000644000175000017500000000062012677434537022465 0ustar onuronurfrom distutils.core import setup setup( name = 'frozendict', version = '0.3', url = 'https://github.com/slezica/python-frozendict', author = 'Santiago Lezica', author_email = 'slezica89@gmail.com', packages = ['frozendict'], license = 'MIT License', description = 'An immutable dictionary', long_description = open('README.txt').read() ) ycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/LICENSE.txt0000644000175000017500000000204312677434537022577 0ustar onuronurCopyright (c) 2012 Santiago Lezica 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. ycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/MANIFEST.in0000644000175000017500000000001612677434537022510 0ustar onuronurinclude *.txt ycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/README.md0000644000175000017500000000202412677434537022232 0ustar onuronurfrozendict ========== `frozendict` is an immutable wrapper around dictionaries that implements the complete mapping interface. It can be used as a drop-in replacement for dictionaries where immutability is desired. Of course, this is `python`, and you can still poke around the object's internals if you want. The `frozendict` constructor mimics `dict`, and all of the expected interfaces (`iter`, `len`, `repr`, `hash`, `getitem`) are provided. Note that a `frozendict` does not guarantee the immutability of its values, so the utility of `hash` method is restricted by usage. The only difference is that the `copy()` method of `frozendict` takes variable keyword arguments, which will be present as key/value pairs in the new, immutable copy. Example shell usage: from frozendict import frozendict fd = frozendict({ 'hello': 'World' }) print fd # print fd['hello'] # 'World' print fd.copy(another='key/value') # ycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/frozendict/0000755000175000017500000000000012677434537023124 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/third_party/frozendict/frozendict/__init__.py0000644000175000017500000000126412677434537025240 0ustar onuronurimport collections, operator class frozendict(collections.Mapping): def __init__(self, *args, **kwargs): self.__dict = dict(*args, **kwargs) self.__hash = None def __getitem__(self, key): return self.__dict[key] def copy(self, **add_or_replace): return frozendict(self, **add_or_replace) def __iter__(self): return iter(self.__dict) def __len__(self): return len(self.__dict) def __repr__(self): return '' % repr(self.__dict) def __hash__(self): if self.__hash is None: self.__hash = reduce(operator.xor, map(hash, self.iteritems()), 0) return self.__hash ycmd-0+20160327+gitc3e6904.orig/ci/0000755000175000017500000000000012677434535014646 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ci/appveyor/0000755000175000017500000000000012677434535016513 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ci/appveyor/appveyor_install.bat0000644000175000017500000000366712677434535022612 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 :: Manually setting PYTHONHOME for python 2.7.11 fix the following error when :: running core tests: "ImportError: No module named site" :: TODO: check if this is still needed when python 2.7.12 is released. if %python% == 27 ( set PYTHONHOME=%python_path% ) :: When using Python 3 on AppVeyor, CMake will always pick the 64 bits :: libraries. We specifically tell CMake the right path to the libraries :: according to the architecture. if %python% == 35 ( set EXTRA_CMAKE_ARGS="-DPYTHON_LIBRARY=%python_path%\libs\python%python%.lib" ) 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% :: :: 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.6.0-x86_64-pc-windows-msvc.exe rust-1.6.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+20160327+gitc3e6904.orig/ci/README.md0000644000175000017500000000026712677434535016132 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+20160327+gitc3e6904.orig/ci/travis/0000755000175000017500000000000012677434535016156 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ci/travis/travis_install.linux.sh0000644000175000017500000000105212677434535022704 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/c++ c++ /usr/bin/clang++-3.7 100 mkdir ${HOME}/bin ln -s /usr/bin/clang++-3.7 ${HOME}/bin/clang++ ln -s /usr/bin/clang-3.7 ${HOME}/bin/clang ln -s /usr/bin/clang++-3.7 ${HOME}/bin/c++ ln -s /usr/bin/clang-3.7 ${HOME}/bin/cc # These shouldn't be necessary, but just in case. ln -s /usr/bin/clang++-3.7 ${HOME}/bin/g++ ln -s /usr/bin/clang-3.7 ${HOME}/bin/gcc export PATH=${HOME}/bin:${PATH} ycmd-0+20160327+gitc3e6904.orig/ci/travis/travis_install.sh0000644000175000017500000000414012677434535021547 0ustar onuronur#!/bin/bash set -ev #################### # 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 ############# # DON'T exit if error set +e git clone https://github.com/yyuu/pyenv.git ~/.pyenv git fetch --tags git checkout v20160202 # Exit if error set -e export PYENV_ROOT="$HOME/.pyenv" 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 PYENV_VERSION="2.7.6" 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 npm install -g typescript # We run coverage tests only on a single build, where COVERAGE=true if [ x"${COVERAGE}" = x"true" ]; then pip install coveralls fi ############ # 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 # The build infrastructure prints a lot of spam after this script runs, so make # sure to disable printing, and failing on non-zero exit code after this script # finishes set +ev ycmd-0+20160327+gitc3e6904.orig/ci/travis/travis_install.osx.sh0000644000175000017500000000174212677434535022364 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+20160327+gitc3e6904.orig/appveyor.yml0000644000175000017500000000164612677434535016652 0ustar onuronurversion: '{build}' branches: # Since Homu does not support AppVeyor, we ignore the branch it uses. except: - auto environment: USE_CLANG_COMPLETER: 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% # 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+20160327+gitc3e6904.orig/check_core_version.py0000755000175000017500000000235612677434535020470 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 . import sys import os import ycm_core VERSION_FILENAME = 'CORE_VERSION' def DirectoryOfThisScript(): return os.path.dirname( os.path.abspath( __file__ ) ) def ExpectedCoreVersion(): return int( open( os.path.join( DirectoryOfThisScript(), VERSION_FILENAME ) ).read() ) def CompatibleWithCurrentCoreVersion(): try: current_core_version = ycm_core.YcmCoreVersion() except AttributeError: return False return ExpectedCoreVersion() == current_core_version if not CompatibleWithCurrentCoreVersion(): sys.exit( 2 ) sys.exit( 0 ) ycmd-0+20160327+gitc3e6904.orig/CODE_OF_CONDUCT.md0000644000175000017500000000452112677434535017054 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+20160327+gitc3e6904.orig/CONTRIBUTING.md0000644000175000017500000001777112677434535016521 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+20160327+gitc3e6904.orig/cpp/0000755000175000017500000000000012677434542015033 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/CMakeLists.txt0000644000175000017500000002012112677434535017571 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 ( DEFINED ENV{TRAVIS} ) # We lie to Travis CI about the min CMake version we need. For what we use # Travis for, the old version of CMake that it has is good enough. cmake_minimum_required( VERSION 2.8 ) else() 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() 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+20160327+gitc3e6904.orig/cpp/ycm/0000755000175000017500000000000012677434535015625 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/ycm/LetterNode.h0000644000175000017500000000327112677434535020046 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 "LetterNodeListMap.h" #include #include #include #include #include namespace YouCompleteMe { class LetterNode : boost::noncopyable { public: LetterNode( char letter, int index ); // this is for root nodes explicit LetterNode( const std::string &text ); inline bool LetterIsUppercase() const { return is_uppercase_; } inline const std::list< LetterNode * > *NodeListForLetter( char letter ) { return letters_.ListPointerAt( letter ); } inline void PrependNodeForLetter( char letter, LetterNode *node ) { letters_[ letter ].push_front( node ); } inline int Index() const { return index_; } private: LetterNodeListMap letters_; std::vector< boost::shared_ptr< LetterNode > > letternode_per_text_index_; bool is_uppercase_; int index_; }; } // namespace YouCompleteMe #endif /* end of include guard: LETTERNODE_H_EIZ6JVWC */ ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/CMakeLists.txt0000644000175000017500000004350312677434535020372 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.8.0" ) if ( APPLE ) set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-x86_64-apple-darwin" ) set( CLANG_SHA256 "e5a961e04b0e1738bbb5b824886a34932dc13b0af699d1fe16519d814d7b776f" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) elseif ( WIN32 ) if( 64_BIT_PLATFORM ) set( CLANG_DIRNAME "LLVM-${CLANG_VERSION}-win64" ) set( CLANG_SHA256 "f9c3147157db32beab025314db9b82c600e182d82994880c1d844c70e29d76ef" ) else() set( CLANG_DIRNAME "LLVM-${CLANG_VERSION}-win32" ) set( CLANG_SHA256 "ebdb056ebc6efd57c0643733a099920d1d5760a4d570580243e6c63f4b52920f" ) endif() set( CLANG_FILENAME "${CLANG_DIRNAME}.exe" ) else() if ( 64_BIT_PLATFORM ) # We MUST support the latest Ubuntu LTS release! # At the time of writing, that's 14.04. Switch to next LTS ~6 months after # it comes out. set( CLANG_DIRNAME "clang+llvm-${CLANG_VERSION}-x86_64-linux-gnu-ubuntu-14.04" ) set( CLANG_SHA256 "3120c3055ea78bbbb6848510a2af70c68538b990cb0545bac8dad01df8ff69d7" ) set( CLANG_FILENAME "${CLANG_DIRNAME}.tar.xz" ) else() # Clang 3.3 is the last version with pre-built x86 binaries upstream. # That's too old now. message( FATAL_ERROR "No pre-built Clang ${CLANG_VERSION} binaries for 32 bit linux. " "You'll have to compile Clang ${CLANG_VERSION} from source. " "See the YCM docs for details on how to use a user-compiled libclang." ) 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 ) find_package( Boost REQUIRED COMPONENTS python filesystem system regex thread ) 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" ) 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} ) 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/0000755000175000017500000000000012677434535020524 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/ClangUtils.cpp0000644000175000017500000000307512677434535023302 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/Diagnostic.h0000644000175000017500000000467312677434535022773 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; 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 std::vector< FixItChunk > fixits_; }; } // namespace YouCompleteMe #endif /* end of include guard: DIAGNOSTIC_H_BZH3BWIZ */ ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/TranslationUnitStore.cpp0000644000175000017500000001037112677434535025405 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/Documentation.h0000644000175000017500000000352712677434535023515 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/CompilationDatabase.h0000644000175000017500000000411512677434535024601 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/CompilationDatabase.cpp0000644000175000017500000000641512677434535025141 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/ClangHelpers.h0000644000175000017500000000310412677434535023242 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/ClangCompleter.cpp0000644000175000017500000001663112677434535024136 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/Location.h0000644000175000017500000000367312677434535022456 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/TranslationUnit.cpp0000644000175000017500000003557212677434535024402 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() { return CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_Incomplete | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion | CXTranslationUnit_CreatePreambleOnFirstParse | 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_ ); for ( std::vector< Diagnostic >::const_iterator it = latest_diagnostics_.begin(); it != latest_diagnostics_.end(); ++it ) { // Find all fixits for the supplied line if ( it->fixits_.size() > 0 && it->location_.line_number_ == static_cast( line ) ) { FixIt fixit; fixit.chunks = it->fixits_; fixit.location = it->location_; fixits.push_back( fixit ); } } } // 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/ClangUtils.h0000644000175000017500000000247012677434535022745 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/Documentation.cpp0000644000175000017500000000316712677434535024050 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/CompletionData.h0000644000175000017500000001000212677434535023571 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/TranslationUnitStore.h0000644000175000017500000000537312677434535025060 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/UnsavedFile.h0000644000175000017500000000267012677434535023107 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/ClangCompleter.h0000644000175000017500000000673512677434535023607 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/Range.h0000644000175000017500000000240612677434535021733 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/CompletionData.cpp0000644000175000017500000001677212677434535024150 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/TranslationUnit.h0000644000175000017500000000672212677434535024042 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/Range.cpp0000644000175000017500000000166012677434535022267 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+20160327+gitc3e6904.orig/cpp/ycm/ClangCompleter/ClangHelpers.cpp0000644000175000017500000001753312677434535023610 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 using boost::unordered_map; namespace YouCompleteMe { namespace { // NOTE: The passed in pointer should never be NULL! std::string FullDiagnosticText( CXDiagnostic cxdiagnostic ) { std::string full_text = CXStringToString( clang_formatDiagnostic( cxdiagnostic, clang_defaultDiagnosticDisplayOptions() ) ); // 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( cxdiagnostic ); if ( !diag_set ) return full_text; uint num_child_diagnostics = clang_getNumDiagnosticsInSet( diag_set ); if ( !num_child_diagnostics ) return full_text; for ( uint i = 0; i < num_child_diagnostics; ++i ) { CXDiagnostic diagnostic = clang_getDiagnosticInSet( diag_set, i ); if ( !diagnostic ) continue; full_text.append( "\n" ); full_text.append( FullDiagnosticText( diagnostic ) ); } return full_text; } 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; } } // 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() ) ); diagnostic.long_formatted_text_ = FullDiagnosticText( diagnostic_wrap.get() ); uint num_fixits = clang_getDiagnosticNumFixIts( diagnostic_wrap.get() ); // If there are any fixits supplied by libclang, cache them in the diagnostic // object. diagnostic.fixits_.reserve( num_fixits ); for ( uint fixit_idx = 0; fixit_idx < num_fixits; ++fixit_idx ) { FixItChunk chunk; CXSourceRange sourceRange; chunk.replacement_text = CXStringToString( clang_getDiagnosticFixIt( diagnostic_wrap.get(), fixit_idx, &sourceRange ) ); chunk.range = sourceRange; diagnostic.fixits_.push_back( chunk ); } return diagnostic; } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/Candidate.h0000644000175000017500000000370112677434535017653 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; 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+20160327+gitc3e6904.orig/cpp/ycm/LetterNodeListMap.h0000644000175000017500000000276612677434535021350 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 #define NUM_LETTERS 128 namespace YouCompleteMe { class LetterNode; YCM_DLL_EXPORT int IndexForChar( char letter ); YCM_DLL_EXPORT bool IsUppercase( char letter ); class LetterNodeListMap : boost::noncopyable { public: LetterNodeListMap(); YCM_DLL_EXPORT ~LetterNodeListMap(); bool HasLetter( char letter ); std::list< LetterNode * > &operator[] ( char letter ); std::list< LetterNode * > *ListPointerAt( char letter ); bool HasLetter( char letter ) const; private: boost::array< std::list< LetterNode * >*, NUM_LETTERS > letters_; }; } // namespace YouCompleteMe #endif /* end of include guard: LETTERNODELISTMAP_H_BRK2UMC1 */ ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/IdentifierDatabase.cpp0000644000175000017500000001201112677434535022033 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+20160327+gitc3e6904.orig/cpp/ycm/IdentifierDatabase.h0000644000175000017500000000631512677434535021512 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+20160327+gitc3e6904.orig/cpp/ycm/Candidate.cpp0000644000175000017500000000661112677434535020211 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 using boost::algorithm::all; using boost::algorithm::is_lower; namespace YouCompleteMe { namespace { LetterNode *FirstUppercaseNode( const std::list< LetterNode *> &list ) { LetterNode *node = NULL; foreach( LetterNode * current_node, list ) { if ( current_node->LetterIsUppercase() ) { node = current_node; break; } } return node; } } // unnamed namespace 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 ) { letter_bitset.set( IndexForChar( letter ) ); } 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 std::list< LetterNode *> *list = node->NodeListForLetter( letter ); if ( !list ) return Result( false ); if ( case_sensitive ) { // 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 = IsUppercase( letter ) ? FirstUppercaseNode( *list ) : list->front(); if ( !node ) return Result( false ); } else { node = list->front(); } index_sum += node->Index(); } return Result( true, &text_, text_is_lowercase_, index_sum, word_boundary_chars_, query ); } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/0000755000175000017500000000000012677434542016765 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/CMakeLists.txt0000644000175000017500000001071612677434535021534 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+20160327+gitc3e6904.orig/cpp/ycm/tests/ClangCompleter/0000755000175000017500000000000012677434535021666 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/ClangCompleter/TranslationUnit_test.cpp0000644000175000017500000001060012677434535026564 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+20160327+gitc3e6904.orig/cpp/ycm/tests/ClangCompleter/ClangCompleter_test.cpp0000644000175000017500000000767412677434535026346 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+20160327+gitc3e6904.orig/cpp/ycm/tests/TestUtils.cpp0000644000175000017500000000412212677434535021432 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+20160327+gitc3e6904.orig/cpp/ycm/tests/testdata/0000755000175000017500000000000012677434535020600 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/testdata/basic.tags0000644000175000017500000000116612677434535022545 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+20160327+gitc3e6904.orig/cpp/ycm/tests/testdata/goto.cpp0000644000175000017500000000025712677434535022260 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+20160327+gitc3e6904.orig/cpp/ycm/tests/testdata/SWObject.h0000644000175000017500000000020412677434535022425 0ustar onuronur@interface SWObject /** testFunc * * a detail description */ - (void)test:(int)arg1 withArg2:(int)arg2 withArg3:(int)arg3; @end ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/testdata/SWObject.m0000644000175000017500000000020412677434535022432 0ustar onuronur#import "SWObject.h" @implementation SWObject - (void)test { [self test:0 /*complete at here*/] } - /*complete at here*/ @end ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/testdata/basic.cpp0000644000175000017500000000026612677434535022371 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+20160327+gitc3e6904.orig/cpp/ycm/tests/IsUppercase_test.cpp0000644000175000017500000000224612677434535022761 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+20160327+gitc3e6904.orig/cpp/ycm/tests/IdentifierUtils_test.cpp0000644000175000017500000000367612677434535023651 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+20160327+gitc3e6904.orig/cpp/ycm/tests/IdentifierCompleter_test.cpp0000644000175000017500000002311312677434535024467 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::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( "" ), ElementsAre() ); } 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, 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+20160327+gitc3e6904.orig/cpp/ycm/tests/IndexForChar_test.cpp0000644000175000017500000000237612677434535023056 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( IndexForCharTest, Basic ) { EXPECT_EQ( static_cast( 'a' ), IndexForChar( 'a' ) ); EXPECT_EQ( static_cast( 'a' ), IndexForChar( 'A' ) ); EXPECT_EQ( static_cast( 'z' ), IndexForChar( 'z' ) ); EXPECT_EQ( static_cast( 'z' ), IndexForChar( 'Z' ) ); EXPECT_EQ( static_cast( '[' ), IndexForChar( '[' ) ); EXPECT_EQ( static_cast( ' ' ), IndexForChar( ' ' ) ); EXPECT_EQ( static_cast( '~' ), IndexForChar( '~' ) ); } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/LetterBitsetFromString_test.cpp0000644000175000017500000000220412677434535025155 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( IndexForChar( 'a' ) ); expected.set( IndexForChar( 'o' ) ); expected.set( IndexForChar( 'c' ) ); expected.set( IndexForChar( 'f' ) ); expected.set( IndexForChar( 'b' ) ); std::string text = "abcfoof"; EXPECT_EQ( expected, LetterBitsetFromString( text ) ); } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/TestUtils.h0000644000175000017500000000326012677434535021101 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+20160327+gitc3e6904.orig/cpp/ycm/tests/main.cpp0000644000175000017500000000043612677434535020422 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+20160327+gitc3e6904.orig/cpp/ycm/tests/cmake/0000755000175000017500000000000012677434535020047 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/cpp/ycm/tests/cmake/FindGMock.cmake0000644000175000017500000001077712677434535022666 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+20160327+gitc3e6904.orig/cpp/ycm/tests/Candidate_test.cpp0000644000175000017500000002556612677434535022424 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+20160327+gitc3e6904.orig/cpp/ycm/tests/CandidateRepository_test.cpp0000644000175000017500000000464112677434535024513 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+20160327+gitc3e6904.orig/cpp/ycm/IdentifierUtils.h0000644000175000017500000000217112677434535021102 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+20160327+gitc3e6904.orig/cpp/ycm/versioning.cpp0000644000175000017500000000147512677434535020523 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+20160327+gitc3e6904.orig/cpp/ycm/DLLDefines.h0000644000175000017500000000212412677434535017706 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+20160327+gitc3e6904.orig/cpp/ycm/LetterNode.cpp0000644000175000017500000000330112677434535020373 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 ) : is_uppercase_( IsUppercase( letter ) ), index_( index ) { } // TODO: this class needs tests LetterNode::LetterNode( const std::string &text ) : is_uppercase_( false ), index_( -1 ) { letternode_per_text_index_.resize( text.size() ); for ( uint i = 0; i < text.size(); ++i ) { char letter = text[ i ]; LetterNode *node = new LetterNode( letter, i ); letters_[ letter ].push_back( node ); letternode_per_text_index_[ i ] = boost::shared_ptr< LetterNode >( node ); } for ( int i = static_cast< int >( letternode_per_text_index_.size() ) - 1; i >= 0; --i ) { LetterNode *node_to_add = letternode_per_text_index_[ i ].get(); for ( int j = i - 1; j >= 0; --j ) { letternode_per_text_index_[ j ]->PrependNodeForLetter( text[ i ], node_to_add ); } } } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/ReleaseGil.h0000644000175000017500000000211312677434535020007 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+20160327+gitc3e6904.orig/cpp/ycm/PythonSupport.h0000644000175000017500000000312412677434535020654 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+20160327+gitc3e6904.orig/cpp/ycm/.ycm_extra_conf.py0000644000175000017500000001434012677434535021257 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, 'do_cache': True } ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/PythonSupport.cpp0000644000175000017500000000715612677434535021220 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; } 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+20160327+gitc3e6904.orig/cpp/ycm/LetterNodeListMap.cpp0000644000175000017500000000401512677434535021670 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'; } int IndexForChar( char letter ) { if ( IsUppercase( letter ) ) return letter + ( 'a' - 'A' ); return letter; } LetterNodeListMap::LetterNodeListMap() { std::fill( letters_.begin(), letters_.end(), static_cast< std::list< LetterNode * >* >( NULL ) ); } LetterNodeListMap::~LetterNodeListMap() { for ( uint i = 0; i < letters_.size(); ++i ) { delete letters_[ i ]; } } bool LetterNodeListMap::HasLetter( char letter ) { int letter_index = IndexForChar( letter ); std::list< LetterNode * > *list = letters_[ letter_index ]; return list; } std::list< LetterNode * > &LetterNodeListMap::operator[] ( char letter ) { int letter_index = IndexForChar( letter ); std::list< LetterNode * > *list = letters_[ letter_index ]; if ( list ) return *list; letters_[ letter_index ] = new std::list< LetterNode * >(); return *letters_[ letter_index ]; } std::list< LetterNode * > *LetterNodeListMap::ListPointerAt( char letter ) { return letters_[ IndexForChar( letter ) ]; } bool LetterNodeListMap::HasLetter( char letter ) const { return letters_[ IndexForChar( letter ) ] != NULL; } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/Utils.h0000644000175000017500000000466212677434535017106 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+20160327+gitc3e6904.orig/cpp/ycm/exceptions.h0000644000175000017500000000256412677434535020166 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+20160327+gitc3e6904.orig/cpp/ycm/CustomAssert.cpp0000644000175000017500000000600212677434535020763 0ustar onuronur/* * Copyright (c) 2008, Power of Two Games LLC * 2013, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Power of Two Games LLC nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY POWER OF TWO GAMES LLC ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL POWER OF TWO GAMES LLC BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "CustomAssert.h" #include #include namespace assert_ns { namespace { Assert::FailBehavior DefaultHandler(const char* condition, const char* msg, const char* file, const int line) { std::printf("%s(%d): Assert Failure: ", file, line); if (condition != NULL) std::printf("'%s' ", condition); if (msg != NULL) std::printf("%s", msg); std::printf("\n"); return Assert::Halt; } Assert::Handler& GetAssertHandlerInstance() { static Assert::Handler s_handler = &DefaultHandler; return s_handler; } } Assert::Handler Assert::GetHandler() { return GetAssertHandlerInstance(); } void Assert::SetHandler(Assert::Handler newHandler) { GetAssertHandlerInstance() = newHandler; } Assert::FailBehavior Assert::ReportFailure(const char* condition, const char* file, const int line, const char* msg, ...) { const char* message = NULL; if (msg != NULL) { char messageBuffer[1024]; { va_list args; va_start(args, msg); #if defined(_MSC_VER) vsnprintf_s(messageBuffer, 1024, 1024, msg, args); #else vsnprintf(messageBuffer, 1024, msg, args); #endif va_end(args); } message = messageBuffer; } return GetAssertHandlerInstance()(condition, message, file, line); } } ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/CandidateRepository.h0000644000175000017500000000444412677434535021760 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+20160327+gitc3e6904.orig/cpp/ycm/Utils.cpp0000644000175000017500000000316512677434535017436 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+20160327+gitc3e6904.orig/cpp/ycm/CustomAssert.h0000644000175000017500000000722612677434535020441 0ustar onuronur/* * Copyright (c) 2008, Power of Two Games LLC * 2013, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Power of Two Games LLC nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY POWER OF TWO GAMES LLC ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL POWER OF TWO GAMES LLC BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CUSTOM_ASSERT_H #define CUSTOM_ASSERT_H namespace assert_ns { namespace Assert { enum FailBehavior { Halt, Continue, }; typedef FailBehavior (*Handler)(const char* condition, const char* msg, const char* file, int line); Handler GetHandler(); void SetHandler(Handler newHandler); FailBehavior ReportFailure(const char* condition, const char* file, int line, const char* msg, ...); }} #if defined(_MSC_VER) # define X_HALT() __debugbreak() #elif defined(__GNUC__) || defined(__clang__) # define X_HALT() __builtin_trap() #else # define X_HALT() exit(__LINE__) #endif #define X_UNUSED(x) do { (void)sizeof(x); } while(0) #ifndef NDEBUG #define X_ASSERT(cond) \ do \ { \ if (!(cond)) \ { \ if (assert_ns::Assert::ReportFailure(#cond, __FILE__, __LINE__, 0) == \ assert_ns::Assert::Halt) \ X_HALT(); \ } \ } while(0) #define X_ASSERT_MSG(cond, msg, ...) \ do \ { \ if (!(cond)) \ { \ if (assert_ns::Assert::ReportFailure(#cond, __FILE__, __LINE__, (msg), __VA_ARGS__) == \ assert_ns::Assert::Halt) \ X_HALT(); \ } \ } while(0) #define X_ASSERT_FAIL(msg, ...) \ do \ { \ if (assert_ns::Assert::ReportFailure(0, __FILE__, __LINE__, (msg), __VA_ARGS__) == \ assert_ns::Assert::Halt) \ X_HALT(); \ } while(0) #define X_VERIFY(cond) X_ASSERT(cond) #define X_VERIFY_MSG(cond, msg, ...) X_ASSERT_MSG(cond, msg, ##__VA_ARGS__) #else #define X_ASSERT(condition) \ do { X_UNUSED(condition); } while(0) #define X_ASSERT_MSG(condition, msg, ...) \ do { X_UNUSED(condition); X_UNUSED(msg); } while(0) #define X_ASSERT_FAIL(msg, ...) \ do { X_UNUSED(msg); } while(0) #define X_VERIFY(cond) (void)(cond) #define X_VERIFY_MSG(cond, msg, ...) \ do { (void)(cond); X_UNUSED(msg); } while(0) #endif #define X_STATIC_ASSERT(x) \ typedef char StaticAssert[(x) ? 1 : -1]; #endif // CUSTOM_ASSERT_H ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/IdentifierUtils.cpp0000644000175000017500000001252712677434535021443 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" ) ( "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+20160327+gitc3e6904.orig/cpp/ycm/standard.h0000644000175000017500000000155712677434535017606 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 "CustomAssert.h" // We're most definitely not going to use // it as BOOST_FOREACH. #define foreach BOOST_FOREACH typedef unsigned int uint; ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/versioning.h0000644000175000017500000000211512677434535020160 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+20160327+gitc3e6904.orig/cpp/ycm/ycm_core.cpp0000644000175000017500000002055312677434535020136 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 ); 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+20160327+gitc3e6904.orig/cpp/ycm/Result.cpp0000644000175000017500000001606312677434535017615 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+20160327+gitc3e6904.orig/cpp/ycm/CandidateRepository.cpp0000644000175000017500000000767712677434535022326 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 #include #ifdef USE_CLANG_COMPLETER # include "ClangCompleter/CompletionData.h" #endif // USE_CLANG_COMPLETER namespace YouCompleteMe { using boost::all; using boost::is_print; 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 && all( candidate_text, is_print( std::locale::classic() ) ) ) return candidate_text; return empty_; } } // namespace YouCompleteMe ycmd-0+20160327+gitc3e6904.orig/cpp/ycm/Result.h0000644000175000017500000000674712677434535017272 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+20160327+gitc3e6904.orig/cpp/ycm/IdentifierCompleter.h0000644000175000017500000000514512677434535021740 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+20160327+gitc3e6904.orig/cpp/ycm/IdentifierCompleter.cpp0000644000175000017500000000571212677434535022273 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; 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+20160327+gitc3e6904.orig/README.md0000644000175000017500000002650412677434535015541 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://coveralls.io/repos/Valloric/ycmd/badge.svg?branch=master&service=github)](https://coveralls.io/github/Valloric/ycmd?branch=master) 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. 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. 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]. 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 ycmd-0+20160327+gitc3e6904.orig/update_boost.sh0000755000175000017500000000302512677434535017302 0ustar onuronur#!/usr/bin/env bash # This script is used to update cpp/BoostParts to the latest boost version # Give it the full path to the boost_1_XX_X folder # Exit if error set -e if [ -z "$1" ]; then echo "Usage: $0 /path/to/boost_1_XX_X" exit 0 fi pushd "$1" ./bootstrap.sh ./b2 tools/bcp boost_part_dir=`mktemp -d -t boost_parts.XXXXXX` dist/bin/bcp 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_part_dir pushd "${boost_part_dir}" # DON'T exit if error set +e find libs \( -name assign -o -name mpi -o -name config -o -name lockfree \) -exec rm -rf '{}' \; find libs \( -name doc -o -name test -o -name examples -o -name build \) -exec rm -rf '{}' \; find libs -not \( -name "*.hpp" -o -name "*.cpp" -o -name "*.ipp" -o -name "*.inl" \) -type f -delete # Breaks the build for some reason and doesn't seem necessary at all. rm libs/serialization/src/shared_ptr_helper.cpp # Exit if error set -e popd popd rm -rf cpp/BoostParts/libs rm -rf cpp/BoostParts/boost cp -R "${boost_part_dir}/libs" cpp/BoostParts/libs cp -R "${boost_part_dir}/boost" cpp/BoostParts/boost rm -rf "${boost_part_dir}" ycmd-0+20160327+gitc3e6904.orig/TESTS.md0000644000175000017500000001044412677434535015502 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`: Output test coverage report 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 There's a coverage module for Python 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: ``` $ pip install coverage $ ./run_tests.py --coverage --cover-html ``` 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+20160327+gitc3e6904.orig/build.py0000755000175000017500000003666512677434535015747 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 import os import subprocess import os.path as p import sys import shlex import errno 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( 'Some folders in ' + DIR_OF_THIRD_PARTY + ' are empty; ' 'you probably forgot to run:' '\n\tgit submodule update --init --recursive\n\n' ) sys.path.insert( 1, p.abspath( p.join( DIR_OF_THIRD_PARTY, 'argparse' ) ) ) from tempfile import mkdtemp from shutil import rmtree import platform import argparse import multiprocessing 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( 'Please install CMake and retry.') # Shamelessly stolen from https://gist.github.com/edufelipe/1027906 def CheckOutput( *popen_args, **kwargs ): """Run command with arguments and return its output as a byte string. Backported from Python 2.7.""" process = subprocess.Popen( stdout=subprocess.PIPE, *popen_args, **kwargs ) output, unused_err = process.communicate() retcode = process.poll() if retcode: command = kwargs.get( 'args' ) if command is None: command = popen_args[ 0 ] error = subprocess.CalledProcessError( retcode, command ) error.output = output raise error return output def CustomPythonCmakeArgs(): # The CMake 'FindPythonLibs' Module does not work properly. # So we are forced to do its job for it. print( 'Searching for python libraries...' ) python_prefix = CheckOutput( [ 'python-config', '--prefix' ] ).strip().decode( 'utf8' ) if p.isfile( p.join( python_prefix, '/Python' ) ): python_library = p.join( python_prefix, '/Python' ) python_include = p.join( python_prefix, '/Headers' ) print( 'Using OSX-style libs from {0}'.format( python_prefix ) ) else: major_minor = CheckOutput( [ 'python', '-c', 'import sys;i=sys.version_info;print( "%d.%d" % (i[0], i[1]) )' ] ).strip().decode( 'utf8' ) which_python = 'python' + major_minor # Python 3 has an 'm' suffix, for instance libpython3.3m.a if major_minor.startswith( '3' ): which_python += 'm' lib_python = '{0}/lib/lib{1}'.format( python_prefix, which_python ).strip() print( 'Searching for python with prefix: {0} and lib {1}:'.format( python_prefix, which_python ) ) # On MacOS, ycmd does not work with statically linked python library. # It typically manifests with the following error when there is a # self-compiled python without --enable-framework (or, technically # --enable-shared): # # Fatal Python error: PyThreadState_Get: no current thread # # The most likely explanation for this is that both the ycm_core.so and the # python binary include copies of libpython.a (or whatever included # objects). When the python interpreter starts it initializes only the # globals within its copy, so when ycm_core.so's copy starts executing, it # points at its own copy which is uninitialized. # # Some platforms' dynamic linkers (ld.so) are able to resolve this when # loading shared libraries at runtime[citation needed], but OSX seemingly # cannot. # # So we do 2 things special on OS X: # - look for a .dylib first # - if we find a .a, raise an error. if p.isfile( '{0}.dylib'.format( lib_python ) ): python_library = '{0}.dylib'.format( lib_python ) elif p.isfile( '/usr/lib/lib{0}.dylib'.format( which_python ) ): # For no clear reason, python2.6 only exists in /usr/lib on OS X and # not in the python prefix location python_library = '/usr/lib/lib{0}.dylib'.format( which_python ) elif p.isfile( '{0}.a'.format( lib_python ) ): if OnMac(): sys.exit( 'ERROR: You must use a python compiled with ' '--enable-shared or --enable-framework (and thus a {0}.dylib ' 'library) on OS X'.format( lib_python ) ) python_library = '{0}.a'.format( lib_python ) # This check is for CYGWIN elif p.isfile( '{0}.dll.a'.format( lib_python ) ): python_library = '{0}.dll.a'.format( lib_python ) else: sys.exit( 'ERROR: Unable to find an appropriate python library' ) python_include = '{0}/include/{1}'.format( python_prefix, which_python ) print( 'Using PYTHON_LIBRARY={0} PYTHON_INCLUDE_DIR={1}'.format( python_library, 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 ( not args.arch and platform.architecture()[ 0 ] == '64bit' or args.arch == 64 ): 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( '--arch', type = int, choices = [ 32, 64 ], help = 'Force architecture to 32 or 64 bits on ' 'Windows (default: python interpreter architecture).' ), 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' ) args = parser.parse_args() if ( args.system_libclang and not args.clang_completer and not args.all_completers ): sys.exit( "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' ) 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 subprocess.check_call( 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 ): build_dir = mkdtemp( prefix = 'ycm_build.' ) try: full_cmake_args = [ '-G', GetGenerator( args ) ] if OnMac(): 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 ) subprocess.check_call( [ 'cmake' ] + full_cmake_args ) build_target = ( 'ycm_core' if 'YCM_TESTRUN' not in os.environ else 'ycm_core_tests' ) build_command = [ 'cmake', '--build', '.', '--target', build_target ] if OnWindows(): build_command.extend( [ '--config', 'Release' ] ) else: build_command.extend( [ '--', '-j', str( NumCores() ) ] ) subprocess.check_call( build_command ) if 'YCM_TESTRUN' in os.environ: RunYcmdTests( build_dir ) finally: os.chdir( DIR_OF_THIS_SCRIPT ) rmtree( build_dir, ignore_errors = OnTravisOrAppVeyor() ) def BuildOmniSharp(): build_command = PathToFirstExistingExecutable( [ 'msbuild', 'msbuild.exe', 'xbuild' ] ) if not build_command: sys.exit( 'msbuild or xbuild is required to build Omnisharp' ) os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'OmniSharpServer' ) ) subprocess.check_call( [ build_command, '/property:Configuration=Release' ] ) def BuildGoCode(): if not FindExecutable( 'go' ): sys.exit( 'go is required to build gocode' ) os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'gocode' ) ) subprocess.check_call( [ 'go', 'build' ] ) os.chdir( p.join( DIR_OF_THIS_SCRIPT, 'third_party', 'godef' ) ) subprocess.check_call( [ 'go', 'build' ] ) def BuildRacerd(): """ Build racerd. This requires a reasonably new version of rustc/cargo. """ if not FindExecutable( 'cargo' ): sys.exit( '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' ) subprocess.check_call( args ) def SetUpTern(): paths = {} for exe in [ 'node', 'npm' ]: path = FindExecutable( exe ) if not path: sys.exit( '"' + exe + '" is required to set up ternjs' ) 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 submodle 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. TERN_RUNTIME_DIR = os.path.join( DIR_OF_THIS_SCRIPT, 'third_party', 'tern_runtime' ) try: os.makedirs( TERN_RUNTIME_DIR ) except Exception: # os.makedirs throws if the dir already exists, it also throws if the # permissions prevent creating the directory. There's no way to know the # difference, so we just let the call to os.chdir below throw if this fails # to create the target directory. pass os.chdir( TERN_RUNTIME_DIR ) subprocess.check_call( [ paths[ 'npm' ], 'install', '--production' ] ) 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() if __name__ == '__main__': Main() ycmd-0+20160327+gitc3e6904.orig/ycmd/0000755000175000017500000000000012677434535015207 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/__main__.py0000755000175000017500000001366312677434535017315 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, CompatibleWithCurrentCoreVersion SetUpPythonPath() from future import standard_library standard_library.install_aliases() from builtins import * # noqa import sys import logging import json import argparse import waitress import signal import os import base64 from ycmd import user_options_store from ycmd import extra_conf_store from ycmd import utils from ycmd.watchdog_plugin import WatchdogPlugin from ycmd.hmac_plugin import HmacPlugin from ycmd.utils import ToBytes, ReadFile, OpenForStdHandle 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( stdout, stderr, keep_logfiles ): def SignalHandler( signum, frame ): # 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 ) sys.exit() for sig in [ signal.SIGTERM, signal.SIGINT ]: signal.signal( sig, SignalHandler ) 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( '--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() if not CompatibleWithCurrentCoreVersion(): # ycm_core.[so|dll|dylib] is too old and needs to be recompiled. sys.exit( 2 ) PossiblyDetachFromTerminal() # This can't be a top-level import because it transitively imports # ycm_core which we want to be imported ONLY after extra conf # preload has executed. from ycmd import handlers handlers.UpdateUserOptions( options ) handlers.SetHmacSecret( hmac_secret ) SetUpSignalHandler( args.stdout, args.stderr, args.keep_logfiles ) handlers.app.install( WatchdogPlugin( args.idle_suicide_seconds ) ) handlers.app.install( HmacPlugin( hmac_secret ) ) CloseStdin() waitress.serve( handlers.app, host = args.host, port = args.port, threads = 30 ) if __name__ == "__main__": Main() ycmd-0+20160327+gitc3e6904.orig/ycmd/hmac_utils.py0000644000175000017500000000632612677434535017720 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+20160327+gitc3e6904.orig/ycmd/completers/0000755000175000017500000000000012677434535017364 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/javascript/0000755000175000017500000000000012677434535021532 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/javascript/hook.py0000644000175000017500000000221612677434535023045 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+20160327+gitc3e6904.orig/ycmd/completers/javascript/__init__.py0000644000175000017500000000000012677434535023631 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/javascript/tern_completer.py0000644000175000017500000004636112677434535025140 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 http.client import logging import os import requests import threading import traceback from subprocess import PIPE from ycmd import utils, responses from ycmd.completers.completer import Completer _logger = logging.getLogger( __name__ ) PATH_TO_TERNJS_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' 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_TERNJS_BINARY ) if not installed: _logger.info( 'Not using Tern completer: not installed at ' + PATH_TO_TERNJS_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 ): for folder in utils.PathsToAllParentFolders( starting_directory ): tern_project = os.path.join( folder, '.tern-project' ) if os.path.exists( tern_project ): return tern_project # 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 return None 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.Lock() self._do_tern_project_check = False with self._server_state_mutex: self._server_stdout = None self._server_stderr = None self._Reset() self._StartServerNoLock() 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 tern_project = FindTernProjectFile( os.getcwd() ) if not tern_project: _logger.warning( 'No .tern-project file detected: ' + os.getcwd() ) raise RuntimeError( 'Warning: Unable to detect a .tern-project file ' 'in the hierarchy before ' + os.getcwd() + ' 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-project file at: ' + tern_project ) 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 ).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 { 'StartServer': ( lambda self, request_data, args: self._StartServer() ), '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 ): if self._server_handle is None: # server is not running because we haven't tried to start it. return ' * Tern server is not running' if not self._ServerIsRunning(): # The handle is set, but the process isn't running. This means either it # crashed or we failed to start it. return ( ' * Tern server is not running (crashed)' + '\n * Server stdout: ' + self._server_stdout + '\n * Server stderr: ' + self._server_stderr ) # Server is up and running. return ( ' * Tern server is running on port: ' + str( self._server_port ) + ' with PID: ' + str( self._server_handle.pid ) + '\n * Server stdout: ' + self._server_stdout + '\n * Server stderr: ' + self._server_stderr ) def Shutdown( self ): _logger.debug( "Shutting down Tern server" ) self._StopServer() def ServerIsReady( self, request_data = {} ): if not self._ServerIsRunning(): return False try: target = self._GetServerAddress() + '/ping' response = requests.get( target ) return response.status_code == http.client.OK except requests.ConnectionError: return False def _Reset( self ): """Callers must hold self._server_state_mutex""" if not self._server_keep_logfiles: if self._server_stdout: utils.RemoveIfExists( self._server_stdout ) if self._server_stderr: utils.RemoveIfExists( self._server_stderr ) self._server_handle = None self._server_port = 0 self._server_stdout = None self._server_stderr = None 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 != http.client.OK: raise RuntimeError( response.text ) return response.json() def _GetResponse( self, query, 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.""" def MakeTernLocation( request_data ): return { 'line': request_data[ 'line_num' ] - 1, 'ch': request_data[ 'start_column' ] - 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 _StartServer( self ): if not self._ServerIsRunning(): with self._server_state_mutex: self._StartServerNoLock() def _StartServerNoLock( self ): """Start the server, under the lock. Callers must hold self._server_state_mutex""" if self._ServerIsRunning(): return _logger.info( 'Starting Tern.js server...' ) self._server_port = utils.GetUnusedLocalhostPort() if _logger.isEnabledFor( logging.DEBUG ): extra_args = [ '--verbose' ] else: extra_args = [] command = [ PATH_TO_NODE, PATH_TO_TERNJS_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: logfile_format = os.path.join( utils.PathToCreatedTempDir(), u'tern_{port}_{std}.log' ) self._server_stdout = logfile_format.format( port = self._server_port, std = 'stdout' ) self._server_stderr = logfile_format.format( port = self._server_port, std = 'stderr' ) # On Windows, we need to open a pipe to stdin to prevent Tern crashing # with following error: "Implement me. Unknown stdin file type!" with utils.OpenForStdHandle( self._server_stdout ) as stdout: with utils.OpenForStdHandle( self._server_stderr ) as stderr: self._server_handle = utils.SafePopen( command, stdin_windows = PIPE, stdout = stdout, stderr = stderr ) except Exception: _logger.warning( 'Unable to start Tern.js server: ' + traceback.format_exc() ) self._Reset() if self._server_port > 0 and self._ServerIsRunning(): _logger.info( 'Tern.js Server started with pid: ' + str( self._server_handle.pid ) + ' listening on port ' + str( self._server_port ) ) _logger.info( 'Tern.js Server log files are: ' + self._server_stdout + ' and ' + self._server_stderr ) self._do_tern_project_check = True else: _logger.warning( 'Tern.js server did not start successfully' ) def _StopServer( self ): with self._server_state_mutex: self._StopServerNoLock() def _StopServerNoLock( self ): """Stop the server, under the lock. Callers must hold self._server_state_mutex""" if self._ServerIsRunning(): _logger.info( 'Stopping Tern.js server with PID ' + str( self._server_handle.pid ) + '...' ) self._server_handle.terminate() self._server_handle.wait() _logger.info( 'Tern.js server terminated.' ) self._Reset() def _ServerIsRunning( self ): return utils.ProcessIsRunning( self._server_handle ) def _GetType( self, request_data ): query = { 'type': 'type', } response = self._GetResponse( query, 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 ) 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 ) return responses.BuildGoToResponse( response[ 'file' ], response[ 'start' ][ 'line' ] + 1, response[ 'start' ][ 'ch' ] + 1 ) def _GoToReferences( self, request_data ): query = { 'type': 'refs', } response = self._GetResponse( query, request_data ) return [ responses.BuildGoToResponse( ref[ 'file' ], ref[ 'start' ][ 'line' ] + 1, ref[ 'start' ][ 'ch' ] + 1 ) 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 ) # Tern response format: # 'changes': [ # { # 'file' # 'start' { # 'line' # 'ch' # } # 'end' { # 'line' # 'ch' # } # 'text' # } # ] # ycmd response format: # # { # 'fixits': [ # 'chunks': (list) [ # { # 'replacement_text', # 'range' (Range) { # 'start_' (Location): { # 'line_number_', # 'column_number_', # 'filename_' # }, # 'end_' (Location): { # 'line_number_', # 'column_number_', # 'filename_' # } # } # } # ], # 'location' (Location) { # 'line_number_', # 'column_number_', # 'filename_' # } # # ] # } def BuildRange( filename, start, end ): return responses.Range( responses.Location( start[ 'line' ] + 1, start[ 'ch' ] + 1, filename ), responses.Location( end[ 'line' ] + 1, end[ 'ch' ] + 1, filename ) ) def BuildFixItChunk( change ): return responses.FixItChunk( change[ 'text' ], BuildRange( os.path.abspath( change[ 'file'] ), 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' ] ] ) ] ) ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/general_completer.py0000644000175000017500000000267212677434535023434 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+20160327+gitc3e6904.orig/ycmd/completers/completer.py0000644000175000017500000003063312677434535021735 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: 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 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 ServerIsReady member function to handle the /ready 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_column = request_data[ 'start_column' ] - 1 column_num = request_data[ 'column_num' ] - 1 filetype = self._CurrentFiletype( request_data[ 'filetypes' ] ) return self.prepared_triggers.MatchesForFiletype( current_line, start_column, column_num, filetype ) def QueryLengthAboveMinThreshold( self, request_data ): query_length = request_data[ 'column_num' ] - request_data[ 'start_column' ] 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 def DefinedSubcommands( self ): return sorted( self.GetSubcommandsMap().keys() ) 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 def OnBufferVisit( self, request_data ): pass def OnBufferUnload( self, request_data ): pass def OnInsertLeave( self, request_data ): pass 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 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 def ServerIsReady( self ): """Called by the /ready handler to check if the underlying completion server is started and ready to receive requests. Returns bool.""" return True class CompletionsCache( object ): 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 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 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 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+20160327+gitc3e6904.orig/ycmd/completers/__init__.py0000644000175000017500000000000012677434535021463 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/rust/0000755000175000017500000000000012677434535020361 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/rust/hook.py0000644000175000017500000000206012677434535021671 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+20160327+gitc3e6904.orig/ycmd/completers/rust/rust_completer.py0000644000175000017500000003315412677434535024010 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 http.client import json import tempfile import base64 import binascii import threading import os from os import path as p _logger = logging.getLogger( __name__ ) DIR_OF_THIS_SCRIPT = p.dirname( p.abspath( __file__ ) ) DIR_OF_THIRD_PARTY = p.join( DIR_OF_THIS_SCRIPT, '..', '..', '..', '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".' ) 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.' ) 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 = 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' ) if not self._racerd: _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 is http.client.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, '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 ] ) filename_format = p.join( utils.PathToCreatedTempDir(), 'racerd_{port}_{std}.log' ) self._server_stdout = filename_format.format( port = port, std = 'stdout' ) self._server_stderr = filename_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 ServerIsReady. """ with self._server_state_lock: return ( bool( self._racerd_host ) and ProcessIsRunning( self._racerd_phandle ) ) def ServerIsReady( 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: self._racerd_phandle.terminate() self._racerd_phandle.wait() self._racerd_phandle = None self._racerd_host = None if not self._keep_logfiles: # Remove stdout log if self._server_stdout and p.exists( self._server_stdout ): os.unlink( self._server_stdout ) self._server_stdout = None # Remove stderr log if self._server_stderr and p.exists( self._server_stderr ): os.unlink( 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() ), } 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 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 ( 'racerd\n' ' listening at: {0}\n' ' racerd path: {1}\n' ' stdout log: {2}\n' ' stderr log: {3}').format( self._racerd_host, self._racerd, self._server_stdout, self._server_stderr ) if self._server_stdout and self._server_stderr: return ( 'racerd is no longer running\n', ' racerd path: {0}\n' ' stdout log: {1}\n' ' stderr log: {2}').format( self._racerd, self._server_stdout, self._server_stderr ) return 'racerd is not running' ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/rust/__init__.py0000644000175000017500000000000012677434535022460 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/c/0000755000175000017500000000000012677434535017606 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/c/hook.py0000644000175000017500000000217512677434535021125 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+20160327+gitc3e6904.orig/ycmd/completers/all/0000755000175000017500000000000012677434535020134 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/all/tests/0000755000175000017500000000000012677434535021276 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/all/tests/__init__.py0000644000175000017500000000000012677434535023375 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/all/__init__.py0000644000175000017500000000000012677434535022233 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/all/identifier_completer.py0000755000175000017500000002015712677434535024712 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 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[ 'filetypes' ][ 0 ] ) ) 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 ): try: filetype = request_data[ 'filetypes' ][ 0 ] except KeyError: filetype = None 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 ): cursor_identifier = _GetCursorIdentifier( request_data ) if not cursor_identifier: return self.AddIdentifier( cursor_identifier, request_data ) def AddBufferIdentifiers( self, request_data ): try: filetype = request_data[ 'filetypes' ][ 0 ] except KeyError: filetype = None filepath = request_data[ 'filepath' ] collect_from_comments_and_strings = bool( self.user_options[ 'collect_identifiers_from_comments_and_strings' ] ) if not filetype or not filepath: return 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 AddIdentifiersFromTagFiles( self, tag_files ): absolute_paths_to_tag_files = ycm_core.StringVector() 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 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, filetypes ): keyword_vector = ycm_core.StringVector() for keyword in keyword_list: keyword_vector.append( ToCppStringCompatible( keyword ) ) filepath = SYNTAX_FILENAME + filetypes[ 0 ] self._completer.AddIdentifiersToDatabase( keyword_vector, ToCppStringCompatible( filetypes[ 0 ] ), 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[ 'filetypes' ] ) 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 ): 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_num' ] - 1 filepath = request_data[ 'filepath' ] try: filetype = request_data[ 'filetypes' ][ 0 ] except KeyError: filetype = None contents_per_line = ( request_data[ 'file_data' ][ filepath ][ 'contents' ].split( '\n' ) ) ident = PreviousIdentifierOnLine( contents_per_line[ line_num ], column_num ) if ident: if len( ident ) < min_num_candidate_size_chars: return '' return ident prev_line = contents_per_line[ line_num - 1 ] ident = PreviousIdentifierOnLine( prev_line, len( prev_line ) ) 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 ): try: filetype = request_data[ 'filetypes' ][ 0 ] except KeyError: filetype = None return identifier_utils.IdentifierAtIndex( request_data[ 'line_value' ], request_data[ 'column_num' ] - 1, 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+20160327+gitc3e6904.orig/ycmd/completers/cpp/0000755000175000017500000000000012677434535020146 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cpp/hook.py0000644000175000017500000000217512677434535021465 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+20160327+gitc3e6904.orig/ycmd/completers/cpp/tests/0000755000175000017500000000000012677434535021310 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cpp/tests/__init__.py0000644000175000017500000000000012677434535023407 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cpp/clang_helpers.py0000644000175000017500000000204712677434535023331 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+20160327+gitc3e6904.orig/ycmd/completers/cpp/ephemeral_values_set.py0000644000175000017500000000445512677434535024724 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+20160327+gitc3e6904.orig/ycmd/completers/cpp/__init__.py0000644000175000017500000000000012677434535022245 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cpp/clang_completer.py0000755000175000017500000004417012677434535023667 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 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 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' ) ), '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 ) ), 'GetDocQuick' : ( 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[ 'unloaded_buffer' ] ) ) 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 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' ] if not filename: return '' flags = self._FlagsForRequest( request_data ) or [] source = extra_conf_store.ModuleFileForSourceFile( filename ) return 'Flags for {0} loaded from {1}:\n{2}'.format( filename, source, list( flags ) ) def _FlagsForRequest( self, request_data ): filename = request_data[ 'filepath' ] if 'compilation_flags' in request_data: return PrepareFlagsForClang( request_data[ 'compilation_flags' ], filename ) 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 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( declaration.text if declaration is not None else "", doc_data.brief_comment, doc_data.canonical_type, doc_data.display_name, _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+20160327+gitc3e6904.orig/ycmd/completers/cpp/flags.py0000644000175000017500000003333412677434535021622 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', '--fcolor-diagnostics']) # The -M* flags spec: # https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Preprocessor-Options.html FILE_FLAGS_TO_SKIP = set(['-MD', '-MMD', '-MF', '-MT', '-MQ', '-o']) # 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 ) if results[ 'do_cache' ]: 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 ): flags = _CompilerToLanguageFlag( flags ) flags = _RemoveXclangFlags( flags ) flags = _RemoveUnusedFlags( flags, filename ) 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 _CompilerToLanguageFlag( 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. We want to replace it with a corresponding language flag. E.g., -x c for gcc and -x c++ for g++.""" flags = _RemoveFlagsPrecedingCompiler( flags ) # First flag is now the compiler path or a flag starting with a dash if flags[ 0 ].startswith( '-' ): return flags language = ( 'c++' if CPP_COMPILER_REGEX.search( flags[ 0 ] ) else 'c' ) return flags[ :1 ] + [ '-x', language ] + flags[ 1: ] 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 Valloric/YouCompleteMe#303 for details. MAC_INCLUDE_PATHS = ( _PathsForAllMacToolchains( 'usr/include/c++/v1' ) + [ '/usr/local/include' ] + _PathsForAllMacToolchains( 'usr/include' ) + [ '/usr/include', '/System/Library/Frameworks', '/Library/Frameworks' ] + _LatestMacClangIncludes() ) def _ExtraClangFlags(): flags = _SpecialClangIncludes() if OnMac(): for path in MAC_INCLUDE_PATHS: flags.extend( [ '-isystem', path ] ) # On Windows, parsing of templates is delayed until instantation time. # This makes GetType and GetParent commands not returning the expected # result when the cursor is in templates. # 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 _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+20160327+gitc3e6904.orig/ycmd/completers/typescript/0000755000175000017500000000000012677434535021572 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/typescript/hook.py0000644000175000017500000000210212677434535023077 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 TypeScriptCompleter def GetCompleter( user_options ): return TypeScriptCompleter( user_options ) ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/typescript/__init__.py0000644000175000017500000000000012677434535023671 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/typescript/typescript_completer.py0000755000175000017500000004130512677434535026432 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 from threading import Thread from threading import Event from threading import Lock from tempfile import NamedTemporaryFile from ycmd import responses from ycmd import utils from ycmd.completers.completer import Completer BINARY_NOT_FOUND_MESSAGE = ( 'tsserver not found. ' 'TypeScript 1.5 or higher is required' ) MAX_DETAILED_COMPLETIONS = 100 RESPONSE_TIMEOUT_SECONDS = 10 _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 = 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' ] 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 ) # Used to prevent threads from concurrently writing to # the tsserver process' stdin self._writelock = Lock() binarypath = utils.PathToFirstExistingExecutable( [ 'tsserver' ] ) if not binarypath: _logger.error( BINARY_NOT_FOUND_MESSAGE ) raise RuntimeError( BINARY_NOT_FOUND_MESSAGE ) self._logfile = _LogFileName() tsserver_log = '-file {path} -level {level}'.format( path = self._logfile, level = _LogLevel() ) # TSServer get 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 self._environ = os.environ.copy() utils.SetEnviron( self._environ, 'TSS_LOG', tsserver_log ) # 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 = Lock() # TSServer ignores the fact that newlines are two characters on Windows # (\r\n) instead of one on other platforms (\n), so we use the # universal_newlines option to convert those newlines to \n. See the issue # https://github.com/Microsoft/TypeScript/issues/3403 # TODO: remove this option when the issue is fixed. # We also need to redirect the error stream to the output one on Windows. self._tsserver_handle = utils.SafePopen( binarypath, stdout = subprocess.PIPE, stdin = subprocess.PIPE, stderr = subprocess.STDOUT, env = self._environ, universal_newlines = True ) # 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._pendinglock = Lock() # Start a thread to read response from TSServer. self._thread = Thread( target = self._ReaderLoop, args = () ) self._thread.daemon = True self._thread.start() _logger.info( 'Enabling typescript completion' ) def _ReaderLoop( self ): """ Read responses from TSServer and use them to resolve the DeferredResponse instances. """ while True: try: message = self._ReadMessage() # 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( 'Recieved {0} event from tsserver'.format( eventname ) ) continue if msgtype != 'response': _logger.error( 'Unsuported message type {0}'.format( msgtype ) ) continue seq = message[ 'request_seq' ] with self._pendinglock: if seq in self._pending: self._pending[ seq ].resolve( message ) del self._pending[ seq ] except Exception as e: _logger.error( 'ReaderLoop error: {0}'.format( str( e ) ) ) 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 = 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' ] ) return json.loads( self._tsserver_handle.stdout.read( contentlength ) ) 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 _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 ) with self._writelock: self._tsserver_handle.stdin.write( json.dumps( request ) ) self._tsserver_handle.stdin.write( "\n" ) self._tsserver_handle.stdin.flush() 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._pendinglock: seq = request[ 'seq' ] self._pending[ seq ] = deferred with self._writelock: self._tsserver_handle.stdin.write( json.dumps( request ) ) self._tsserver_handle.stdin.write( "\n" ) self._tsserver_handle.stdin.flush() 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 } ) os.unlink( tmpfile.name ) 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[ 'column_num' ] } ) # 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[ 'column_num' ], 'entryNames': names } ) return [ _ConvertDetailedCompletionData( e, namelength ) for e in detailed_entries ] def GetSubcommandsMap( self ): return { 'GoToDefinition' : ( 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._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_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 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_num' ] } ) return [ responses.BuildGoToResponse( filepath = ref[ 'file' ], line_num = ref[ 'start' ][ 'line' ], column_num = ref[ 'start' ][ 'offset' ], description = ref[ 'lineText' ] ) for ref in response[ 'refs' ] ] 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_num' ] } ) 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_num' ] } ) 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_num' ], '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( new_name, file_replacement ) ) return responses.BuildFixItResponse( [ responses.FixIt( location, chunks ) ] ) def Shutdown( self ): self._SendCommand( 'exit' ) if not self.user_options[ 'server_keep_logfiles' ]: os.unlink( self._logfile ) self._logfile = None def DebugInfo( self, request_data ): return ( 'TSServer logfile:\n {0}' ).format( self._logfile ) def _LogFileName(): with NamedTemporaryFile( dir = utils.PathToCreatedTempDir(), prefix = 'tsserver_', suffix = '.log', delete = False ) as logfile: return logfile.name 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_name, source_range ): """ returns list FixItChunk for a tsserver source range """ return responses.FixItChunk( new_name, responses.Range( start = responses.Location( source_range[ 'start' ][ 'line' ], source_range[ 'start' ][ 'offset' ], file_name ), end = responses.Location( source_range[ 'end' ][ 'line' ], source_range[ 'end' ][ 'offset' ], file_name ) ) ) def _BuildFixItChunksForFile( 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' ] ) _logger.debug( 'Converted {0} to {1}'.format( file_replacement[ 'file' ], file_path ) ) return [ _BuildFixItChunkForRange( new_name, file_path, r ) for r in file_replacement[ 'locs' ] ] ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/objcpp/0000755000175000017500000000000012677434535020641 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/objcpp/hook.py0000644000175000017500000000217512677434535022160 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+20160327+gitc3e6904.orig/ycmd/completers/completer_utils.py0000644000175000017500000001707512677434535023162 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 from collections import defaultdict from ycmd.utils import ToCppStringCompatible, ToUnicode 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_column, column_num, filetype ): try: triggers = self._filetype_to_prepared_triggers[ filetype ] except KeyError: return None return _MatchingSemanticTrigger( current_line, start_column, column_num, triggers ) def MatchesForFiletype( self, current_line, start_column, column_num, filetype ): return self.MatchingTriggerForFiletype( current_line, start_column, column_num, 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 def _RegexTriggerMatches( trigger, line_value, start_column, column_num ): for match in trigger.finditer( line_value ): # By definition of 'start_column', we know that the character just before # 'start_column' is not an identifier character but all characters # between 'start_column' and 'column_num' are. This means that if our # trigger ends with an identifier character, its tail must match between # 'start_column' and 'column_num', 'start_column' excluded. But if it # doesn't, its tail must match exactly at 'start_column'. Both cases are # mutually exclusive hence the following condition. if start_column <= match.end() and match.end() <= column_num: return True return False # start_column and column_num are 0-based def _MatchingSemanticTrigger( line_value, start_column, column_num, trigger_list ): if start_column < 0 or column_num < 0: return None line_length = len( line_value ) if not line_length or start_column > line_length: return None # Ignore characters after user's caret column line_value = line_value[ :column_num ] for trigger in trigger_list: if _RegexTriggerMatches( trigger, line_value, start_column, column_num ): return trigger return None def _MatchesSemanticTrigger( line_value, start_column, column_num, trigger_list ): return _MatchingSemanticTrigger( line_value, start_column, column_num, 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 return FilterAndSortCandidates( candidates, ToCppStringCompatible( sort_property ), ToCppStringCompatible( query ) ) 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 ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/python/0000755000175000017500000000000012677434535020705 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/python/hook.py0000644000175000017500000000211412677434535022215 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+20160327+gitc3e6904.orig/ycmd/completers/python/__init__.py0000644000175000017500000000000012677434535023004 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/python/jedi_completer.py0000644000175000017500000003360312677434535024251 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?' ) LOG_FILENAME_FORMAT = os.path.join( utils.PathToCreatedTempDir(), u'jedihttp_{port}_{std}.log' ) PATH_TO_JEDIHTTP = os.path.join( os.path.abspath( 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: if not self._CheckBinaryExists( binary ): msg = BINARY_NOT_FOUND_MESSAGE.format( binary ) self._logger.error( msg ) raise RuntimeError( msg ) self._python_binary_path = binary def _CheckBinaryExists( self, binary ): """This method is here to help testing""" return os.path.isfile( binary ) def SupportedFiletypes( self ): """ Just python """ return [ 'python' ] def Shutdown( self ): if self.ServerIsRunning(): self._StopServer() def ServerIsReady( 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 ServerIsReady. """ 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: self._logger.info( 'Stopping JediHTTP' ) if self._jedihttp_phandle: self._jedihttp_phandle.terminate() self._jedihttp_phandle = None self._jedihttp_port = None if not self._keep_logfiles: utils.RemoveIfExists( self._logfile_stdout ) utils.RemoveIfExists( self._logfile_stderr ) 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 ), '--hmac-file-secret', hmac_file.name ] self._logfile_stdout = LOG_FILENAME_FORMAT.format( port = self._jedihttp_port, std = 'stdout' ) self._logfile_stderr = LOG_FILENAME_FORMAT.format( port = self._jedihttp_port, std = 'stderr' ) with utils.OpenForStdHandle( self._logfile_stderr ) as logerr: with utils.OpenForStdHandle( self._logfile_stdout ) as logout: self._jedihttp_phandle = utils.SafePopen( command, stdout = logout, stderr = logerr ) def _GenerateHmacSecret( self ): return os.urandom( HMAC_SECRET_LENGTH ) 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 col = request_data[ 'column_num' ] - 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 DefinedSubcommands( self ): # We don't want expose this sub-command because is not really needed for # the user but is useful in tests for tearing down the server subcommands = super( JediCompleter, self ).DefinedSubcommands() subcommands.remove( 'StopServer' ) return subcommands 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 ( 'JediHTTP running at 127.0.0.1:{0}\n' ' python binary: {1}\n' ' stdout log: {2}\n' ' stderr log: {3}' ).format( self._jedihttp_port, self._python_binary_path, self._logfile_stdout, self._logfile_stderr ) if self._logfile_stdout and self._logfile_stderr: return ( 'JediHTTP is no longer running\n' ' stdout log: {1}\n' ' stderr log: {2}' ).format( self._logfile_stdout, self._logfile_stderr ) return 'JediHTTP is not running' ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/general/0000755000175000017500000000000012677434535021001 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/general/filename_completer.py0000644000175000017500000001657012677434535025216 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 ToUnicode, OnWindows 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_column = request_data[ 'start_column' ] - 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_column ] ) ) def ShouldUseNowInner( self, request_data ): start_column = request_data[ 'start_column' ] - 1 current_line = request_data[ 'line_value' ] return ( start_column and ( current_line[ start_column - 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_column = request_data[ 'start_column' ] - 1 filepath = request_data[ 'filepath' ] filetypes = request_data[ 'file_data' ][ filepath ][ 'filetypes' ] line = current_line[ :start_column ] 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( os.getcwd(), 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+20160327+gitc3e6904.orig/ycmd/completers/general/tests/0000755000175000017500000000000012677434535022143 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/general/tests/__init__.py0000644000175000017500000000000012677434535024242 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/general/__init__.py0000644000175000017500000000000012677434535023100 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/general/ultisnips_completer.py0000644000175000017500000000371012677434535025460 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+20160327+gitc3e6904.orig/ycmd/completers/general/general_completer_store.py0000644000175000017500000001004112677434535026252 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+20160327+gitc3e6904.orig/ycmd/completers/go/0000755000175000017500000000000012677434535017771 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/go/hook.py0000644000175000017500000000217612677434535021311 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+20160327+gitc3e6904.orig/ycmd/completers/go/go_completer.py0000755000175000017500000002120712677434535023027 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 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 = '{0} shell call failed.' PARSE_ERROR_MESSAGE = 'Gocode returned invalid JSON response.' NO_COMPLETIONS_MESSAGE = 'Gocode returned empty JSON response.' GOCODE_PANIC_MESSAGE = ( 'Gocode panicked trying to find completions, ' + 'you likely have a syntax error.' ) DIR_OF_THIRD_PARTY = os.path.join( os.path.abspath( 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' ) ) } ) _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 ): def __init__( self, user_options ): super( GoCompleter, self ).__init__( user_options ) self._popener = utils.SafePopen # Overridden in test. self._binary_gocode = FindBinary( 'gocode', user_options ) self._binary_godef = FindBinary( 'godef', user_options ) def SupportedFiletypes( self ): return [ 'go' ] def ComputeCandidatesInner( self, request_data ): filename = request_data[ 'filepath' ] _logger.info( "gocode completion request %s" % filename ) if not filename: return contents = utils.ToBytes( request_data[ 'file_data' ][ filename ][ 'contents' ] ) offset = _ComputeOffset( contents, request_data[ 'line_num' ], request_data[ 'column_num' ] ) stdoutdata = self._ExecuteBinary( self._binary_gocode, '-f=json', 'autocomplete', filename, str( offset ), contents = contents ) try: resultdata = json.loads( ToUnicode( stdoutdata ) ) except ValueError: _logger.error( PARSE_ERROR_MESSAGE ) raise RuntimeError( PARSE_ERROR_MESSAGE ) if len( resultdata ) != 2: _logger.error( NO_COMPLETIONS_MESSAGE ) raise RuntimeError( 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 { 'StartServer': ( lambda self, request_data, args: self._StartServer() ), 'StopServer': ( lambda self, request_data, args: self._StopServer() ), '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 OnFileReadyToParse( self, request_data ): self._StartServer() def Shutdown( self ): self._StopServer() def _StartServer( self ): """ Start the GoCode server """ self._ExecuteBinary( self._binary_gocode ) def _StopServer( self ): """ Stop the GoCode server """ _logger.info( 'Stopping GoCode server' ) self._ExecuteBinary( self._binary_gocode, 'close' ) def _ExecuteBinary( self, binary, *args, **kwargs): """ Execute the GoCode/GoDef binary with given arguments. Use the contents argument to send data to GoCode. Return the standard output. """ popen_handle = self._popener( [ binary ] + list( args ), stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE ) contents = kwargs[ 'contents' ] if 'contents' in kwargs else None stdoutdata, stderrdata = popen_handle.communicate( contents ) if popen_handle.returncode: binary_str = 'Godef' if binary == self._binary_godef else 'Gocode' _logger.error( SHELL_ERROR_MESSAGE.format( binary_str ) + " code %i stderr: %s", popen_handle.returncode, stderrdata) raise RuntimeError( SHELL_ERROR_MESSAGE.format( binary_str ) ) return stdoutdata def _GoToDefinition( self, request_data ): try: filename = request_data[ 'filepath' ] _logger.info( "godef GoTo request %s" % filename ) if not filename: return contents = utils.ToBytes( request_data[ 'file_data' ][ filename ][ 'contents' ] ) offset = _ComputeOffset( contents, request_data[ 'line_num' ], request_data[ 'column_num' ] ) stdout = self._ExecuteBinary( self._binary_godef, "-i", "-f=%s" % filename, '-json', "-o=%s" % offset, contents = contents ) return self._ConstructGoToFromResponse( stdout ) except Exception as e: _logger.exception( e ) raise RuntimeError( 'Can\'t jump to definition.' ) 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.' ) # Compute the byte offset in the file given the line and column. # TODO(ekfriis): If this is slow, consider moving this to C++ ycm_core, # perhaps in RequestWrap. def _ComputeOffset( contents, line, col ): contents = ToBytes( contents ) curline = 1 curcol = 1 newline = bytes( b'\n' )[ 0 ] for i, byte in enumerate( contents ): if curline == line and curcol == col: return i curcol += 1 if byte == newline: curline += 1 curcol = 1 _logger.error( 'GoCode completer - could not compute byte offset ' + 'corresponding to L%i C%i', line, col ) return -1 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+20160327+gitc3e6904.orig/ycmd/completers/go/__init__.py0000644000175000017500000000000012677434535022070 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cs/0000755000175000017500000000000012677434535017771 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cs/hook.py0000644000175000017500000000211412677434535021301 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+20160327+gitc3e6904.orig/ycmd/completers/cs/__init__.py0000644000175000017500000000000012677434535022070 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/cs/solutiondetection.py0000644000175000017500000001173712677434535024127 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+20160327+gitc3e6904.orig/ycmd/completers/cs/cs_completer.py0000755000175000017500000006103712677434535023034 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 time import re from ycmd.completers.completer import Completer from ycmd.utils import ForceSemanticCompletion from ycmd import responses from ycmd import utils 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.join( os.path.abspath( os.path.dirname( __file__ ) ), '..', '..', '..', 'third_party', 'OmniSharpServer', 'OmniSharp', 'bin', 'Release', 'OmniSharp.exe' ) 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 ): if solutioncompleter.ServerIsRunning(): 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 { 'StartServer' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = '_StartServer', no_request_data = True ) ), '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' ) ), 'ServerIsRunning' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = 'ServerIsRunning', no_request_data = True ) ), 'ServerIsHealthy' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = 'ServerIsHealthy', no_request_data = True ) ), 'ServerIsReady' : ( lambda self, request_data, args: self._SolutionSubcommand( request_data, method = 'ServerIsReady', no_request_data = True ) ), } 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( 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, quick_fix ): filename = quick_fix[ "FileName" ] location = responses.Location( quick_fix[ "Line" ], quick_fix[ "Column" ], filename ) location_range = responses.Range( location, location ) return responses.Diagnostic( list(), location, location_range, 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 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 ): solutioncompleter = self._GetSolutionCompleter( request_data ) if solutioncompleter.ServerIsRunning(): return ( 'OmniSharp Server running at: {0}\n' 'OmniSharp logfiles:\n{1}\n{2}' ).format( solutioncompleter._ServerLocation(), solutioncompleter._filename_stdout, solutioncompleter._filename_stderr ) else: return 'OmniSharp Server is not running' 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. \n' ) 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' ] ) filename_format = os.path.join( utils.PathToCreatedTempDir(), u'omnisharp_{port}_{sln}_{std}.log' ) solutionfile = os.path.basename( path_to_solutionfile ) self._filename_stdout = filename_format.format( port = self._omnisharp_port, sln = solutionfile, std = 'stdout' ) self._filename_stderr = filename_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 not self.ServerIsRunning(): return self._logger.info( 'Stopping OmniSharp server' ) self._TryToStopServer() # Kill it if it's still up if self.ServerIsRunning(): self._logger.info( 'Killing OmniSharp server' ) self._omnisharp_phandle.kill() self._CleanupAfterServerStop() self._logger.info( 'Stopped OmniSharp server' ) def _TryToStopServer( self ): for _ in range( 5 ): try: self._GetResponse( '/stopserver', timeout = .1 ) except: pass for _ in range( 10 ): if not self.ServerIsRunning(): return time.sleep( .1 ) def _CleanupAfterServerStop( self ): self._omnisharp_port = None self._omnisharp_phandle = None if ( not self._keep_logfiles ): if self._filename_stdout: os.unlink( self._filename_stdout ) if self._filename_stderr: os.unlink( self._filename_stderr ) 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.BuildGoToResponse( 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.BuildGoToResponse( implementation[ 'QuickFixes' ][ 0 ][ 'FileName' ], implementation[ 'QuickFixes' ][ 0 ][ 'Line' ], implementation[ 'QuickFixes' ][ 0 ][ 'Column' ] ) else: return [ responses.BuildGoToResponse( 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" ] 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_num' ] 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 ) 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, index - curr_pos + 1 curr_pos += len( line ) assert False ycmd-0+20160327+gitc3e6904.orig/ycmd/completers/objc/0000755000175000017500000000000012677434535020301 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/completers/objc/hook.py0000644000175000017500000000217512677434535021620 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+20160327+gitc3e6904.orig/ycmd/responses.py0000644000175000017500000001545712677434535017616 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 ) def BuildGoToResponse( filepath, line_num, column_num, description = None ): response = { 'filepath': os.path.realpath( filepath ), 'line_num': line_num, 'column_num': column_num } 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 def BuildCompletionResponse( completion_datas, start_column, errors=None ): return { 'completions': completion_datas, 'completion_start_column': start_column, 'errors': errors if errors else [], } 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.""" def __init__ ( self, location, chunks ): """location of type Location, chunks of type list""" self.location = location self.chunks = chunks 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, filename is absolute path of the file""" self.line_number_ = line self.column_number_ = column self.filename_ = 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 ], } return { 'fixits' : [ BuildFixItData( x ) for x in fixits ] } def BuildExceptionResponse( exception, traceback ): return { 'exception': exception, 'message': str( exception ), 'traceback': traceback } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/0000755000175000017500000000000012677434535016351 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/0000755000175000017500000000000012677434535020517 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/0000755000175000017500000000000012677434535022330 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/trivial2.js0000644000175000017500000000000312677434535024413 0ustar onuronurX. ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/.tern-project0000644000175000017500000000032312677434535024743 0ustar onuronur{ "libs": [ "browser", "jquery" ], "loadEagerly": [ "file1.js", "file2.js", "file3.js" ], "plugins": { "requirejs": { "baseURL": "./", "paths": {} } } } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/file2.js0000644000175000017500000000003112677434535023661 0ustar onuronur console.log( global ); ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/lamelib/0000755000175000017500000000000012677434535023735 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/lamelib/lame_widget.js0000644000175000017500000000051012677434535026550 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+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/file1.js0000644000175000017500000000006712677434535023671 0ustar onuronurvar global = 'this is a test' console.log( global ); ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/trivial.js0000644000175000017500000000005312677434535024336 0ustar onuronurvar X = { y: 'string', z: 'integer' }; ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/requirejs_test.js0000644000175000017500000000064612677434535025744 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+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/coollib/0000755000175000017500000000000012677434535023753 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/coollib/cool_widget.js0000644000175000017500000000054312677434535026612 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+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/coollib/cool_object.js0000644000175000017500000000104612677434535026574 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+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/file4.js0000644000175000017500000000042112677434535023666 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+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/simple_test.js0000644000175000017500000000066512677434535025225 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+20160327+gitc3e6904.orig/ycmd/tests/javascript/testdata/file3.js0000644000175000017500000000005612677434535023671 0ustar onuronur function method( xyz ) { return global } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/get_completions_test.py0000644000175000017500000003240712677434535025331 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 http.client 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': http.client.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': http.client.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': http.client.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': http.client.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': http.client.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': http.client.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': http.client.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(), } ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/__init__.py0000644000175000017500000001003312677434535022625 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 import time from ycmd import handlers from ycmd.tests.test_utils import BuildRequest, SetUpApp 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 WaitUntilTernServerReady( app ): app.post_json( '/run_completer_command', BuildRequest( command_arguments = [ 'StartServer' ], completer_target = 'filetype_default', filetype = 'javascript', filepath = '/foo.js', contents = '', line_num = '1' ) ) retries = 100 while retries > 0: result = app.get( '/ready', { 'subserver': 'javascript' } ).json if result: return time.sleep( 0.2 ) retries = retries - 1 raise RuntimeError( 'Timeout waiting for Tern.js server to be ready' ) def StopTernServer( app ): app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'StopServer' ], filetype = 'javascript' ), expect_errors = True ) 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 = os.getcwd() os.chdir( PathToTestFile() ) WaitUntilTernServerReady( shared_app ) 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 StopTernServer( shared_app ) 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 ): 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 old_current_dir = os.getcwd() try: os.chdir( PathToTestFile() ) app = SetUpApp() WaitUntilTernServerReady( app ) test( app, *args, **kwargs ) StopTernServer( app ) finally: os.chdir( old_current_dir ) handlers._server_state = old_server_state return Wrapper ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/event_notification_test.py0000644000175000017500000001463612677434535026031 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 http.client import os from ycmd.tests.test_utils import BuildRequest, ErrorMatcher from ycmd.tests.javascript import ( IsolatedYcmd, PathToTestFile, WaitUntilTernServerReady ) from ycmd.utils import ReadFile @IsolatedYcmd def EventNotification_OnFileReadyToParse_ProjectFile_cwd_test( app ): 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, http.client.OK ) assert_that( response.json, empty() ) @IsolatedYcmd def EventNotification_OnFileReadyToParse_ProjectFile_parentdir_test( app ): 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, http.client.OK ) assert_that( response.json, empty() ) @IsolatedYcmd @patch( 'ycmd.completers.javascript.tern_completer.GlobalConfigExists', return_value = False ) def EventNotification_OnFileReadyToParse_NoProjectFile_test( app, *args ): # 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, http.client.INTERNAL_SERVER_ERROR ) assert_that( response.json, ErrorMatcher( RuntimeError, 'Warning: Unable to detect a .tern-project file ' 'in the hierarchy before ' + os.getcwd() + ' 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, http.client.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 = [ 'StopServer' ], filetype = 'javascript', contents = contents, completer_target = 'filetype_default' ) ) app.post_json( '/run_completer_command', BuildRequest( command_arguments = [ 'StartServer' ], filetype = 'javascript', contents = contents, completer_target = 'filetype_default' ) ) WaitUntilTernServerReady( app ) 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, http.client.INTERNAL_SERVER_ERROR ) assert_that( response.json, ErrorMatcher( RuntimeError, 'Warning: Unable to detect a .tern-project file ' 'in the hierarchy before ' + os.getcwd() + ' 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 ): 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, http.client.OK ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/javascript/subcommands_test.py0000644000175000017500000003056212677434535024451 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, has_entries from nose.tools import eq_ from pprint import pformat import http.client from ycmd.tests.javascript import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, ChunkMatcher, ErrorMatcher, LocationMatcher ) from ycmd.utils import ReadFile @SharedYcmd def Subcommands_DefinedSubcommands_test( app ): subcommands_data = BuildRequest( completer_target = 'javascript' ) eq_( sorted( [ 'GoToDefinition', 'GoTo', 'GetDoc', 'GetType', 'StartServer', 'StopServer', 'GoToReferences', 'RefactorRename' ] ), 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 ) # 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': http.client.OK, 'data': has_entries( { 'filepath': PathToTestFile( 'simple_test.js' ), 'line_num': 1, 'column_num': 5, } ) } } ) @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': http.client.OK, 'data': has_entries( { 'filepath': PathToTestFile( 'simple_test.js' ), 'line_num': 1, 'column_num': 5, } ) } } ) @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': http.client.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': http.client.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': http.client.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_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': http.client.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': http.client.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': http.client.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 ): 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': http.client.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': http.client.INTERNAL_SERVER_ERROR, 'data': ErrorMatcher( ValueError, 'Please specify a new name to rename it to.\n' 'Usage: RefactorRename ' ), } } ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/0000755000175000017500000000000012677434535020162 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/0000755000175000017500000000000012677434535024014 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/0000755000175000017500000000000012677434535025765 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/0000755000175000017500000000000012677434535027410 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/Qt/0000755000175000017500000000000012677434535027774 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/Qt/QtGui0000644000175000017500000000005012677434535030743 0ustar onuronur// This file includes all QtGui headers ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/0000755000175000017500000000000012677434535030441 5ustar onuronur././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QDialogycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QDial0000644000175000017500000000000012677434535031344 0ustar onuronur././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QWidgetycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/include/QtGui/QWidg0000644000175000017500000000000012677434535031365 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/foo漢字.txt0000644000175000017500000000000012677434535031454 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/test.cpp0000644000175000017500000000007212677434535027447 0ustar onuronur#include "test.hpp" #include const char* c = ""; ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/filename_completer/inner_dir/test.hpp0000644000175000017500000000000012677434535027443 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/windows/0000755000175000017500000000000012677434535021654 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/windows/compile_commands.json0000644000175000017500000000014512677434535026060 0ustar onuronur[ { "directory": "C:\\dir", "command": "/usr/bin/clang++ example.cc", "file": "example.cc" } ] ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/unix/0000755000175000017500000000000012677434535021145 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/testdata/unix/compile_commands.json0000644000175000017500000000014212677434535025346 0ustar onuronur[ { "directory": "/dir", "command": "/usr/bin/clang++ example.cc", "file": "example.cc" } ] ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/identifier_utils_test.py0000644000175000017500000002744112677434535023334 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_generic_test(): ok_( iu.IsIdentifier( 'foo' ) ) ok_( iu.IsIdentifier( 'foo129' ) ) ok_( iu.IsIdentifier( 'f12' ) ) 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_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' ) ) 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' ) ) 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' ) ) 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' ) ) 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' ) ) 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+20160327+gitc3e6904.orig/ycmd/tests/get_completions_test.py0000644000175000017500000003130212677434535023154 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, equal_to, has_items from mock import patch from nose.tools import eq_ from ycmd.tests import SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, DummyCompleter, PatchCompleter, UserOption ) @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_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 @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_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 ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/bottle_utils_test.py0000644000175000017500000000367512677434535022506 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+20160327+gitc3e6904.orig/ycmd/tests/utils_test.py0000644000175000017500000002276112677434535021132 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 import os import subprocess from shutil import rmtree import ycm_core from future.utils import native from mock import patch, call from nose.tools import eq_, ok_ from ycmd import utils from ycmd.tests.test_utils import Py2Only, Py3Only, WindowsOnly 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 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 PathToCreatedTempDir_DirDoesntExist_test(): tempdir = PathToTestFile( 'tempdir' ) rmtree( tempdir, ignore_errors = True ) try: eq_( utils.PathToCreatedTempDir( tempdir ), tempdir ) finally: rmtree( tempdir, ignore_errors = True ) def PathToCreatedTempDir_DirDoesExist_test(): tempdir = PathToTestFile( 'tempdir' ) os.makedirs( tempdir ) try: eq_( utils.PathToCreatedTempDir( tempdir ), tempdir ) finally: rmtree( tempdir, ignore_errors = True ) 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' ] ) ) @patch( 'os.environ', { 'TRAVIS': 1 } ) def OnTravis_IsOnTravis_test(): ok_( utils.OnTravis() ) @patch( 'os.environ', {} ) def OnTravis_IsNotOnTravis_test(): ok_( not utils.OnTravis() ) @patch( 'ycmd.utils.OnWindows', return_value = False ) @patch( 'subprocess.Popen' ) def SafePopen_RemovesStdinWindows_test( *args ): utils.SafePopen( [ 'foo' ], stdin_windows = subprocess.PIPE ) eq_( subprocess.Popen.call_args, call( [ 'foo' ] ) ) @patch( 'ycmd.utils.OnWindows', return_value = True ) @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 ) @patch( 'ycmd.utils.OnWindows', return_value = False ) def ConvertArgsToShortPath_PassthroughOnUnix_test( *args ): eq_( 'foo', utils.ConvertArgsToShortPath( 'foo' ) ) eq_( [ 'foo' ], utils.ConvertArgsToShortPath( [ 'foo' ] ) ) @patch( 'ycmd.utils.OnWindows', return_value = False ) def SetEnviron_UnicodeNotOnWindows_test( *args ): env = {} utils.SetEnviron( env, u'key', u'value' ) eq_( env, { u'key': u'value' } ) @Py2Only @patch( 'ycmd.utils.OnWindows', return_value = True ) 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 ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/server_utils_test.py0000644000175000017500000000314112677434535022507 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 raises, assert_that, calling from nose.tools import ok_ from ycmd.server_utils import ( PathToNearestThirdPartyFolder, AddNearestThirdPartyFoldersToSysPath ) import os.path 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.*' ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/check_core_version_test.py0000644000175000017500000000213712677434535023617 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 ..server_utils import CompatibleWithCurrentCoreVersion from nose.tools import eq_ def CompatibleWithCurrentCoreVersion_test(): eq_( CompatibleWithCurrentCoreVersion(), True ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/__init__.py0000644000175000017500000000356412677434535020472 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 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 ): return test( shared_app, *args, **kwargs ) return Wrapper ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/rust/0000755000175000017500000000000012677434535017346 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/rust/testdata/0000755000175000017500000000000012677434535021157 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/rust/testdata/std_completions.rs0000644000175000017500000000013112677434535024726 0ustar onuronuruse std::path::Path; pub fn main() { let program = Path::new( "/foo" ); program. } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/rust/testdata/test.rs0000644000175000017500000000031712677434535022505 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+20160327+gitc3e6904.orig/ycmd/tests/rust/get_completions_test.py0000644000175000017500000000532412677434535024156 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, has_entry, has_items, contains_string from ycmd.tests.rust import IsolatedYcmd, PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, CompletionEntryMatcher from ycmd.utils import ReadFile @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 ): 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, has_entry( 'message', contains_string( 'rust_src_path' ) ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/rust/__init__.py0000644000175000017500000000701412677434535021461 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 import time from ycmd.tests.test_utils import BuildRequest, SetUpApp from ycmd import handlers 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 WaitUntilRacerdServerReady( app ): retries = 100 while retries > 0: result = app.get( '/ready', { 'subserver': 'rust' } ).json if result: return time.sleep( 0.2 ) retries = retries - 1 raise RuntimeError( "Timeout waiting for JediHTTP" ) def StopRacerdServer( app ): app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'StopServer' ], filetype = 'rust' ), expect_errors = True ) 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() WaitUntilRacerdServerReady( shared_app ) 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 StopRacerdServer( shared_app ) 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 ): 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() WaitUntilRacerdServerReady( app ) test( app, *args, **kwargs ) StopRacerdServer( app ) finally: handlers._server_state = old_server_state return Wrapper ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/rust/subcommands_test.py0000644000175000017500000000371212677434535023275 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 ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/0000755000175000017500000000000012677434535017435 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/0000755000175000017500000000000012677434535021246 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/FixIt_Clang_cpp11.cpp0000644000175000017500000000312412677434535025105 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() { } } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/GetType_Clang_test.cc0000644000175000017500000000130312677434535025276 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; return 0; } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/GetDoc_Clang.cc0000644000175000017500000000360012677434535024025 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/GoTo_all_Clang_test.cc0000644000175000017500000000054312677434535025422 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; } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/FixIt_Clang_objc.m0000644000175000017500000000037212677434535024552 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/.ycm_extra_conf.py0000644000175000017500000000015112677434535024673 0ustar onuronurdef FlagsForFile( filename ): return { 'flags': ['-x', 'c++', '-I', '.'], 'do_cache': True } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/GoTo_Clang_ZeroBasedLineAndColumn_test.cc0000644000175000017500000000024612677434535031141 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/basic.cpp0000644000175000017500000000020112677434535023024 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/client_data/0000755000175000017500000000000012677434535023515 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/client_data/.ycm_extra_conf.py0000644000175000017500000000017112677434535027144 0ustar onuronurdef FlagsForFile( filename, **kwargs ): return { 'flags': kwargs['client_data']['flags'], 'do_cache': True } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/client_data/include.hpp0000644000175000017500000000000012677434535025637 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/client_data/main.cpp0000644000175000017500000000015512677434535025146 0ustar onuronurstruct Foo { int x; }; int main() { Foo foo; // The location after the dot is line 9, col 7 foo. } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/client_data/include.cpp0000644000175000017500000000001312677434535025636 0ustar onuronur#include " ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/general_fallback/0000755000175000017500000000000012677434535024502 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/general_fallback/lang_cpp.cc0000644000175000017500000000245012677434535026575 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/general_fallback/.ycm_extra_conf.py0000644000175000017500000000103612677434535030132 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, 'do_cache': True } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/general_fallback/lang_c.c0000644000175000017500000000500712677434535026073 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/GetParent_Clang_test.cc0000644000175000017500000000125412677434535025613 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/noflags/0000755000175000017500000000000012677434535022677 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/noflags/.ycm_extra_conf.py0000644000175000017500000000012412677434535026324 0ustar onuronurdef FlagsForFile( filename ): return { 'flags': [], 'do_cache': True } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/noflags/basic.cpp0000644000175000017500000000020112677434535024455 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/0000755000175000017500000000000012677434535023646 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/quote/0000755000175000017500000000000012677434535025003 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/quote/b.hpp0000644000175000017500000000000012677434535025723 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/system/0000755000175000017500000000000012677434535025172 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/system/c.hpp0000644000175000017500000000000012677434535026113 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/system/a.hpp0000644000175000017500000000000012677434535026111 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/.ycm_extra_conf.py0000644000175000017500000000035112677434535027275 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' ) ], 'do_cache': True } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/main.cpp0000644000175000017500000000032112677434535025272 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+20160327+gitc3e6904.orig/ycmd/tests/clang/testdata/test-include/a.hpp0000644000175000017500000000000012677434535024565 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/get_completions_test.py0000644000175000017500000003775612677434535024263 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 hamcrest import ( assert_that, contains, contains_inanyorder, empty, has_item, has_items, has_entry, has_entries ) import http.client 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 ) 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: 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 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 } """ app.post_json( '/load_extra_conf_file', { 'filepath': PathToTestFile( 'general_fallback', '.ycm_extra_conf.py' ) } ) 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' ] ) 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': http.client.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': http.client.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': http.client.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': http.client.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': http.client.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': http.client.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': http.client.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() } ) }, } ) @SharedYcmd 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' ] ) @SharedYcmd 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, http.client.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, http.client.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, http.client.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]' ) ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/__init__.py0000644000175000017500000000511712677434535021552 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 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 ): 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+20160327+gitc3e6904.orig/ycmd/tests/clang/comment_strip_test.py0000644000175000017500000001171312677434535023734 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+20160327+gitc3e6904.orig/ycmd/tests/clang/diagnostics_test.py0000644000175000017500000001532312677434535023361 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 } ), ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/subcommands_test.py0000644000175000017500000010612712677434535023370 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, calling, contains, equal_to, has_entries, raises ) from nose.tools import eq_ from pprint import pprint from webtest import AppError import http.client 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 from ycmd.utils import ReadFile @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 ) eq_( response, app.post_json( '/run_completer_command', goto_data ).json ) 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] }, ] 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 ] 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 ] 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, } eq_( response, app.post_json( '/run_completer_command', goto_data ).json ) 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 ) eq_( { 'message': expected }, app.post_json( '/run_completer_command', request_data ).json ) 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'], ] for test in tests: yield ( RunGetSemanticTest, 'GetType_Clang_test.cc', test, [ 'GetType' ] ) 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 Subcommands_FixIt_all_test(): cfile = 'FixIt_Clang_cpp11.cpp' mfile = 'FixIt_Clang_objc.m' tests = [ [ 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 ], ] 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, http.client.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, http.client.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_GetDocQuick_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 = [ 'GetDocQuick' ], 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_GetDocQuick_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 = [ 'GetDocQuick' ], 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_GetDocQuick_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 = [ 'GetDocQuick' ], 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_GetDocQuick_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 = [ 'GetDocQuick' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors = True ) eq_( response.status_code, http.client.INTERNAL_SERVER_ERROR ) assert_that( response.json, ErrorMatcher( ValueError, NO_DOCUMENTATION_MESSAGE ) ) @SharedYcmd def Subcommands_GetDocQuick_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 = [ 'GetDocQuick' ], completer_target = 'filetype_default' ) response = app.post_json( '/run_completer_command', event_data, expect_errors = True ) eq_( response.status_code, http.client.INTERNAL_SERVER_ERROR ) assert_that( response.json, ErrorMatcher( ValueError, NO_DOCUMENTATION_MESSAGE ) ) @SharedYcmd def Subcommands_GetDocQuick_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 = [ 'GetDocQuick' ], 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.""" } ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/clang/flags_test.py0000644000175000017500000002060712677434535022147 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 @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' ], 'do_cache': True } 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' ] ) 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_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 CompilerToLanguageFlag_Passthrough_test(): eq_( [ '-foo', '-bar' ], flags._CompilerToLanguageFlag( [ '-foo', '-bar' ] ) ) def _ReplaceCompilerTester( compiler, language ): to_removes = [ [], [ '/usr/bin/ccache' ], [ 'some_command', 'another_command' ] ] expected = [ '-foo', '-bar' ] for to_remove in to_removes: eq_( [ compiler, '-x', language ] + expected, flags._CompilerToLanguageFlag( to_remove + [ compiler ] + expected ) ) def CompilerToLanguageFlag_ReplaceCCompiler_test(): compilers = [ 'cc', 'gcc', 'clang', '/usr/bin/cc', '/some/other/path', 'some_command' ] for compiler in compilers: yield _ReplaceCompilerTester, compiler, 'c' def CompilerToLanguageFlag_ReplaceCppCompiler_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 _ReplaceCompilerTester, compiler, '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+20160327+gitc3e6904.orig/ycmd/tests/filename_completer_test.py0000644000175000017500000002547412677434535023630 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 nose.tools import eq_ from ycmd.completers.general.filename_completer import FilenameCompleter from ycmd.request_wrap import RequestWrap from ycmd import user_options_store 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 ): request = REQUEST_DATA.copy() request[ 'column_num' ] = len( contents ) + 1 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 ] 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 ): return _CompletionResultsForLine( self._filename_completer, contents ) 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 http.client 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, http.client.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+20160327+gitc3e6904.orig/ycmd/tests/request_wrap_test.py0000644000175000017500000001130512677434535022503 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 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_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' ] ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/0000755000175000017500000000000012677434535020557 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/testdata/0000755000175000017500000000000012677434535022370 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/testdata/file2.ts0000644000175000017500000000003012677434535023732 0ustar onuronurnew Bar().testMethod(); ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/testdata/tsconfig.json0000644000175000017500000000016212677434535025076 0ustar onuronur{ "compilerOptions": { "noEmit": true }, "files": [ "test.ts", "file2.ts", "file3.ts" ] } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/testdata/file3.ts0000644000175000017500000000004712677434535023743 0ustar onuronurvar bar = new Bar(); bar.testMethod(); ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/testdata/test.ts0000644000175000017500000000061112677434535023715 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+20160327+gitc3e6904.orig/ycmd/tests/typescript/get_completions_test.py0000644000175000017500000000605412677434535025370 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_inanyorder, has_entries from mock import patch from ycmd.tests.typescript import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest, CompletionEntryMatcher 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': contains_inanyorder( CompletionEntryMatcher( 'methodA' ), CompletionEntryMatcher( 'methodB' ), CompletionEntryMatcher( 'methodC' ) ) } ) } } ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/__init__.py0000644000175000017500000000356412677434535022700 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 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 ): return test( shared_app, *args, **kwargs ) return Wrapper ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/typescript/subcommands_test.py0000644000175000017500000003443212677434535024511 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_inanyorder, has_items, 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_GoToReferences_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 ) references_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'GoToReferences' ], line_num = 33, column_num = 6, contents = contents, filetype = 'typescript', filepath = filepath ) expected = has_items( has_entries( { 'description': 'var bar = new Bar();', 'line_num' : 33, 'column_num' : 5 } ), has_entries( { 'description': 'bar.testMethod();', 'line_num' : 34, 'column_num' : 1 } ) ) actual = app.post_json( '/run_completer_command', references_data ).json 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_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_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 print( str( response ) ) 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 print( str( response ) ) 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 ) } ) ) } ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/request_validation_test.py0000644000175000017500000000624012677434535023666 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+20160327+gitc3e6904.orig/ycmd/tests/test_utils.py0000644000175000017500000001152012677434535021121 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 from mock import patch from webtest import TestApp import bottle import contextlib from ycmd import handlers, user_options_store from ycmd.completers.completer import Completer from ycmd.responses import BuildCompletionData from ycmd.utils import OnMac, OnWindows 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' ) 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 } ) } ) @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 finally: handlers.UpdateUserOptions( current_options ) def SetUpApp(): bottle.debug( True ) handlers.SetServerStateToDefaults() return TestApp( handlers.app ) 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 [] ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python_support_test.py0000644000175000017500000001072512677434535023104 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+20160327+gitc3e6904.orig/ycmd/tests/completer_test.py0000644000175000017500000000372112677434535021757 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 ycmd.tests.test_utils import DummyCompleter from ycmd.user_options_store import DefaultOptions from nose.tools import eq_ 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' } ] ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/completer_utils_test.py0000644000175000017500000002042712677434535023201 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+20160327+gitc3e6904.orig/ycmd/tests/subcommands_test.py0000644000175000017500000000412712677434535022301 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+20160327+gitc3e6904.orig/ycmd/tests/python/0000755000175000017500000000000012677434535017672 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/0000755000175000017500000000000012677434535021503 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/goto_file2.py0000644000175000017500000000004212677434535024102 0ustar onuronurfrom goto_file3 import bar as foo ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/goto_file3.py0000644000175000017500000000002212677434535024101 0ustar onuronurdef bar(): pass ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/unicode.py0000644000175000017500000000004612677434535023503 0ustar onuronurdef Foo(): """aafäö""" pass Fo ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/GetDoc.py0000644000175000017500000000044212677434535023222 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+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/goto_file4.py0000644000175000017500000000003112677434535024102 0ustar onuronurfrom math import sin sin ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/goto_file1.py0000644000175000017500000000003712677434535024105 0ustar onuronurfrom goto_file2 import foo foo ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/basic.py0000644000175000017500000000012512677434535023134 0ustar onuronurclass Foo(object): def __init__(self): self.a = 1 self.b = 2 f = Foo() f. ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/goto_file5.py0000644000175000017500000000003712677434535024111 0ustar onuronurclass Foo(object): pass Bar ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/general_fallback/0000755000175000017500000000000012677434535024737 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/general_fallback/lang_python.py0000644000175000017500000000175412677434535027642 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+20160327+gitc3e6904.orig/ycmd/tests/python/testdata/goto_references.py0000644000175000017500000000005112677434535025222 0ustar onuronurdef f(): pass a = f() b = f() c = f() ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/get_completions_test.py0000644000175000017500000001162112677434535024477 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 ) from ycmd.utils import ReadFile from ycmd.tests.python import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import ( BuildRequest, CompletionEntryMatcher, CompletionLocationMatcher ) import http.client @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': http.client.OK, 'data': has_entries( { 'completions': contains( CompletionEntryMatcher( 'a_parameter', '[ID]' ), CompletionEntryMatcher( 'another_parameter', '[ID]' ), ), 'errors': empty(), } ) }, } ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/python/__init__.py0000644000175000017500000000706412677434535022012 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 import time from ycmd import handlers from ycmd.tests.test_utils import BuildRequest, 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 WaitUntilJediHTTPServerReady( app ): retries = 100 while retries > 0: result = app.get( '/ready', { 'subserver': 'python' } ).json if result: return time.sleep( 0.2 ) retries = retries - 1 raise RuntimeError( "Timeout waiting for JediHTTP" ) def StopJediHTTPServer( app ): # We don't actually start a JediHTTP server on every test, so we just # ignore errors when stopping the server app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'StopServer' ], filetype = 'python' ), expect_errors = True ) 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() WaitUntilJediHTTPServerReady( shared_app ) 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 StopJediHTTPServer( shared_app ) 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 ): 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+20160327+gitc3e6904.orig/ycmd/tests/python/user_defined_python_test.py0000644000175000017500000001301012677434535025333 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.completers.python.jedi_completer.JediCompleter.' '_CheckBinaryExists', return_value = False ) 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.completers.python.jedi_completer.JediCompleter.' '_CheckBinaryExists', return_value = True ) 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.completers.python.jedi_completer.JediCompleter.' '_CheckBinaryExists', return_value = True ) 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.completers.python.jedi_completer.JediCompleter.' '_CheckBinaryExists', return_value = True ) 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.completers.python.jedi_completer.JediCompleter.' '_CheckBinaryExists', return_value = False ) 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+20160327+gitc3e6904.orig/ycmd/tests/python/subcommands_test.py0000644000175000017500000001522412677434535023622 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+20160327+gitc3e6904.orig/ycmd/tests/go/0000755000175000017500000000000012677434535016756 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/0000755000175000017500000000000012677434535020567 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/test.go0000644000175000017500000000017712677434535022102 0ustar onuronur// Package testdata is dummy data for gocode completion test. package testdata import ( "log" ) func Hello() { log.Logge } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/test2.go0000644000175000017500000000045312677434535022161 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+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/gocode_output_offset_121.json0000644000175000017500000000044712677434535026300 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+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/goto.go0000644000175000017500000000010312677434535022060 0ustar onuronurpackage main func dummy() { } func main() { dummy() //GoTo }ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/gocode_output_offset_292.json0000644000175000017500000000010312677434535026276 0ustar onuronur[5, [{"class": "func", "name": "Prefix", "type": "func() string"}]]ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/gocode_dontpanic_output_offset_10.json0000644000175000017500000000007312677434535030247 0ustar onuronur[0, [{"class": "PANIC", "name": "PANIC", "type": "PANIC"}]]ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/win.go0000644000175000017500000000007212677434535021712 0ustar onuronurpackage main func foo() {} func main() { foo() } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/dontpanic.go0000644000175000017500000000052312677434535023075 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+20160327+gitc3e6904.orig/ycmd/tests/go/testdata/gocode_output_offset_215.json0000644000175000017500000000035112677434535026276 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+20160327+gitc3e6904.orig/ycmd/tests/go/get_completions_test.py0000644000175000017500000000333612677434535023567 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, has_item 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' ) ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/__init__.py0000644000175000017500000000433112677434535021070 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 BuildRequest, 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 StopGoCodeServer( app ): app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'StopServer' ], filetype = 'go' ) ) 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 tearDownPackage(): global shared_app StopGoCodeServer( shared_app ) 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 ): return test( shared_app, *args, **kwargs ) return Wrapper ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/go_completer_test.py0000644000175000017500000001506312677434535023053 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 import os from nose.tools import eq_, raises from ycmd.completers.go.go_completer import GoCompleter, GO_BINARIES, FindBinary from ycmd.request_wrap import RequestWrap from ycmd import user_options_store from ycmd.utils import ReadFile 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' ] } } } class GoCompleter_test( object ): def setUp( self ): user_options = user_options_store.DefaultOptions() user_options[ 'gocode_binary_path' ] = DUMMY_BINARY self._completer = GoCompleter( user_options ) def _BuildRequest( self, line_num, column_num ): request = REQUEST_DATA.copy() request[ 'column_num' ] = column_num request[ 'line_num' ] = line_num request[ 'file_data' ][ PATH_TO_TEST_FILE ][ 'contents' ] = ReadFile( PATH_TO_TEST_FILE ) return RequestWrap( request ) def FindGoCodeBinary_test( self ): 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 ) ) # Test line-col to offset in the file before any unicode occurrences. def ComputeCandidatesInnerOffsetBeforeUnicode_test( self ): mock = MockPopen( returncode = 0, stdout = ReadFile( PATH_TO_POS121_RES ), stderr = '' ) self._completer._popener = mock # Col 8 corresponds to cursor at log.Pr^int("Line 7 ... self._completer.ComputeCandidatesInner( self._BuildRequest( 7, 8 ) ) eq_( mock.cmd, [ DUMMY_BINARY, '-f=json', 'autocomplete', PATH_TO_TEST_FILE, '121' ] ) # Test line-col to offset in the file after a unicode occurrences. def ComputeCandidatesInnerAfterUnicode_test( self ): mock = MockPopen( returncode = 0, stdout = ReadFile( PATH_TO_POS215_RES ), stderr = '' ) self._completer._popener = mock # Col 9 corresponds to cursor at log.Pri^nt("Line 7 ... self._completer.ComputeCandidatesInner(self._BuildRequest(9, 9)) eq_( mock.cmd, [ DUMMY_BINARY, '-f=json', 'autocomplete', PATH_TO_TEST_FILE, '215' ] ) # Test end to end parsing of completed results. def ComputeCandidatesInner_test( self ): mock = MockPopen( returncode = 0, stdout = ReadFile( PATH_TO_POS292_RES ), stderr = '' ) self._completer._popener = mock # Col 40 corresponds to cursor at ..., log.Prefi^x ... result = self._completer.ComputeCandidatesInner( self._BuildRequest( 10, 40 ) ) eq_( mock.cmd, [ DUMMY_BINARY, '-f=json', 'autocomplete', PATH_TO_TEST_FILE, '292' ] ) 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. @raises( RuntimeError ) def ComputeCandidatesInnerGoCodeFailure_test( self ): mock = MockPopen( returncode = 1, stdout = '', stderr = '' ) self._completer._popener = mock self._completer.ComputeCandidatesInner( self._BuildRequest( 1, 1 ) ) # Test JSON parsing failure. @raises( RuntimeError ) def ComputeCandidatesInnerParseFailure_test( self ): mock = MockPopen( returncode = 0, stdout = "{this isn't parseable", stderr = '' ) self._completer._popener = mock self._completer.ComputeCandidatesInner( self._BuildRequest( 1, 1 ) ) # Test empty results error (different than no results). @raises( RuntimeError ) def ComputeCandidatesInnerNoResultsFailure_test( self ): mock = MockPopen( returncode = 0, stdout = '[]', stderr = '' ) self._completer._popener = mock self._completer.ComputeCandidatesInner( self._BuildRequest( 1, 1 ) ) # Test empty results error (different than no results). @raises( RuntimeError ) def ComputeCandidatesGoCodePanic_test( self ): mock = MockPopen( returncode = 0, stdout = ReadFile( PATH_TO_PANIC_OUTPUT_RES ), stderr = '' ) self._completer._popener = mock self._completer.ComputeCandidatesInner( self._BuildRequest( 1, 1 ) ) class MockSubprocess( object ): def __init__( self, returncode, stdout, stderr ): self.returncode = returncode self.stdout = stdout self.stderr = stderr def communicate( self, stdin ): self.stdin = stdin return ( self.stdout, self.stderr ) class MockPopen( object ): def __init__( self, returncode = None, stdout = None, stderr = None ): self._returncode = returncode self._stdout = stdout self._stderr = stderr # cmd will be populated when a subprocess is created. self.cmd = None def __call__( self, cmd, stdout = None, stderr = None, stdin = None ): self.cmd = cmd return MockSubprocess( self._returncode, self._stdout, self._stderr ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/go/subcommands_test.py0000644000175000017500000000511312677434535022702 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 nose.tools import eq_ from ycmd.tests.go import PathToTestFile, SharedYcmd from ycmd.tests.test_utils import BuildRequest from ycmd.utils import ReadFile @SharedYcmd def RunGoToTest( app, params ): filepath = PathToTestFile( 'goto.go' ) contents = ReadFile( filepath ) command = params[ 'command' ] goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ command ], line_num = 8, column_num = 8, contents = contents, filetype = 'go', filepath = filepath ) results = app.post_json( '/run_completer_command', goto_data ) eq_( { 'line_num': 3, 'column_num': 6, 'filepath': filepath }, results.json ) filepath = PathToTestFile( 'win.go' ) contents = ReadFile( filepath ) command = params[ 'command' ] goto_data = BuildRequest( completer_target = 'filetype_default', command_arguments = [ command ], line_num = 4, column_num = 7, contents = contents, filetype = 'go', filepath = filepath ) results = app.post_json( '/run_completer_command', goto_data ) eq_( { 'line_num': 2, 'column_num': 6, 'filepath': filepath }, results.json ) def Subcommands_GoTo_all_test(): tests = [ { 'command': 'GoTo' }, { 'command': 'GoToDefinition' }, { 'command': 'GoToDeclaration' } ] for test in tests: yield RunGoToTest, test ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/identifier_completer_test.py0000644000175000017500000001113012677434535024152 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 nose.tools import eq_ from ycmd.completers.all import identifier_completer as ic from ycmd.request_wrap import RequestWrap 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_ColumnInMiddleStillWholeIdent_test(): eq_( 'foobar', ic._PreviousIdentifier( 2, BuildRequestWrap( 'foobar', 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 ) ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/0000755000175000017500000000000012677434535016756 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/0000755000175000017500000000000012677434535020567 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/0000755000175000017500000000000012677434535021737 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/GotoTestCase.cs0000644000175000017500000000146112677434535024634 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/testy.userprefs0000644000175000017500000000100212677434535025040 0ustar onuronur ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/GetTypeTestCase.cs0000644000175000017500000000034612677434535025306 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/GetDocTestCase.cs0000644000175000017500000000155212677434535025072 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/Properties/0000755000175000017500000000000012677434535024073 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/Properties/AssemblyInfo.cs0000644000175000017500000000172512677434535027022 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/testy.sln0000644000175000017500000000150412677434535023625 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/Program.cs0000644000175000017500000000021012677434535023666 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { int 九 = 9; Console. } } } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/ImportTest.cs0000644000175000017500000000020012677434535024370 0ustar onuronurusing System; namespace testy { public class ImportTest { public static void Main (string[] args) { new Date } } } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/ContinuousTest.cs0000644000175000017500000000021512677434535025272 0ustar onuronurusing System; namespace testy { public class ContinuousTest { public static void Main (string[] args) { var test = String } } } ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/FixItTestCase.cs0000644000175000017500000000074512677434535024753 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy/testy.csproj0000644000175000017500000000352212677434535024333 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/0000755000175000017500000000000012677434535025625 5ustar onuronur././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000016600000000000011606 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/Properties/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172512677434535031542 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/Program.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017012677434535031533 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy/testy.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317112677434535031537 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/Properties/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172512677434535031542 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/Program.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017012677434535031533 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy/testy.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317112677434535031537 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/.ycm_extra_conf.pyycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000036712677434535031543 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-abs/testy2.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152012677434535031533 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy1.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152012677434535031533 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/Properties/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172512677434535031542 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/testy2.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000151212677434535031534 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/Program.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017012677434535031533 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy/testy.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317112677434535031537 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/.ycm_extra_conf.pyycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000010212677434535031526 0ustar onuronur def CSharpSolutionFile( path, **kwargs ): return "testy2.sln" ././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-rel/testy2.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152012677434535031533 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/testy2.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152012677434535031533 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000022700000000000011604 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/.ycm_extra_conf.pyycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000010212677434535031526 0ustar onuronur def CSharpSolutionFile( path, **kwargs ): return "nosuch.sln" ././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/Properties/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000755000175000017500000000000012677434535031533 5ustar onuronur././@LongLink0000644000000000000000000000023700000000000011605 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000172512677434535031542 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/Program.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000017012677434535031533 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy/testy.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000317112677434535031537 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-like-folder/extra-conf-bad/testy2.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-not-named-l0000644000175000017500000000152012677434535031533 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000012677434535031503 5ustar onuronur././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000012677434535031503 5ustar onuronur././@LongLink0000644000000000000000000000017500000000000011606 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/Properties/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000012677434535031503 5ustar onuronur././@LongLink0000644000000000000000000000021400000000000011600 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000172512677434535031512 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/Program.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000017012677434535031503 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy/testy.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000317112677434535031507 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000012677434535031503 5ustar onuronur././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/Properties/ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000755000175000017500000000000012677434535031503 5ustar onuronur././@LongLink0000644000000000000000000000022000000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000172512677434535031512 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/Program.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000017012677434535031503 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000020200000000000011575 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/not-testy/testy.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000317112677434535031507 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy2.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000152012677434535031503 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/testy.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000152012677434535031503 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-folder/solution-named-like-folder.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/testy-multiple-solutions/solution-named-like-0000644000175000017500000000152412677434535031507 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/0000755000175000017500000000000012677434535034706 5ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/Properties/0000755000175000017500000000000012677434535037042 5ustar onuronur././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/Properties/AssemblyInfo.csycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/Properties/0000644000175000017500000000172512677434535037051 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/a project.userprefsycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/a project.u0000644000175000017500000000100212677434535036734 0ustar onuronur ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/Program.cs0000644000175000017500000000017012677434535036642 0ustar onuronurusing System; namespace testy { class MainClass { public static void Main (string[] args) { Console. } } } ././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/a project.slnycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/a project.s0000644000175000017500000000152012677434535036737 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+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/a project.csprojycmd-0+20160327+gitc3e6904.orig/ycmd/tests/cs/testdata/неприличное слово/a project.c0000644000175000017500000000317512677434535036727 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+20160327+gitc3e6904.orig/ycmd/tests/cs/get_completions_test.py0000644000175000017500000004053512677434535023571 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, empty, greater_than, has_item, has_items, has_entries ) 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_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' ) exception_caught = False try: app.post_json( '/event_notification', event_data ) except AppError as e: if 'Autodetection of solution file failed' in str( e ): exception_caught = True # The test passes if we caught an exception when trying to start it, # so raise one if it managed to start if not exception_caught: WaitUntilOmniSharpServerReady( app, filepath ) StopOmniSharpServer( app, filepath ) raise Exception( '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+20160327+gitc3e6904.orig/ycmd/tests/cs/__init__.py0000644000175000017500000001170112677434535021067 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 import time from ycmd import handlers from ycmd.tests.test_utils import BuildRequest, SetUpApp 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 StartOmniSharpServer( app, filepath ): app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ "StartServer" ], filepath = filepath, filetype = 'cs' ) ) def StopOmniSharpServer( app, filepath ): app.post_json( '/run_completer_command', BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'StopServer' ], filepath = filepath, filetype = 'cs' ) ) def WaitUntilOmniSharpServerReady( app, filepath ): retries = 100 success = False # If running on Travis CI, keep trying forever. Travis will kill the worker # after 10 mins if nothing happens. while retries > 0 or OnTravis(): result = app.get( '/ready', { 'subserver': 'cs' } ).json if result: success = True break request = BuildRequest( completer_target = 'filetype_default', command_arguments = [ 'ServerIsRunning' ], filepath = filepath, filetype = 'cs' ) result = app.post_json( '/run_completer_command', request ).json if not result: raise RuntimeError( "OmniSharp failed during startup." ) time.sleep( 0.2 ) retries = retries - 1 if not success: raise RuntimeError( "Timeout waiting for OmniSharpServer" ) 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: StopOmniSharpServer( shared_app, filepath ) @contextmanager def WrapOmniSharpServer( app, filepath ): global shared_filepaths if filepath not in shared_filepaths: StartOmniSharpServer( app, filepath ) shared_filepaths.append( filepath ) WaitUntilOmniSharpServerReady( app, filepath ) 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 ): 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+20160327+gitc3e6904.orig/ycmd/tests/cs/diagnostics_test.py0000644000175000017500000001253712677434535022706 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_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+20160327+gitc3e6904.orig/ycmd/tests/cs/subcommands_test.py0000644000175000017500000004373212677434535022713 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 import re import os.path from ycmd.tests.cs import ( IsolatedYcmd, PathToTestFile, SharedYcmd, StopOmniSharpServer, WaitUntilOmniSharpServerReady, WrapOmniSharpServer ) from ycmd.tests.test_utils import BuildRequest, UserOption 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_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_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, expected_result ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) 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 ) eq_( expected_result, app.post_json( '/run_completer_command', fixit_data ).json ) @SharedYcmd def Subcommands_FixIt_RemoveSingleLine_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 11, 1, { u'fixits': [ { u'location': { u'line_num': 11, u'column_num': 1, u'filepath': filepath }, u'chunks': [ { u'replacement_text': '', u'range': { u'start': { u'line_num': 10, u'column_num': 20, u'filepath': filepath }, u'end': { u'line_num': 11, u'column_num': 30, u'filepath': filepath }, } } ] } ] } ) @SharedYcmd def Subcommands_FixIt_MultipleLines_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 19, 1, { u'fixits': [ { u'location': { u'line_num': 19, u'column_num': 1, u'filepath': filepath }, u'chunks': [ { u'replacement_text': "return On", u'range': { u'start': { u'line_num': 20, u'column_num': 13, u'filepath': filepath }, u'end': { u'line_num': 21, u'column_num': 35, u'filepath': filepath }, } } ] } ] } ) @SharedYcmd def Subcommands_FixIt_SpanFileEdge_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 1, 1, { u'fixits': [ { u'location': { u'line_num': 1, u'column_num': 1, u'filepath': filepath }, u'chunks': [ { u'replacement_text': 'System', u'range': { u'start': { u'line_num': 1, u'column_num': 7, u'filepath': filepath }, u'end': { u'line_num': 3, u'column_num': 18, u'filepath': filepath }, } } ] } ] } ) @SharedYcmd def Subcommands_FixIt_AddTextInLine_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 9, 1, { u'fixits': [ { u'location': { u'line_num': 9, u'column_num': 1, u'filepath': filepath }, u'chunks': [ { u'replacement_text': ', StringComparison.Ordinal', u'range': { u'start': { u'line_num': 9, u'column_num': 29, u'filepath': filepath }, u'end': { u'line_num': 9, u'column_num': 29, u'filepath': filepath }, } } ] } ] } ) @SharedYcmd def Subcommands_FixIt_ReplaceTextInLine_test( app ): filepath = PathToTestFile( 'testy', 'FixItTestCase.cs' ) RunFixItTest( app, 10, 1, { u'fixits': [ { u'location': { u'line_num': 10, u'column_num': 1, u'filepath': filepath }, u'chunks': [ { u'replacement_text': 'const int', u'range': { u'start': { u'line_num': 10, u'column_num': 13, u'filepath': filepath }, u'end': { u'line_num': 10, u'column_num': 16, u'filepath': filepath }, } } ] } ] } ) @IsolatedYcmd def Subcommands_StopServer_NoErrorIfNotStarted_test( app ): filepath = PathToTestFile( 'testy', 'GotoTestCase.cs' ) StopOmniSharpServer( app, 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 ) WaitUntilOmniSharpServerReady( app, filepath ) 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: StopOmniSharpServer( app, 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+20160327+gitc3e6904.orig/ycmd/tests/misc_handlers_test.py0000644000175000017500000000421412677434535022576 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 nose.tools import ok_ from hamcrest import assert_that, contains from ycmd.tests import 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' ) ok_( app.post_json( '/semantic_completion_available', request_data ).json ) @SharedYcmd def MiscHandlers_EventNotification_AlwaysJsonResponse_test( app ): event_data = BuildRequest( contents = 'foo foogoo ba', event_name = 'FileReadyToParse' ) app.post_json( '/event_notification', event_data ).json @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 ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/tests/hmac_utils_test.py0000644000175000017500000000517712677434535022124 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_, raises from ycmd import hmac_utils as hu from ycmd.tests.test_utils import Py2Only 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_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'goo' ) ) ) def SecureBytesEqual_Empty_test(): ok_( hu.SecureBytesEqual( bytes(), bytes() ) ) @raises( TypeError ) def SecureBytesEqual_ExceptionOnUnicode_test(): ok_( hu.SecureBytesEqual( u'foo', u'foo' ) ) @Py2Only @raises( TypeError ) def SecureBytesEqual_ExceptionOnPy2Str_test(): ok_( hu.SecureBytesEqual( 'foo', 'foo' ) ) ycmd-0+20160327+gitc3e6904.orig/ycmd/__init__.py0000644000175000017500000000000012677434535017306 0ustar onuronurycmd-0+20160327+gitc3e6904.orig/ycmd/handlers.py0000644000175000017500000002274712677434535017375 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 from os import path try: import ycm_core except ImportError as e: raise RuntimeError( 'Error importing ycm_core. Are you sure you have placed a ' 'version 3.2+ libclang.[so|dll|dylib] in folder "{0}"? ' 'See the Installation Guide in the docs. Full error: {1}'.format( path.realpath( path.join( path.abspath( __file__ ), '..', '..' ) ), str( e ) ) ) import atexit import logging import json import bottle import http.client import traceback from bottle import request from . import server_state from ycmd import user_options_store from ycmd.responses import BuildExceptionResponse, BuildCompletionResponse from ycmd import hmac_plugin from ycmd import extra_conf_store 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 = 1000 * 1024 _server_state = None _hmac_secret = bytes() _logger = logging.getLogger( __name__ ) app = bottle.Bottle() @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 ) @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' ] ) @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 ) ) # The type of the param is Bottle.HTTPError @app.error( http.client.INTERNAL_SERVER_ERROR ) def ErrorHandler( httperror ): body = _JsonResponse( BuildExceptionResponse( httperror.exception, httperror.traceback ) ) hmac_plugin.SetHmacHeader( body, _hmac_secret ) return body 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 ] ) @atexit.register def ServerShutdown(): _logger.info( 'Server shutting down' ) 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() ycmd-0+20160327+gitc3e6904.orig/ycmd/identifier_utils.py0000644000175000017500000001106312677434535021124 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 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: http://doc.perl6.org/language/syntax 'perl6': re.compile( r"[_a-zA-Z](?:\w|[-'](?=[_a-zA-Z]))*", re.UNICODE ), } 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' ] 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+20160327+gitc3e6904.orig/ycmd/user_options_store.py0000644000175000017500000000275412677434535021536 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+20160327+gitc3e6904.orig/ycmd/watchdog_plugin.py0000644000175000017500000000701412677434535020741 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 os import copy from ycmd import utils from threading import Thread, Lock # 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 = 60 * 10 ): 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): utils.TerminateProcess( os.getpid() ) self._UpdateLastWakeupTime() def __call__( self, callback ): def wrapper( *args, **kwargs ): self._SetLastRequestTime( time.time() ) return callback( *args, **kwargs ) return wrapper ycmd-0+20160327+gitc3e6904.orig/ycmd/bottle_utils.py0000644000175000017500000000345712677434535020303 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+20160327+gitc3e6904.orig/ycmd/request_validation.py0000644000175000017500000000506612677434535021472 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+20160327+gitc3e6904.orig/ycmd/utils.py0000644000175000017500000002446712677434535016736 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 PY2, native import tempfile import os import sys import signal import socket import stat import subprocess # 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 extensions used on Windows WIN_EXECUTABLE_EXTS = [ '.exe', '.bat', '.cmd' ] # Don't use this! Call PathToCreatedTempDir() instead. This exists for the sake # of tests. RAW_PATH_TO_TEMP_DIR = os.path.join( tempfile.gettempdir(), 'ycm_temp' ) # Readable, writable and executable by everyone. ACCESSIBLE_TO_ALL_MASK = ( stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP ) # 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.) return open( filepath, 'wb' if PY2 else 'w' ) # 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 ) # 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 PathToCreatedTempDir( tempdir = RAW_PATH_TO_TEMP_DIR ): try: os.makedirs( tempdir ) # Needed to support multiple users working on the same machine; # see issue 606. MakeFolderAccessibleToAll( tempdir ) except OSError: # Folder already exists, skip folder creation. pass return tempdir def MakeFolderAccessibleToAll( path_to_folder ): current_stat = os.stat( path_to_folder ) flags = current_stat.st_mode | ACCESSIBLE_TO_ALL_MASK os.chmod( path_to_folder, flags ) 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 # 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 ): 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 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 OnTravis(): return 'TRAVIS' in os.environ def ProcessIsRunning( handle ): return handle is not None and handle.poll() is None # 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 ) 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() ycmd-0+20160327+gitc3e6904.orig/ycmd/request_wrap.py0000644000175000017500000000751612677434535020313 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.utils import ToUnicode, ToBytes 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 = { 'line_value': self._CurrentLine, 'start_column': self.CompletionStartColumn, 'query': self._Query, 'filetypes': self._Filetypes, } 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' ] # Handling ''.splitlines() returning [] instead of [''] if contents is not None and len( contents ) == 0: return '' return contents.splitlines()[ self._request[ 'line_num' ] - 1 ] def CompletionStartColumn( self ): try: filetype = self[ 'filetypes' ][ 0 ] except (KeyError, IndexError): filetype = None return CompletionStartColumn( self[ 'line_value' ], self[ 'column_num' ], filetype ) def _Query( self ): return self[ 'line_value' ][ self[ 'start_column' ] - 1 : self[ 'column_num' ] - 1 ] def _Filetypes( self ): path = self[ 'filepath' ] return self[ 'file_data' ][ path ][ 'filetypes' ] def CompletionStartColumn( line_value, column_num, filetype ): """Returns the 1-based 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: column_num and other numbers on the wire are byte indices, but we need # to walk codepoints for identifier checks. utf8_line_value = ToBytes( line_value ) unicode_line_value = ToUnicode( line_value ) codepoint_column_num = len( str( utf8_line_value[ : column_num - 1 ], 'utf8' ) ) + 1 # -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 len( unicode_line_value[ : codepoint_start_column - 1 ].encode( 'utf8' ) ) + 1 ycmd-0+20160327+gitc3e6904.orig/ycmd/server_utils.py0000644000175000017500000000652512677434535020317 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 sys import os import io VERSION_FILENAME = 'CORE_VERSION' CORE_NOT_COMPATIBLE_MESSAGE = ( 'ycmd can\'t run: ycm_core lib too old, PLEASE RECOMPILE' ) DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) ) def SetUpPythonPath(): sys.path.insert( 0, os.path.join( DIR_OF_CURRENT_SCRIPT, '..' ) ) AddNearestThirdPartyFoldersToSysPath( __file__ ) 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 CompatibleWithCurrentCoreVersion(): import ycm_core try: current_core_version = ycm_core.YcmCoreVersion() except AttributeError: return False return ExpectedCoreVersion() == current_core_version 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 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. So to work around issues, we place the python-future last on # sys.path so that they can be overriden by the standard library. if folder == 'python-future': folder = os.path.join( folder, 'src' ) sys.path.append( 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+20160327+gitc3e6904.orig/ycmd/hmac_plugin.py0000644000175000017500000000654512677434535020061 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 http.client 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( http.client.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( http.client.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+20160327+gitc3e6904.orig/ycmd/extra_conf_store.py0000644000175000017500000001515312677434535021132 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 . # 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 # 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 ): logger = _Logger() 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 ' + function_name ) return module = Load( global_ycm_extra_conf, force = True ) if not module or not hasattr( module, function_name ): logger.debug( 'Global extra conf not loaded or no function ' + function_name ) return logger.info( 'Calling global extra conf method {0} on conf file {1}'.format( function_name, global_ycm_extra_conf ) ) getattr( module, function_name )() 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 if not force: with _module_for_module_file_lock: if module_file in _module_for_module_file: return _module_for_module_file[ module_file ] if 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() ) module = LoadPythonSource( _RandomName(), module_file ) 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' ) ) def _Logger(): return logging.getLogger( __name__ ) ycmd-0+20160327+gitc3e6904.orig/ycmd/default_settings.json0000644000175000017500000000217312677434535021451 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, "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+20160327+gitc3e6904.orig/ycmd/server_state.py0000644000175000017500000001126212677434535020271 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 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 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+20160327+gitc3e6904.orig/vagrant_bootstrap.sh0000644000175000017500000001076612677434535020360 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' ####################### # 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+20160327+gitc3e6904.orig/style_format.sh0000755000175000017500000000077512677434535017333 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+20160327+gitc3e6904.orig/test_requirements.txt0000644000175000017500000000032412677434535020575 0ustar onuronurflake8>=2.5.2 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 # This needs to be kept in sync with submodule checkout in third_party future==0.15.2