diff --git a/Dockerfile b/Dockerfile index 5db2460..cd36f9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -109,7 +109,7 @@ RUN curl -SL $DOTNET_SDK_DOWNLOAD_URL --output dotnet.tar.gz \ && ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet # build rtags -copy rtags /rtags/ -run cd /rtags && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 && make -j$(nproc) install -run rm -rf /rtags +copy rtags.zip / +run unzip rtags.zip && cd /rtags && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 && make -j$(nproc) install +run rm -rf rtags.zip rtags diff --git a/rtags.zip b/rtags.zip new file mode 100644 index 0000000..ee3517d Binary files /dev/null and b/rtags.zip differ diff --git a/rtags/.dir-locals.el b/rtags/.dir-locals.el deleted file mode 100644 index 98c6493..0000000 --- a/rtags/.dir-locals.el +++ /dev/null @@ -1,15 +0,0 @@ -;;; Directory Local Variables -;;; For more information see (info "(emacs) Directory Variables") - -((nil - (indent-tabs-mode)) - (c++-mode - (c-basic-offset . 4) - (indent-tabs-mode)) - (cmake-mode - (cmake-tab-width . 4) - (indent-tabs-mode)) - (python-mode - (python-indent-offset . 4) - (tab-width . 4) - (indent-tabs-mode))) diff --git a/rtags/.travis.yml b/rtags/.travis.yml deleted file mode 100644 index f81822f..0000000 --- a/rtags/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -# -# Available repositories are listed here: -# https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json -# - -language: cpp -sudo: required - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.9 - - python3-pip - - libcppunit-dev - -git: - depth: 3 - -matrix: - include: - - os: linux - compiler: g++ - dist: trusty - env: T=g++-linux COMPILER_VERSION=-4.9 - - os: osx - compiler: clang - env: T=clang-osx - -branches: - only: - - master - - develop - -script: ./scripts/travis.sh diff --git a/rtags/CMakeLists.txt b/rtags/CMakeLists.txt deleted file mode 100644 index ae18077..0000000 --- a/rtags/CMakeLists.txt +++ /dev/null @@ -1,106 +0,0 @@ -cmake_minimum_required(VERSION 2.8.6) -project(rtags) -set(RTAGS_VERSION_MAJOR 2) -set(RTAGS_VERSION_MINOR 18) -set(RTAGS_VERSION_DATABASE 125) -set(RTAGS_VERSION_SOURCES_FILE 14) -set(RTAGS_VERSION ${RTAGS_VERSION_MAJOR}.${RTAGS_VERSION_MINOR}.${RTAGS_VERSION_DATABASE}) - -set(RCT_WITH_TESTS ${BUILD_TESTING}) - -set(CMAKE_LEGACY_CYGWIN_WIN32 0) - -if (APPLE) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g") -else () - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ggdb") -endif () - -if (ASAN) - string(REPLACE "," ";" ASANS ${ASAN}) - foreach (SANITIZE ${ASANS}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${SANITIZE}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=${SANITIZE}") - endforeach () -endif () - -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING - "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) -endif() - -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_COMPILER_IS_CLANGCXX TRUE) -endif() - -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") - -include(FeatureSummary) -add_subdirectory(src) - -add_custom_target(man - COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen-man-pages.sh" "${PROJECT_BINARY_DIR}/bin" - DEPENDS man/man7/rdm.7 man/man7/rc.7) -add_dependencies(man rdm rc) - -if (EXISTS "rules.ninja") - add_custom_target(release COMMAND ${CMAKE_COMMAND} -GNinja -DCMAKE_BUILD_TYPE=Release . WORKING_DIRECTORY .) - add_custom_target(debug COMMAND ${CMAKE_COMMAND} -GNinja -DCMAKE_BUILD_TYPE=Debug . WORKING_DIRECTORY .) -else() - add_custom_target(release COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release . WORKING_DIRECTORY .) - add_custom_target(debug COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug . WORKING_DIRECTORY .) -endif() - -# Create uninstall script and target -configure_file("${CMAKE_MODULE_PATH}/Uninstall.cmake.in" "${CMAKE_BINARY_DIR}/Uninstall.cmake" IMMEDIATE @ONLY) -add_custom_target(uninstall ${CMAKE_COMMAND} -P "${CMAKE_BINARY_DIR}/Uninstall.cmake") - -if (RTAGS_ENABLE_DEV_OPTIONS) - set(CPACK_PACKAGE_INSTALL_DIRECTORY "RTAGS") - set(CPACK_PACKAGE_VENDOR "RTags") - set(CPACK_PACKAGE_CONTACT "http://rtags.net") - set(CPACK_PACKAGE_VERSION_MAJOR ${RTAGS_VERSION_MAJOR}) - set(CPACK_PACKAGE_VERSION_MINOR ${RTAGS_VERSION_MINOR}) - set(CPACK_PACKAGE_VERSION_DATABASE ${RTAGS_VERSION_DATABASE}) - set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") - set(CPACK_PACKAGE_VERSION "${RTAGS_VERSION}") - - if (NOT CPACK_GENERATOR) - set(CPACK_GENERATOR TGZ) - endif () - set(CPACK_SOURCE_PACKAGE_FILE_NAME "rtags-${RTAGS_VERSION_MAJOR}.${RTAGS_VERSION_MINOR}" - CACHE INTERNAL "tarball basename") - set(CPACK_SOURCE_GENERATOR ${CPACK_GENERATOR}) - - set(CPACK_SOURCE_IGNORE_FILES - "~$" - "\\\\.gitignore$" - "\\\\.gitmodules$" - "^${PROJECT_SOURCE_DIR}/.git/" - "^${PROJECT_SOURCE_DIR}/build/" - ) - - include(CPack) -endif () - -include(CTest) - -if (BUILD_TESTING) - find_package(Perl QUIET) - if(PERL_FOUND) - add_test(NAME SBRootTest COMMAND perl "${CMAKE_SOURCE_DIR}/tests/sbroot/sbroot_test.pl") - set_property(TEST SBRootTest PROPERTY ENVIRONMENT "RTAGS_BINARY_DIR=${CMAKE_BINARY_DIR}/bin") - else() - message(WARNING "Perl not found! Excluding sbroot test from tests.") - endif() - - find_program(NOSETEST NAMES nosetests nosetests-2.7 PATHS "$ENV{HOME}/.local/bin") - if (NOSETEST) - add_test(NAME nosetests COMMAND ${NOSETEST} -w ${CMAKE_SOURCE_DIR}/tests/automated --no-byte-compile -v) - set_property(TEST nosetests PROPERTY ENVIRONMENT "RTAGS_BINARY_DIR=${CMAKE_BINARY_DIR}/bin") - else() - message(WARNING "Nosetests executable not found! Excluding automated_tests from tests.") - endif () -endif () - -feature_summary(INCLUDE_QUIET_PACKAGES WHAT ALL) diff --git a/rtags/LICENSE.txt b/rtags/LICENSE.txt deleted file mode 100644 index a73e010..0000000 --- a/rtags/LICENSE.txt +++ /dev/null @@ -1,14 +0,0 @@ -Copyright (C) 2011-2016 Jan Erik Hanssen and Anders Bakken - -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 . diff --git a/rtags/README.org b/rtags/README.org deleted file mode 100644 index c2c329d..0000000 --- a/rtags/README.org +++ /dev/null @@ -1,1220 +0,0 @@ -#+OPTIONS: ^:nil - -#+html:
MELPA MELPA
-#+html:
rtagsac-rtagscompany-rtagsflycheck-rtagshelm-rtagsivy-rtags
MELPAMELPAMELPAMELPAMELPAMELPA
- -* Introduction -RTags is a client/server application that indexes C/C++ code and keeps a -persistent file-based database of references, declarations, definitions, -symbolnames etc. There's also limited support for ObjC/ObjC++. It allows you -to find symbols by name (including nested class and namespace scope). Most -importantly we give you proper follow-symbol and find-references support. We -also have neat little things like rename-symbol, integration with clang's -"fixits" (http://clang.llvm.org/diagnostics.html). We also integrate with -flymake using clang's vastly superior errors and warnings. Since RTags -constantly will reindex "dirty" files you get live updates of compiler errors -and warnings. Since we already know how to compile your sources we have a way -to quickly bring up the preprocessed output of the current source file in a -buffer. - -While existing taggers like gnu global, cscope, etags, ctags etc do a decent -job for C they often fall a little bit short for C++. With its incredible -lexical complexity, parsing C++ is an incredibly hard task and we make no -bones about the fact that the only reason we are able to improve on the -current tools is because of clang (http://clang.llvm.org/). RTags is named -RTags in recognition of Roberto Raggi on whose C++ parser we intended to base -this project but he assured us clang was the way to go. The name stuck though. - -* TLDR Quickstart -Build RTags - -#+BEGIN_SRC sh -git clone --recursive https://github.com/Andersbakken/rtags.git -cd rtags -cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 . -make -#+END_SRC - -Start the RTags daemon (=rdm=) - -#+BEGIN_SRC sh -./bin/rdm & -#+END_SRC - -Index the RTags project, and wait until =rdm= is silent - -#+BEGIN_SRC sh -./bin/rc -J . -#+END_SRC - -Open source file in =emacs= - -#+BEGIN_SRC sh -emacs +73:34 src/rdm.cpp -#+END_SRC - -Load =rtags.el= - -#+BEGIN_EXAMPLE -M-: (load-file "rtags.el") RET -#+END_EXAMPLE - -Insure =rc= can be found - -#+BEGIN_EXAMPLE -M-x set-variable RET rtags-path RET "../bin" RET -#+END_EXAMPLE - -Call =rtags-find-symbol-at-point= - -#+BEGIN_EXAMPLE -M-x rtags-find-symbol-at-point RET -#+END_EXAMPLE - -Your location is now on the definition of =Server::instance()= - -* Installing RTags -** Prerequisites -There are a few prerequisites you need to have in order to build RTags - -- =LLVM/Clang= >= 3.3 - - On Linux you may be able to use your distribution package manager to install - this. On OS X you can use Homebrew or possibly other package managers, - though see below for details if you plan to tag projects that use C++11 - features (such as RTags itself). Alternatively you can grab the sources from - [[http://llvm.org/releases/download.html][llvm.org]] and build it yourself. - -- =GCC/Clang= >= 4.9/3.3 - - A modern compiler to build RTags. RTags makes extensive use of C++11 - features such as variadic templates and threading utility classes from the - C++ standard library. - -- =cmake= >= 2.8 - - The meta-built system used by RTags. ------ -- =emacs= >= 24.3 is recommended - - RTags might very well work with much older =emacs= versions but the oldest - version we have tested with is 24.3. There's no particular effort made to - support older versions, but patches that make it work are welcome. Having - said that, completion ([[https://github.com/auto-complete/auto-complete][ac]], [[https://github.com/company-mode/company-mode][company]]) as well as [[https://github.com/flycheck/flycheck][Flycheck]] integration only - works, and has been tested with =emacs= >= 24.3. - - *NOTE:* Emacs is no real prerequisite. That implies you can compile RTags - without =emacs= installed. This may be of interest to you, if you want use - RTags as back-end for a different editor like vim, see section [[#support-for-other-editors][Support for - other editors]]. You explicitly can tell =cmake= to ignore the elisp files by - passing =-DRTAGS_NO_ELISP_FILES=1= to =cmake=. - -*** Optional -- =pkg-config= and =bash-completion= - - RTags comes with bash completion support. If you want the bash completion - files to be installed, you either have to make sure that =pkg-config= and - =bash-completion= package is installed or you can manually force the - installation by setting the variable =FORCE_BASH_COMPLETION_INSTALLATION= - to =TRUE= or =ON=. - - The default installation path is - =CMAKE_INSTALL_PREFIX/share/bash-completion/completions=. You can adjust the - path with the =cmake= variable =BASH_COMPLETION_COMPLETIONSDIR= - variable. However, if the bash completions files are not installed in the - default completion path, i.e. =/usr/share/bash-completion/completions= on - GNU/Linux, you have to make sure the RTags bash completion file gets - sourced to get completion support. - -- =lua= version >= 5.3 - - TODO(Andersbakken): Add some notes why we optionally require Lua, whats the - purpose of it. - - If your system does not provide a suitable version you can download Lua from - [[https://www.lua.org/download.html][here]]. We recommend downloading the pre-built binaries. If you have compiled - Lua from scratch (the build will only create an archive =liblua.a= and no - shared library) or you have installed the headers/library to a non standard - place you need to tell =cmake= where the headers/library is located. - - E.g. - #+BEGIN_SRC sh - cmake -DLUA_INCLUDE_DIR=/opt/lua/include -DLUA_LIBRARY=/opt/lua/lib/liblua.a - # or liblua53.so or liblua53.a if you have downloaded, e.g. lua-5.3.2 binaries - cmake -DLUA_INCLUDE_DIR=/opt/lua/include -DLUA_LIBRARY=/opt/lua/lib/liblua53.so - #+END_SRC - -- =ZLIB= - -- =OpenSSL= - -** C++11 on OS X - -If you plan to tag projects using C++11 features on OS X then you'll -need a libclang linked with LLVM's [[http://libcxx.llvm.org/][libc++]]. -For LLVM 3.9 the following works: - -#+BEGIN_SRC sh -brew install llvm --with-libcxx --with-clang --without-assertions --with-rtti -#+END_SRC - -Note that unless you link llvm -#+BEGIN_SRC sh -brew link llvm -#+END_SRC - -You'll likely have to tell cmake where to find llvm-config. - -E.g. - -#+BEGIN_SRC sh -$ PATH=/usr/local/Cellar/llvm/3.9.1/bin/:$PATH cmake /path/to/rtags -$ make -#+END_SRC - -or you can install clang and llvm from mac ports - -#+BEGIN_SRC sh -sudo port install clang-3.5 -#+END_SRC - -** Building RTags -- Get the code - - To build RTags, you need to checkout RTags and the repository's sub-modules, - this can be done in one step. After that, you need to run =cmake=, =make= and - =make install=, in that order. - - #+BEGIN_SRC sh - git clone --recursive https://github.com/Andersbakken/rtags.git - #+END_SRC - - You can also download the sources from here: - - https://andersbakken.github.io/rtags-releases/rtags-2.18.tar.bz2 - - or - - https://andersbakken.github.io/rtags-releases/rtags-2.18.tar.gz - -- Building RTags - - We recommend building in a separate directory to keep the build files separate - from the source, but you can run =cmake= in the source tree if you prefer. - - #+BEGIN_SRC sh - cd rtags - mkdir build - cd build - cmake .. - make - make install - #+END_SRC - - *TIP:* You can run =ccmake= (CMake with an ncurses UI) instead of =cmake= to - interactively configure the RTags build. - - Note that if you're trying to test RTags by indexing RTags' own - source code you shouldn't build it in /tmp/ since RTags will refuse - to index files in /tmp/ - - "make install" runs ctest by default. If you want to skip ctest during install, - you can pass -DSKIP_CTEST=True to cmake. - - #+BEGIN_SRC sh - cmake .. -DSKIP_CTEST=True - make - make install - #+END_SRC - -- Elpa - - You can install the elisp part of RTags using package.el if you add - melpa to your sources list. - - Once you have emacs installed from melpa you can use the elisp to - build the c++ parts of RTags. You still need to have a working - compiler, libclang and cmake installed. - - To use: - #+BEGIN_SRC elisp - M-x rtags-install - #+END_SRC - - You may have to set additional arguments to cmake for this - work. E.g. - - #+BEGIN_SRC elisp - M-: (rtags-install nil "-DLIBCLANG_LLVM_CONFIG_EXECUTABLE=/usr/local//Cellar/llvm/4.0.0/bin/llvm-config") - #+END_SRC - -* Finding clang -** Use Your System's version -Unless you define RTAGS_BUILD_CLANG in cmake (or configure), the build system will try to -locate the required llvm/clang libraries and options automatically from what is -installed on your system. - -RTags needs three pieces of information about =libclang=. All of these can be -provided to =cmake= by way of an environment variable or a =cmake= variable. If -not provided we will try to find =llvm-config= and interrogate it for the -information. You can tell RTags which =llvm-config= to use like this: - -#+BEGIN_SRC sh -LIBCLANG_LLVM_CONFIG_EXECUTABLE=/path/to/llvm-config cmake . -#+END_SRC - -or - -#+BEGIN_SRC sh -cmake -DLIBCLANG_LLVM_CONFIG_EXECUTABLE=/path/to/llvm-config . -#+END_SRC - -If you don't, we will look for variations of the =llvm-config= executable name -in your =$PATH=. If llvm is installed at a different place, you could set the -cmake variable =CMAKE_PREFIX_PATH= to the install prefix path of llvm. - -The three things we need are: - -1. =LIBCLANG_CXXFLAGS= - - Usually something like this: - - #+BEGIN_SRC sh - $ llvm-config --cxxflags - # Max OS X - -I/usr/local/Cellar/llvm36/3.6.0/lib/llvm-3.6/include -DNDEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -O3 -std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-common -Woverloaded-virtual -Wcast-qual - # Fedora 23 64 bit - -I/usr/include -DNDEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -O3 -std=c++11 -fvisibility-inlines-hidden -fno-exceptions -fno-common -Woverloaded-virtual -Wcast-qual - #+END_SRC - -2. =LIBCLANG_LIBDIR= - - Usually something like this: - - #+BEGIN_SRC sh - $ llvm-config --libdir - # Mac OS X - /usr/local/Cellar/llvm36/3.6.0/lib/llvm-3.6/lib - # Fedora 23 64 bit - /usr/lib64/llvm - #+END_SRC - - We need this to locate clang's system headers, and we will assume that they - are located in: =${LIBCLANG_LIBDIR}/clang/CLANG_VERSION_STRING/include - (/usr/local/Cellar/llvm36/3.6.0/lib/llvm-3.6/lib/clang/3.6.0/include)=. There - should be headers like stdarg.h and limits.h in this directory. - -3. =LIBCLANG_LIBRARIES= - - Usually something like this: - - #+BEGIN_EXAMPLE - # Mac OS X - /usr/local/Cellar/llvm36/3.6.0/lib/llvm-3.6/lib/libclang.so - # Fedora 23 64 bit - /usr/lib64/llvm/libclang.so - #+END_EXAMPLE - - Unless otherwise specified, we will try to find the clang library using - =cmake='s =find_library= feature and/or assuming that they there will be a - libclang.(so|dylib) in =${LIBCLANG_LIBDIR}= - -Like with =LIBCLANG_LLVM_CONFIG_EXECUTABLE= these variables can be overwritten -as a =cmake= variable =(cmake -DLIBCLANG_LIBDIR =...)= or an environment variable -=(LIBCLANG_LIBDIR =... cmake)= - -** Let the Build System Download and Compile LLVM/Clang -By default, cmake searches for a system libclang. If you want it to -download and build the required llvm/clang libraries, either call -cmake with -DRTAGS_BUILD_CLANG=1 or configure with --build-clang - -Note that if you use ninja to build RTags you might run into the -following error: - -#+BEGIN_SRC sh -ninja: error: '/usr/local/rtags-llvmclang/lib/libclang.dylib', needed by 'bin/rdm', missing and no known rule to make it -#+END_SRC - -In that case you need to do this: - -#+BEGIN_SRC sh -ninja llvmclang && ninja && ninja install -#+END_SRC - -* Setup - -=rdm= runs in the background and monitors all your indexed files for changes, -and reindexes when a source file or one of its dependencies is modified. Since -clang is a fully compliant compiler it needs specific information about how -your sources are compiled to be able to properly index them. This is done -through telling =rdm= about the compile line like this: - -#+BEGIN_SRC sh -rc -c gcc -I... -fsomeflag -c foobar.c -rc -J /path/to/a/directory/containing/compile_commands.json -#+END_SRC sh - -You can generate a compile_commands.json with various different tools, one -might fit better than the other, depending on your project build system. - -- [[https://ninja-build.org/manual.html][ninja]] - - #+begin_src sh - ninja -t compdb cxx cc > compile_commands.json - rc -J - #+end_src - - With =ninja= it's also possible to pipe the commands directly to =rc=. - - #+BEGIN_SRC sh - ninja -t commands | rc -c - - # Parse commands for a specific target only - ninja -t commands rdm | rc -c - - #+END_SRC - -- =cmake= - - =cmake= can generate a compile_commands.json file as well. - - #+BEGIN_SRC sh - cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 . - rc -J - #+END_SRC - -- [[https://github.com/rizsotto/Bear][Bear]] - - For other projects you can use =bear= to generate a compile_commands.json - file. However, if you are cross-compiling you probably need to adjust the - command entries in the compile_commands.json file to match the correct - compiler. Furthermore, make sure you clean your project before invoking - =bear=. - - #+BEGIN_SRC sh - make clean - bear make - rc -J - # Parse commands for a specific target only - make clean - bear make rdm - rc -J - #+END_SRC - -- =make= - - You can ask =make= to only print the recipes without actually doing something. - This way may be perfectly fine for not too complex Makefiles. - - #+BEGIN_SRC sh - make clean - make -nk | rc -c - - #+END_SRC - - There are very likely similar things you can do with other build systems that - we're unfamiliar with, please let us know if you do. - -- A different approach to get your files indexed is the man-in-the-middle - - This can be done like this: - - #+BEGIN_SRC sh - ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/gcc - ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/c++ - ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/cc - ln -s /path/to/rtags/bin/gcc-rtags-wrapper.sh /somewhere/that/is/in/your/path/before/usr/bin/g++ -#+END_SRC - - E.g. - - #+BEGIN_EXAMPLE - $ which -a gcc | xargs file - /home/abakken/bin/gcc: symbolic link to `/home/abakken/dev/rtags/bin/gcc-rtags-wrapper.sh' - /usr/bin/gcc: symbolic link to `gcc-4.7' - #+END_EXAMPLE - - Now every time you compile a file with =which gcc= =rc= will get its grubby - hands all over your command line and make sure RTags knows about it. - -RTags will group source files into projects based on some heuristics. - -Essentially it will look for certain files/dirs (like -configure/CMakeLists.txt/scons.1/.git) etc to try to determine the likely -project root for each source file. For generated source files that end up in -the build directory we try to find the source root based on similar heuristics -around config.status/CMakeCache.txt etc. Usually this works out reasonably -well. If it doesn't for you, you can pass =--project-root -/path/to/the/project/root= to =rc=. - -RTags only gives you information about current project when you ask -for things by name. You can explicitly change the current project using: - -#+BEGIN_SRC sh -rc -w foobar -#+END_SRC - -We try to do it automatically for you by passing along information about the -current buffer when we call =rc= from elisp so that =rdm= can update its -current project on demand. - -RTags keeps a cache of indexed data so you don't have to reindex everything if -you restart it. - -The location of this data is by default =~/.rtags= but can be overridden by -passing =--data-dir /other/dir= to =rdm= or putting something like this in -your ~/.rdmrc: - -#+BEGIN_EXAMPLE -$ cat ~/.rdmrc ---data-dir=/other/dir -#+END_EXAMPLE - -** Integration with =launchd= /(Mac OS X)/ - -On Mac OS X, you can set =rdm= can be run on demand, on your behalf, by -=launchd=, and have it exit cleanly after a period of inactivity. The easiest -way to do this is with Homebrew: - -#+BEGIN_SRC -brew services start rtags -#+END_SRC - -You can also do it manually using the following steps: - -1. Create a file, e.g., in emacs, with the following contents: - - #+BEGIN_SRC xml - - - - - Label - com.andersbakken.rtags.agent - ProgramArguments - - sh - -c - $RDM -v --launchd --inactivity-timeout 300 --log-file ~/Library/Logs/rtags.launchd.log - - Sockets - - Listener - - SockPathName - $HOME/.rdm - - - - - #+END_SRC - -2. Replace =$HOME= with the absolute path to your home folder. Replace - =$RDM= with the path to your copy of =rdm=, and add any command line - parameters you might usually use. - - (The =SockPathName= entry relates to the name of the domain socket that - =rdm= uses. The settings above are for the default value; if your command - line options direct it to use some other name, please modify it to - suit. Unfortunately =launchd='s configuration files are a bit naff, so - you'll have to repeat yourself.) - -3. Save the result as - =~/Library/LaunchAgents/com.andersbakken.rtags.agent.plist=. - -4. Run the following command from the terminal: - - : launchctl load ~/Library/LaunchAgents/com.andersbakken.rtags.agent.plist - - (This will happen automatically next time you log back in.) - -5. Try using RTags, and you should find =rdm= will spring into life! - -*** Notes - -- =rdm= will automatically quit after 5 minutes of inactivity (this is - what the =--inactivity-timeout 300= command line option is for), so - it won't stick around hogging memory. But =launchd= will still be - watching its socket for activity, and will relaunch it if necessary. - -- You can watch =launchd='s logging by tailing - =~/Library/Logs/rtags.launchd.log=. - -** Integration with =systemd= /(GNU Linux)/ - -On GNU/Linux distributions based on the =systemd= service manager, =rdm= can -also be socket acivated. - - 1. Add the following to =~/.config/systemd/user/rdm.socket= - - #+BEGIN_EXAMPLE - [Unit] - Description=RTags daemon socket - - [Socket] - ListenStream=%t/rdm.socket - - [Install] - WantedBy=default.target - #+END_EXAMPLE - - 2. Add the following to =~/.config/systemd/user/rdm.service= - - #+BEGIN_EXAMPLE - [Unit] - Description=RTags daemon - - Requires=rdm.socket - - [Service] - Type=simple - ExecStart=$RDM -v --inactivity-timeout 300 --log-flush - ExecStartPost=/bin/sh -c "echo +19 > /proc/$MAINPID/autogroup" - Nice=19 - CPUSchedulingPolicy=idle - #+END_EXAMPLE - - 3. Replace =$RDM= with the path to your copy of =rdm=, and add any command - line parameters you might usually use. - - You have to use absolute paths here. =%h= is expanded to your home - directory. Environment variables are not expanded inside strings. - - 4. Run the following command from the terminal: - - #+BEGIN_SRC sh - systemctl --user enable rdm.socket - systemctl --user start rdm.socket - #+END_SRC - - =Systemd= will create the =rdm= socket automatically. - - Note that user level systemd does not work on RHEL - derivatives. See here for more info: https://bugs.centos.org/view.php?id=8767 - -If you prefer using SystemV something like this could be used: - -#+BEGIN_EXAMPLE - -#!/bin/bash -# -# chkconfig: 35 90 12 -# description: Foo server -# - -# Get function from functions library -. /etc/init.d/functions - -# Start the service FOO -start() { - initlog -c "echo -n Starting FOO server: " - /path/to/FOO & - ### Create the lock file ### - touch /var/lock/subsys/FOO - success $"FOO server startup" - echo -} - -# Restart the service FOO -stop() { - initlog -c "echo -n Stopping FOO server: " - killproc FOO - ### Now, delete the lock file ### - rm -f /var/lock/subsys/FOO - echo -} - -### main logic ### -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status FOO - ;; - restart|reload|condrestart) - stop - start - ;; - *) - echo $"Usage: $0 {start|stop|restart|reload|status}" - exit 1 -esac - -exit 0 - -#+END_EXAMPLE - -* Usage - -Now that your files are indexed you can start using RTags. Normally you -would do this from your editor but the way to extract this information from -=rdm= is to use the command line tool =rc=. - -E.g. - -#+BEGIN_EXAMPLE -$ rdm & -$ ninja -t commands | rc -c -$ rc --follow-location Job.cpp:20:10 -/home/abakken/dev/rtags/src/Job.h:10:18 List *mPathFiltersRegExp; -#+END_EXAMPLE - -A location has the format of file:line:column. - -For Emacs we maintain a set of elisp bindings that allows you to control RTags -from your editor. There are projects that provide integration for other -editors out there. - -Vim: https://github.com/lyuts/vim-rtags and https://github.com/shaneharper/vim-rtags - -Neovim: https://github.com/marxin/neo-rtags - -Sublime Text: https://github.com/rampage644/sublime-rtags - -Atom: https://github.com/artagnon/atomic-rtags, https://github.com/rajendrant/atom-rtags and https://github.com/sphaerophoria/atom-rtags-plus - -=rc= has a vast number of commands and options and we have written a -man page for it. Most users will have limited interest in ever calling them -manually and would rather just use the interactive elisp functions. - -* Elisp -** Functions - -#+BEGIN_SRC emacs-lisp -(rtags-start-process-unless-running) -#+END_SRC - -Start the =rdm= process unless the process is already running. You may create -hook to automatically call this function upon entering, e.g. c-mode or -c++mode. - -E.g. - -#+BEGIN_SRC emacs-lisp -(add-hook 'c-mode-hook 'rtags-start-process-unless-running) -(add-hook 'c++-mode-hook 'rtags-start-process-unless-running) -(add-hook 'objc-mode-hook 'rtags-start-process-unless-running) -#+END_SRC - -#+begin_src emacs-lisp -(rtags-restart-process) -#+end_src - -Restart the =rdm= process. - -#+BEGIN_SRC emacs-lisp -(rtags-find-symbol-at-point) -#+END_SRC - -Follow symbol under cursor. For references this goes to the definition (or -declaration if no definition is known of the symbol. For declarations it goes -to the definition and vice versa. For definitions of variables/parameters with -constructors it goes to the constructor in question. If you pass a prefix -argument, limit to current source file, if you pass a prefix argument and have -narrowed the current file, limit to the narrowed region. This prefix argument -is the same for: =rtags-find-references-at-point=, =rtags-find-symbol=, -=rtags-find-references= - -#+BEGIN_SRC emacs-lisp -(rtags-find-references-at-point) -#+END_SRC - -Find all references to symbol under cursor. If symbol is itself a reference it -will find all references to the referenced symbol - -#+BEGIN_SRC emacs-lisp -(rtags-find-symbol) -#+END_SRC - -Prompt for name of symbol to go to. Imagine the following code: - -#+BEGIN_SRC C++ - -namespace N -{ -class C -{ -public: - int func(int); -}; -}; - -using namespace N; -int C::func(int val) -{ - return val * 2; -} -#+END_SRC -int N::C::func(int) will now be accessible by the following names: -- func -- func(int) -- C::func(int) -- C::func -- N::C::func(int) -- N::C::func - -#+BEGIN_SRC emacs-lisp -(rtags-find-references) -#+END_SRC - -Prompt for name of symbol to find references to. Same as above but find -references to symbol rather than declarations and definitions. - -#+BEGIN_SRC emacs-lisp -(rtags-diagnostics) -#+END_SRC - -Start an async process in a buffer to receive warnings/errors from clang -whenever a file gets reindexed. It integrates with flymake to put highlighting -on code with warnings and errors - -#+BEGIN_SRC emacs-lisp -(rtags-enable-standard-keybindings) -#+END_SRC -Sets up a ton of standard keybindings under C-c r. If you pass a mode to the -function it will set it up on that mode, otherwise it will use -c-mode-base-map). You can choose a different prefix than C-c r like this: - -#+BEGIN_SRC emacs-lisp -(rtags-enable-standard-keybindings c-mode-base-map "\C-xr") -#+END_SRC - -#+BEGIN_SRC emacs-lisp -(rtags-find-file) -#+END_SRC - -Lets you jump to file by name (partial or full, concept kinda stolen from -gtags.el) with completion in the project. This includes all files under what -we determine to be the root of the project, not just source files. - -#+BEGIN_SRC emacs-lisp -(rtags-find-virtuals-at-point) -#+END_SRC -For virtual functions, show the various reimplementations of the function at -point - -#+BEGIN_SRC emacs-lisp -(rtags-fixit) -#+END_SRC -Apply clang's automatic fixits in current file. If you pass a prefix arg use -ediff to apply it. See (http://clang.llvm.org/diagnostics.html) for more info. - -#+BEGIN_SRC emacs-lisp -(rtags-imenu) -#+END_SRC -Provides an ido-based imenu like interface to a subset of the symbols in the -current file. Note that it does not actually use imenu infrastructure. - -#+BEGIN_SRC emacs-lisp -(rtags-location-stack-back) -(rtags-location-stack-forward) -#+END_SRC - -Whenever RTags jumps somewhere it pushes a location onto its stack. Jump back -and forward in this stack - -#+BEGIN_SRC emacs-lisp -(rtags-next-match) -(rtags-previous-match) -#+END_SRC - -For functions that return more than one match, jump to the next/previous one. - -#+BEGIN_SRC emacs-lisp -(rtags-preprocess-file) -#+END_SRC - -Preprocess current file according to known C(XX)Flags and show the result in a -buffer. If region is active only display the preprocessed output for that -region. - -#+BEGIN_SRC emacs-lisp -(rtags-print-symbol-info) -#+END_SRC - -Print some info about symbol under cursor - -#+BEGIN_SRC emacs-lisp -(rtags-symbol-type) -#+END_SRC - -Print the type of the symbol under cursor. - -#+BEGIN_SRC emacs-lisp -(rtags-print-dependencies) -#+END_SRC - -Open a buffer showing files that depend on current file/files that current -file depends on. - -#+BEGIN_SRC emacs-lisp -(rtags-print-enum-value-at-point) -#+END_SRC - -Print integral value of enum value at point - -#+BEGIN_SRC emacs-lisp -(rtags-quit-rdm) -#+END_SRC - -Shut down =rdm= - -#+BEGIN_SRC emacs-lisp -(rtags-rename-symbol) -#+END_SRC - -Rename symbol under cursor. Make sure all files are saved and fully indexed -before using. - -#+BEGIN_SRC emacs-lisp -(rtags-reparse-file) -#+END_SRC - -Explicitly trigger a reparse of current file. Mostly for debugging. Unless we -have bugs it should not be necessary. - -#+BEGIN_SRC emacs-lisp -(rtags-show-rtags-buffer) -#+END_SRC - -Switch to =*RTags*= buffer. This is the buffer where a number of functions -display their alternatives when they have more than one match. - -#+BEGIN_SRC emacs-lisp -(rtags-include-file) -#+END_SRC - -Insert selected or entered include, e.g. "string.h"/ in current -buffer, either at the top, after the first include statement or with prefix -argument (=C-u=) at current point. - -#+BEGIN_SRC emacs-lisp -(rtags-get-include-file-for-symbol) -#+END_SRC - -Insert include for entered symbol or symbol under courser in current buffer, -either at the top, after the first include statement or with prefix argument -(=C-u=) at current point. - -** Variables - -#+BEGIN_SRC emacs-lisp -rtags-path -#+END_SRC - -Path to =rc/rdm= if they're not in =$PATH=. - -#+BEGIN_SRC emacs-lisp -rtags-jump-to-first-match -#+END_SRC - -Similar to =compilation-auto-jump-to-first-error=. Whether to jump to the -first match automatically when there's more than one. - -#+BEGIN_SRC emacs-lisp -rtags-find-file-case-insensitive -#+END_SRC - -Whether to match files case-insensitively - -#+BEGIN_SRC emacs-lisp -rtags-find-file-prefer-exact-match -#+END_SRC - -Whether to exclude partial matches for file names when an exact match is -found. E.g. =/foobar.cpp= =/bar.cpp= If =rtags-find-file-prefer-exact-match= -is =t= a query for =bar.cpp= would only return =/bar.cpp=, otherwise both -=foobar.cpp= and =bar.cpp= would be returned. - -** Fall back to other taggers -You can do something like the following to fall back to e.g. gtags -if RTags doesn't have a certain project indexed: - -#+BEGIN_SRC emacs-lisp -(defun use-rtags (&optional useFileManager) - (and (rtags-executable-find "rc") - (cond ((not (gtags-get-rootpath)) t) - ((and (not (eq major-mode 'c++-mode)) - (not (eq major-mode 'c-mode))) (rtags-has-filemanager)) - (useFileManager (rtags-has-filemanager)) - (t (rtags-is-indexed))))) - -(defun tags-find-symbol-at-point (&optional prefix) - (interactive "P") - (if (and (not (rtags-find-symbol-at-point prefix)) rtags-last-request-not-indexed) - (gtags-find-tag))) -(defun tags-find-references-at-point (&optional prefix) - (interactive "P") - (if (and (not (rtags-find-references-at-point prefix)) rtags-last-request-not-indexed) - (gtags-find-rtag))) -(defun tags-find-symbol () - (interactive) - (call-interactively (if (use-rtags) 'rtags-find-symbol 'gtags-find-symbol))) -(defun tags-find-references () - (interactive) - (call-interactively (if (use-rtags) 'rtags-find-references 'gtags-find-rtag))) -(defun tags-find-file () - (interactive) - (call-interactively (if (use-rtags t) 'rtags-find-file 'gtags-find-file))) -(defun tags-imenu () - (interactive) - (call-interactively (if (use-rtags t) 'rtags-imenu 'idomenu))) - -(define-key c-mode-base-map (kbd "M-.") (function tags-find-symbol-at-point)) -(define-key c-mode-base-map (kbd "M-,") (function tags-find-references-at-point)) -(define-key c-mode-base-map (kbd "M-;") (function tags-find-file)) -(define-key c-mode-base-map (kbd "C-.") (function tags-find-symbol)) -(define-key c-mode-base-map (kbd "C-,") (function tags-find-references)) -(define-key c-mode-base-map (kbd "C-<") (function rtags-find-virtuals-at-point)) -(define-key c-mode-base-map (kbd "M-i") (function tags-imenu)) - -(define-key global-map (kbd "M-.") (function tags-find-symbol-at-point)) -(define-key global-map (kbd "M-,") (function tags-find-references-at-point)) -(define-key global-map (kbd "M-;") (function tags-find-file)) -(define-key global-map (kbd "C-.") (function tags-find-symbol)) -(define-key global-map (kbd "C-,") (function tags-find-references)) -(define-key global-map (kbd "C-<") (function rtags-find-virtuals-at-point)) -(define-key global-map (kbd "M-i") (function tags-imenu)) - -#+END_SRC - -* Code Completion in Emacs: -To enable code completion in Emacs with company mode do the following: - -- Enable rtags-diagnostics. The easiest way is to: - -#+BEGIN_SRC emacs-lisp -(setq rtags-autostart-diagnostics t) -#+END_SRC - -but you can also explicitly start it with - -#+BEGIN_EXAMPLE -M-x rtags-diagnostics -#+END_EXAMPLE - -- Enable completions in RTags: - -#+BEGIN_SRC emacs-lisp -(setq rtags-completions-enabled t) -#+END_SRC - -- Enable company-mode - -#+BEGIN_SRC emacs-lisp -(require 'company) -(global-company-mode) -#+END_SRC - -- Add company-rtags to company-backends: - -#+BEGIN_SRC emacs-lisp -(push 'company-rtags company-backends) -#+END_SRC - -This minimal init.el configuration should be enough to get completion to work. - -#+BEGIN_SRC emacs-lisp -(require 'package) -(package-initialize) -(require 'rtags) -(require 'company) - -(setq rtags-autostart-diagnostics t) -(rtags-diagnostics) -(setq rtags-completions-enabled t) -(push 'company-rtags company-backends) -(global-company-mode) -(define-key c-mode-base-map (kbd "") (function company-complete)) -#+END_SRC - -To enable completion in Emacs with auto-complete-mode do the following: -...TODO... -* RTags Flycheck integration -To turn on RTags Flycheck support you need to load the =flycheck-rtags= -package. - -#+BEGIN_SRC emacs-lisp -(require 'flycheck-rtags) -#+END_SRC - -** Optional -You may explicitly select the RTags Flycheck checker for some major modes for -better experience. - -At the moment there is no customize option available to choose between -=rtags-diagnostics= overlays or Flycheck overlays, nor is it planned right -now. -We recommend setting =flycheck-highlighting-mode= locally to =nil= as the -RTags overlays are more accurate. - -Further, Flycheck will trigger automatically, based on events, the syntax -checker for the current buffer, this is however, pretty useless in conjunction -with RTags. We trigger it manually because we find it gives you a better -experience. -To turn off the automatic Flycheck syntax checking, set the variable -=flycheck-check-syntax-automatically= locally to =nil=. - -#+BEGIN_SRC emacs-lisp -(defun my-flycheck-rtags-setup () - (flycheck-select-checker 'rtags) - (setq-local flycheck-highlighting-mode nil) ;; RTags creates more accurate overlays. - (setq-local flycheck-check-syntax-automatically nil)) -(add-hook 'c-mode-hook #'my-flycheck-rtags-setup) -(add-hook 'c++-mode-hook #'my-flycheck-rtags-setup) -(add-hook 'objc-mode-hook #'my-flycheck-rtags-setup) -#+END_SRC - -* Helm integration -You can use Helm to view the result, to do so, set -=rtags-display-result-backend= to =helm=. You don't need to load =helm-rtags=, -we do it. If you have installed *RTags* through MELPA you need to install -=helm-rtags=. - -#+BEGIN_SRC emacs-lisp -(setq rtags-display-result-backend 'helm) -#+END_SRC - -* Ivy integration -You can use Ivy to view the result, to do so, set -=rtags-display-result-backend= to =ivy=. You don't need to load =ivy-rtags=, -we do it. If you have installed *RTags* through MELPA you need to install -=ivy-rtags=. - -#+BEGIN_SRC emacs-lisp -(setq rtags-display-result-backend 'ivy) -#+END_SRC - -* Videos -Here are some videos demonstrating how to use RTags with Emacs though some of -these may be outdated: - -[[http://www.youtube.com/watch?v=Z4g05SjkQzM&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=10][Set up RTags]] - -[[http://www.youtube.com/watch?v=J2B-z0LBL_s&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=6][Set up symlinks and run the daemon]] - -[[http://www.youtube.com/watch?v=bD6Rlycn1RU&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=5][Project setup using make]] - -[[http://www.youtube.com/watch?v=Zivoc5DH_II&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=9][Project setup using ninja]] - -[[http://www.youtube.com/watch?v=IfenCEuOqOs&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=2][Navigation/references]] - -[[http://www.youtube.com/watch?v=wVoaE3Pj4oU&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=1][Fixits]] - -[[http://www.youtube.com/watch?v=mnQPz5J7gN0&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=3]["IMenu" / virtuals / filenames]] - -[[http://www.youtube.com/watch?v=p6JHriYmVuY&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=4][Rename symbol]] - -[[http://www.youtube.com/watch?v=9CsoJTs58q8&list=PLAL6K6Ycnt4IwjIjWcYV9bFgcTG_4T1Y_&index=8][Enums and cursor info]] - -* Debugging RTags -If you find that =rp= is crashing (leading to output like this: "job crashed -191 9698036154370 0x331e7e30"). You should be able to do the following: - -#+BEGIN_SRC sh -rdm --suspend-rp-on-crash -#+END_SRC - -When =rp= crashes the =rp= process will stay alive, enabling you to debug it -with something like this: - -#+BEGIN_SRC sh -gdb -p `pidof rp` -#+END_SRC - -* Support for other editors -There are several other projects integrating RTags with other editors. - -Sublime Text: -https://github.com/rampage644/sublime-rtags - -Vim: -https://github.com/lyuts/vim-rtags -https://github.com/shaneharper/vim-rtags -https://github.com/mattn/vim-rtags - -Neovim: -https://github.com/marxin/neo-rtags - -Note to those maintainers. If you need RTags to behave differently or add -features to make these other integration's easier (like produce output in -other formats etc), just drop us a note. -* Coding style - We are always excited to accept bug fixes, improvements and features - through code contributions. Feel free to send a pull request for - anything you think could be improved upon. - - We'd like contributions to adhere to our coding style. - - The coding style can kinda be deduced from this: - #+begin_src cpp - if (foo) { - while (!done) { - switch (value) { - case 1: - break; - case 2: { - int variable = 12; - break; } - case 3: - break; - } - } - for (auto foo : vars) { - - } - } - - void test(const std::string &bar); - - class Foo - { - private: - int mPrivateMember; - }; - - struct Bar - { - int publicMember; - }; - - class A - { - public: - A(int val); - private: - int mValue; - }; - - A::A(int val) - : mValue(val) - { - } - - conn->setErrorHandler([](const SocketClient::SharedPtr &, Message::MessageError &&error) { - if (error.type == Message::Message_VersionError) { - ::error("Wrong version marker. You're probably using mismatched versions of rc and rdm"); - } else { - logDirect(LogLevel::Error, error.text); - } - }); - -#+end_src - -* Unit tests - There are some tests available in ~tests~, and in - ~src/rct/tests~. The test target will be generated by default. You - can disable the generation of the test target by calling cmake like this: - - #+begin_src sh - cmake -DBUILD_TESTING=0 - #+end_src - - To run the tests, call =make= with the target =test=. - #+begin_src sh - make all test # Build the binaries first - #+end_src -* Disclaimer -RTags is still under development and is not the most stable piece of software -you'll ever find. We're constantly working to improve on it. diff --git a/rtags/bin/cc_prefix.sh b/rtags/bin/cc_prefix.sh deleted file mode 100755 index 8172dd8..0000000 --- a/rtags/bin/cc_prefix.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -[ -z "$RTAGS_DISABLED" ] && [ -x "$(which rc)" ] && rc --silent --compile "$@" & -[ "$RTAGS_RMAKE" ] && exit 1 -compiler="$1" -shift -$compiler "$@" -exit $? diff --git a/rtags/bin/gcc-rtags-hook.sh b/rtags/bin/gcc-rtags-hook.sh deleted file mode 100755 index 337d410..0000000 --- a/rtags/bin/gcc-rtags-hook.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if [ -z "$RTAGS_DISABLED" ] && [ -x "$(which rc)" ]; then - rc --silent --compile "$ICECC_CXX" "$@" & -fi - -[ "$RTAGS_RMAKE" ] && exit 1 -exit 0 diff --git a/rtags/bin/gcc-rtags-wrapper.sh b/rtags/bin/gcc-rtags-wrapper.sh deleted file mode 100755 index 60ec868..0000000 --- a/rtags/bin/gcc-rtags-wrapper.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -if [ "$RTAGS_GCC_WRAPPER" = "1" ]; then - echo 1>&2 "Recursive invocation of gcc-rtags-wrapper.sh detected" - exit 1 -fi - -# tup support - -function eliminateTupVariant -{ - topDir="$PWD" - while [ "$PWD" != / -a ! -e ../.tup -a ! -e .tup ]; do - cd .. - done - - if [ -e tup.config ]; then - configDir=$PWD - cd .. - echo "$PWD${topDir#$configDir}" - else - echo "$topDir" - fi -} - -pushd . >/dev/null -if pwd | grep --quiet /.tup/mnt/@tupjob-; then - # get out from the tup virtual filesystem - cd "/${PWD#*/.tup/mnt/@tupjob-*/}" - - # get out from the tup variant directory (if any) - cd "$(eliminateTupVariant)" -fi - -# tup support end - -rc=$(which rc) -for i in $(which -a "$(basename "$0")"); do - filename="$i" - max=10 - while [ $max -gt 0 -a -L "$filename" ]; do - max=$((max - 1)) - link=$(readlink "$filename") - if echo "$link" | grep --quiet "^/"; then - filename="$link" - else - filename="$(dirname $filename)/$link" - fi - done - - filename=$(basename "$filename") - if [ "$filename" != "gcc-rtags-wrapper.sh" ] && [ -z "$PLAST" -o "$filename" != "plastc" ]; then - [ -n "$RTAGS_SERVER_FILE" ] && RTAGS_ARGS="$RTAGS_ARGS -n$RTAGS_SERVER_FILE" - [ -n "$RTAGS_PROJECT" ] && RTAGS_ARGS="$RTAGS_ARGS --project-root=$RTAGS_PROJECT" - [ -z "$RTAGS_COMPILE_TIMEOUT" ] && RTAGS_COMPILE_TIMEOUT=3000 - - if [ -z "$RTAGS_DISABLED" ] && [ -x "$rc" ]; then - case $(basename "$i") in - mpicc) - cc=cc - flags="$(mpicc -show|cut -d ' ' -f 2-) -DMPICH_NO_ATTR_TYPE_TAGS" - ;; - mpicxx) - cc=c++ - flags="$(mpicxx -show|cut -d ' ' -f 2-) -DMPICH_NO_ATTR_TYPE_TAGS" - ;; - *) - cc="$i" - flags="" - ;; - esac - $rc --timeout=$RTAGS_COMPILE_TIMEOUT $RTAGS_ARGS --silent --compile "$cc" $flags "$@" & - disown &>/dev/null # rc might be finished by now and if so disown will yell at us - fi - [ "$RTAGS_RMAKE" ] && exit 0 - - export RTAGS_GCC_WRAPPER=1 - popd >/dev/null - "$i" "$@" - exit $? - else - PATH="$(echo "$PATH" | sed -e "s,$(dirname "$i")/*:*,,g")" - fi -done -exit 1 ### no compiler found? diff --git a/rtags/bin/rtags-gcc-prefix.sh b/rtags/bin/rtags-gcc-prefix.sh deleted file mode 100755 index aea57c0..0000000 --- a/rtags/bin/rtags-gcc-prefix.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -[ -z "$RTAGS_DISABLED" ] && [ -x "$(which rc)" ] && rc --silent --compile "$@" & -[ -n "$RTAGS_RMAKE" ] && exit 0 -compiler="$1" -shift -$compiler "$@" -exit $? diff --git a/rtags/clang.sup b/rtags/clang.sup deleted file mode 100644 index 90b8415..0000000 --- a/rtags/clang.sup +++ /dev/null @@ -1,19 +0,0 @@ -{ - 1 - Memcheck:Cond - fun:_ZNK5clang4Expr21refersToVectorElementEv - obj:* -} - - -{ - 2 - Memcheck:Cond - fun:_ZNK5clang4Expr21refersToVectorElementEv -} -{ - 3 - Memcheck:Cond - fun:_ZNK5clang4Expr17isTemporaryObjectERNS_10ASTContextEPKNS_13CXXRecordDeclE -} - diff --git a/rtags/cmake/BashCompletion.cmake b/rtags/cmake/BashCompletion.cmake deleted file mode 100644 index a38dabd..0000000 --- a/rtags/cmake/BashCompletion.cmake +++ /dev/null @@ -1,34 +0,0 @@ -set(FORCE_BASH_COMPLETION_INSTALLATION FALSE CACHE BOOL "Force bash completion installation") - -if(FORCE_BASH_COMPLETION_INSTALLATION AND "${BASH_COMPLETION_COMPLETIONSDIR}" STREQUAL "") - set(BASH_COMPLETION_COMPLETIONSDIR "/share/bash-completion/completions") -endif() - -find_package(PkgConfig QUIET) -set_package_properties(PkgConfig - PROPERTIES - URL "https://www.freedesktop.org/wiki/Software/pkg-config/" - DESCRIPTION "helper tool" - TYPE OPTIONAL - PURPOSE "We use it to get the bash completion installation path, and replace the prefix with the value of CMAKE_INSTALL_PREFIX.") -if(PKG_CONFIG_FOUND OR FORCE_BASH_COMPLETION_INSTALLATION) - if(PKG_CONFIG_FOUND AND NOT FORCE_BASH_COMPLETION_INSTALLATION) - execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=completionsdir bash-completion - RESULT_VARIABLE BASH_COMPLETION_UNAVAILABLE - OUTPUT_VARIABLE BASH_COMPLETION_COMPLETIONSDIR - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT BASH_COMPLETION_UNAVAILABLE) - execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=prefix bash-completion - OUTPUT_VARIABLE BASH_COMPLETION_COMPLETIONSDIR_PREFIX - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - string(REPLACE "${BASH_COMPLETION_COMPLETIONSDIR_PREFIX}" "" BASH_COMPLETION_COMPLETIONSDIR ${BASH_COMPLETION_COMPLETIONSDIR}) - endif() - endif() - if(NOT BASH_COMPLETION_UNAVAILABLE OR FORCE_BASH_COMPLETION_INSTALLATION) - set(BASH_COMPLETION_COMPLETIONSDIR "${CMAKE_INSTALL_PREFIX}${BASH_COMPLETION_COMPLETIONSDIR}" CACHE PATH "Bash completion installation directory" FORCE) - mark_as_advanced(BASH_COMPLETION_COMPLETIONSDIR) - set(BASH_COMPLETION_FOUND TRUE) - endif() -endif() diff --git a/rtags/cmake/ClangVersion.cmake b/rtags/cmake/ClangVersion.cmake deleted file mode 100644 index c311f1b..0000000 --- a/rtags/cmake/ClangVersion.cmake +++ /dev/null @@ -1,23 +0,0 @@ -macro(ClangVersion path version_major version_minor) - if(EXISTS "${path}/clang/Basic/Version.inc") - file(READ "${path}/clang/Basic/Version.inc" CLANG_VERSION_DATA) - string(REGEX REPLACE ";" "\\\\;" CLANG_VERSION_DATA ${CLANG_VERSION_DATA}) - string(REGEX REPLACE "\n" ";" CLANG_VERSION_DATA ${CLANG_VERSION_DATA}) - foreach(line ${CLANG_VERSION_DATA}) - string(REGEX REPLACE "^#define CLANG_VERSION ([0-9]+\\.[0-9]+)$" "\\1" CLANG_VERSION_STRING ${line}) - if(DEFINED CLANG_VERSION_STRING) - string(REGEX REPLACE "^([0-9]+)\\.[0-9]+$" "\\1" CLANG_VERSION_MAJOR ${CLANG_VERSION_STRING}) - string(REGEX REPLACE "^[0-9]+\\.([0-9]+)$" "\\1" CLANG_VERSION_MINOR ${CLANG_VERSION_STRING}) - if(NOT ${CLANG_VERSION_MAJOR} STREQUAL "" AND NOT ${CLANG_VERSION_MINOR} STREQUAL "") - break() - endif() - endif() - endforeach() - endif() - if(NOT ${CLANG_VERSION_MAJOR} STREQUAL "" AND NOT ${CLANG_VERSION_MINOR} STREQUAL "") - set(${version_major} ${CLANG_VERSION_MAJOR}) - set(${version_minor} ${CLANG_VERSION_MINOR}) - else() - message(FATAL_ERROR "Unable to parse ClangVersion from ${path}/clang/Basic/Version.inc") - endif() -endmacro() diff --git a/rtags/cmake/EnsureLibraries.cmake b/rtags/cmake/EnsureLibraries.cmake deleted file mode 100644 index 65594a4..0000000 --- a/rtags/cmake/EnsureLibraries.cmake +++ /dev/null @@ -1,46 +0,0 @@ -#### EnsureLibraries - -# Macro for copying needed libraries to target directory -MACRO(EnsureLibraries EXE_NAME LIBRARY_NAMES ) - - FOREACH ( LIBRARY_NAME IN ITEMS ${LIBRARY_NAMES} ) - GET_TARGET_PROPERTY ( libLocation "${LIBRARY_NAME}" LOCATION ) - - IF ( NOT "${libLocation}" STREQUAL "libLocation-NOTFOUND" ) - - GET_TARGET_PROPERTY ( exeLocation "${EXE_NAME}" LOCATION ) - - IF ( CMAKE_COMPILER_IS_GNUCC ) - ADD_CUSTOM_COMMAND ( TARGET ${EXE_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -D LIBRARY="${libLocation}" -D TARGET="${exeLocation}" -P "${CMAKE_SOURCE_DIR}/cmake/EnsureLibrariesRunner.cmake" - COMMENT "Copy lib ${LIBRARY_NAME} to ${EXE_NAME} build ..." - DEPENDS ${LIBRARY_NAME} - ) - ELSE ( CMAKE_COMPILER_IS_GNUCC ) - - INCLUDE(GenerateExportHeader) - - IF ( NOT CYGWIN ) - GENERATE_EXPORT_HEADER( ${LIBRARY_NAME} - BASE_NAME ${LIBRARY_NAME} - EXPORT_MACRO_NAME ${LIBRARY_NAME}_EXPORT - EXPORT_FILE_NAME ${LIBRARY_NAME}_Export.h - STATIC_DEFINE ${LIBRARY_NAME}_BUILT_AS_STATIC - ) - ENDIF ( NOT CYGWIN ) - - ADD_CUSTOM_COMMAND ( TARGET ${EXE_NAME} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy "${libLocation}" "$" - COMMENT "Copy lib ${LIBRARY_NAME} to ${EXE_NAME} build ..." - DEPENDS ${LIBRARY_NAME} - DEPENDS osswin - ) - ENDIF ( CMAKE_COMPILER_IS_GNUCC ) - - ENDIF ( NOT "${libLocation}" STREQUAL "libLocation-NOTFOUND" ) - - ENDFOREACH ( LIBRARY_NAME IN ITEMS ${LIBRARY_NAMES} ) - -ENDMACRO(EnsureLibraries) diff --git a/rtags/cmake/EnsureLibrariesRunner.cmake b/rtags/cmake/EnsureLibrariesRunner.cmake deleted file mode 100644 index 5f5efe3..0000000 --- a/rtags/cmake/EnsureLibrariesRunner.cmake +++ /dev/null @@ -1,28 +0,0 @@ - -IF ( NOT EXISTS ${LIBRARY} ) - MESSAGE ( FATAL_ERROR "The provided file ${LIBRARY} does not exist" ) - RETURN () -ENDIF ( NOT EXISTS ${LIBRARY} ) - -SET ( TARGET_PATH "${TARGET}" ) - -IF ( EXISTS ${TARGET} AND NOT IS_DIRECTORY ${TARGET} ) - FILE ( TO_NATIVE_PATH "${TARGET}" TARGET_PATH ) - IF ( EXISTS ${TARGET_PATH} ) - GET_FILENAME_COMPONENT ( TARGET_PATH ${TARGET} PATH ) - ENDIF ( EXISTS ${TARGET_PATH} ) -ENDIF ( EXISTS ${TARGET} AND NOT IS_DIRECTORY ${TARGET} ) - -IF ( NOT EXISTS ${TARGET_PATH} AND NOT IS_DIRECTORY ${TARGET_PATH} ) - MESSAGE ( FATAL_ERROR "The provided target ${TARGET_PATH} does not exist, and is not a directory" ) - RETURN () -ENDIF ( NOT EXISTS ${TARGET_PATH} AND NOT IS_DIRECTORY ${TARGET_PATH} ) -SET ( OUTPUT_TARGET ${TARGET_PATH} ) - -FILE ( TO_NATIVE_PATH "${LIBRARY}" NATIVE_LIBRARY_PATH ) -FILE ( TO_NATIVE_PATH "${OUTPUT_TARGET}/" NATIVE_TARGET_PATH ) - -#MESSAGE ( STATUS "Copying ${NATIVE_LIBRARY_PATH} => ${NATIVE_TARGET_PATH}" ) - -FILE ( COPY ${NATIVE_LIBRARY_PATH} DESTINATION ${NATIVE_TARGET_PATH} ) - diff --git a/rtags/cmake/FindLibClang.cmake b/rtags/cmake/FindLibClang.cmake deleted file mode 100644 index 1e95cb7..0000000 --- a/rtags/cmake/FindLibClang.cmake +++ /dev/null @@ -1,141 +0,0 @@ -# FindLibClang -# -# This module searches libclang and llvm-config, the llvm-config tool is used to -# get information about the installed llvm/clang package to compile LLVM based -# programs. -# -# It defines the following variables -# -# ``LIBCLANG_LLVM_CONFIG_EXECUTABLE`` -# the llvm-config tool to get various information. -# ``LIBCLANG_LIBRARIES`` -# the clang libraries to link against to use Clang/LLVM. -# ``LIBCLANG_LIBDIR`` -# the directory where the clang libraries are located. -# ``LIBCLANG_FOUND`` -# true if libclang was found -# ``LIBCLANG_VERSION_STRING`` -# version number as a string -# ``LIBCLANG_CXXFLAGS`` -# the compiler flags for files that include LLVM headers -# -#============================================================================= -# Copyright (C) 2011, 2012, 2013 Jan Erik Hanssen and Anders Bakken -# Copyright (C) 2015 Christian Schwarzgruber -# -# This file is part of RTags (http://rtags.net). -# -# RTags is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# RTags is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with RTags. If not, see . - -if (NOT LIBCLANG_ROOT_DIR) - set(LIBCLANG_ROOT_DIR $ENV{LIBCLANG_ROOT_DIR}) -endif () - -if (NOT LIBCLANG_LLVM_CONFIG_EXECUTABLE) - set(LIBCLANG_LLVM_CONFIG_EXECUTABLE $ENV{LIBCLANG_LLVM_CONFIG_EXECUTABLE}) - if (NOT LIBCLANG_LLVM_CONFIG_EXECUTABLE) - if (APPLE) - foreach(major RANGE 9 3) - foreach(minor RANGE 9 0) - foreach(patch RANGE 9 0) - message(STATUS "trying llvm-config llvm-config${major}${minor} in /usr/local/Cellar/llvm/${major}.${minor}.${patch}/bin") - find_program(LIBCLANG_LLVM_CONFIG_EXECUTABLE NAMES llvm-config llvm-config${major}${minor} llvm-config-${major}${minor} llvm-config-${major} llvm-config${major} PATHS /usr/local/Cellar/llvm/${major}.${minor}.${patch}/bin) - if (LIBCLANG_LLVM_CONFIG_EXECUTABLE) - break() - endif () - endforeach () - if (LIBCLANG_LLVM_CONFIG_EXECUTABLE) - break() - endif () - endforeach () - if (LIBCLANG_LLVM_CONFIG_EXECUTABLE) - break() - endif () - endforeach () - else () - set(llvm_config_names llvm-config) - foreach(major RANGE 9 3) - list(APPEND llvm_config_names "llvm-config${major}" "llvm-config-${major}") - foreach(minor RANGE 9 0) - list(APPEND llvm_config_names "llvm-config${major}${minor}" "llvm-config-${major}.${minor}" "llvm-config-mp-${major}.${minor}") - endforeach () - endforeach () - find_program(LIBCLANG_LLVM_CONFIG_EXECUTABLE NAMES ${llvm_config_names}) - endif () - endif () - if (LIBCLANG_LLVM_CONFIG_EXECUTABLE) - message(STATUS "llvm-config executable found: ${LIBCLANG_LLVM_CONFIG_EXECUTABLE}") - endif () -endif () - -if (NOT LIBCLANG_CXXFLAGS) - if (NOT LIBCLANG_LLVM_CONFIG_EXECUTABLE) - message(FATAL_ERROR "Could NOT find llvm-config executable and LIBCLANG_CXXFLAGS is not set ") - endif () - execute_process(COMMAND ${LIBCLANG_LLVM_CONFIG_EXECUTABLE} --cxxflags OUTPUT_VARIABLE LIBCLANG_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) - if (NOT LIBCLANG_CXXFLAGS) - find_path(LIBCLANG_CXXFLAGS_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT clang-c/Index.h HINTS ${LIBCLANG_ROOT_DIR}/include NO_DEFAULT_PATH) - if (NOT EXISTS ${LIBCLANG_CXXFLAGS_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT}) - find_path(LIBCLANG_CXXFLAGS clang-c/Index.h) - if (NOT EXISTS ${LIBCLANG_CXXFLAGS}) - message(FATAL_ERROR "Could NOT find clang include path. You can fix this by setting LIBCLANG_CXXFLAGS in your shell or as a cmake variable.") - endif () - else () - set(LIBCLANG_CXXFLAGS ${LIBCLANG_CXXFLAGS_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT}) - endif () - set(LIBCLANG_CXXFLAGS "-I${LIBCLANG_CXXFLAGS}") - endif () - string(REGEX MATCHALL "-(D__?[a-zA-Z_]*|I([^\" ]+|\"[^\"]+\"))" LIBCLANG_CXXFLAGS "${LIBCLANG_CXXFLAGS}") - string(REGEX REPLACE ";" " " LIBCLANG_CXXFLAGS "${LIBCLANG_CXXFLAGS}") - set(LIBCLANG_CXXFLAGS ${LIBCLANG_CXXFLAGS} CACHE STRING "The LLVM C++ compiler flags needed to compile LLVM based applications.") - unset(LIBCLANG_CXXFLAGS_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT CACHE) -endif () - -if (NOT EXISTS ${LIBCLANG_LIBDIR}) - if (NOT LIBCLANG_LLVM_CONFIG_EXECUTABLE) - message(FATAL_ERROR "Could NOT find llvm-config executable and LIBCLANG_LIBDIR is not set ") - endif () - execute_process(COMMAND ${LIBCLANG_LLVM_CONFIG_EXECUTABLE} --libdir OUTPUT_VARIABLE LIBCLANG_LIBDIR OUTPUT_STRIP_TRAILING_WHITESPACE) - if (NOT EXISTS ${LIBCLANG_LIBDIR}) - message(FATAL_ERROR "Could NOT find clang libdir. You can fix this by setting LIBCLANG_LIBDIR in your shell or as a cmake variable.") - endif () - set(LIBCLANG_LIBDIR ${LIBCLANG_LIBDIR} CACHE STRING "Path to the clang library.") -endif () - -if (NOT LIBCLANG_LIBRARIES) - find_library(LIBCLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT NAMES clang libclang HINTS ${LIBCLANG_LIBDIR} ${LIBCLANG_ROOT_DIR}/lib NO_DEFAULT_PATH) - if (LIBCLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT) - set(LIBCLANG_LIBRARIES "${LIBCLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT}") - else () - find_library(LIBCLANG_LIBRARIES NAMES clang libclang) - if (NOT EXISTS ${LIBCLANG_LIBRARIES}) - set (LIBCLANG_LIBRARIES "-L${LIBCLANG_LIBDIR}" "-lclang" "-Wl,-rpath,${LIBCLANG_LIBDIR}") - endif () - endif () - unset(LIBCLANG_LIB_HACK_CMAKECACHE_DOT_TEXT_BULLSHIT CACHE) -endif () - -set(LIBCLANG_LIBRARY ${LIBCLANG_LIBRARIES} CACHE FILEPATH "Path to the libclang library") - -if (LIBCLANG_LLVM_CONFIG_EXECUTABLE) - execute_process(COMMAND ${LIBCLANG_LLVM_CONFIG_EXECUTABLE} --version OUTPUT_VARIABLE LIBCLANG_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE) -else () - set(LIBCLANG_VERSION_STRING "Unknown") -endif () -message("-- Using Clang version ${LIBCLANG_VERSION_STRING} from ${LIBCLANG_LIBDIR} with CXXFLAGS ${LIBCLANG_CXXFLAGS}") - -# Handly the QUIETLY and REQUIRED arguments and set LIBCLANG_FOUND to TRUE if all listed variables are TRUE -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LibClang DEFAULT_MSG LIBCLANG_LIBRARY LIBCLANG_CXXFLAGS LIBCLANG_LIBDIR) -mark_as_advanced(LIBCLANG_CXXFLAGS LIBCLANG_LIBRARY LIBCLANG_LLVM_CONFIG_EXECUTABLE LIBCLANG_LIBDIR) diff --git a/rtags/cmake/PkgInfo.cmake b/rtags/cmake/PkgInfo.cmake deleted file mode 100644 index a0c125f..0000000 --- a/rtags/cmake/PkgInfo.cmake +++ /dev/null @@ -1,70 +0,0 @@ -find_package(Git) -if(GIT_FOUND) - set(USE_GIT 1) -else() - set(USE_GIT 0) -endif() - -if(${USE_GIT} EQUAL 1) - execute_process( - COMMAND ${GIT_EXECUTABLE} describe --tags --dirty - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_DESCRIBE_VERSION - RESULT_VARIABLE GIT_DESCRIBE_RESULT - ERROR_VARIABLE GIT_DESCRIBE_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND ${GIT_EXECUTABLE} config --get user.name - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE GIT_CONFIG_USERNAME - RESULT_VARIABLE GIT_CONFIG_RESULT - ERROR_VARIABLE GIT_CONFIG_ERROR - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -else() - set(GIT_DESCRIBE_RESULT -1) - set(GIT_CONFIG_RESULT -1) -endif() - -# -# Deal with version first -# -if(GIT_DESCRIBE_RESULT EQUAL 0) - file(WRITE ${CMAKE_BINARY_DIR}/source/VERSION "${GIT_DESCRIBE_VERSION}") -else() - file(READ ${CMAKE_SOURCE_DIR}/VERSION GIT_DESCRIBE_VERSION) -endif() - -string(REGEX REPLACE "v([0-9]*)\\.([0-9]*)(-(.*))?" - "\\1;\\2;\\4" VLIST "${GIT_DESCRIBE_VERSION}") -#message(INFO " vlist ${VLIST}") - -list(GET VLIST 0 VERSION_MAJOR) -list(GET VLIST 1 VERSION_MINOR) -list(LENGTH VLIST VLISTLEN) -if(VLISTLEN EQUAL 3) - list(GET VLIST 2 VERSION_EXTRA) -endif() -set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}-${VERSION_EXTRA}") - -# -# Deal with username -# -string(LENGTH "${GIT_CONFIG_USERNAME}" GIT_CONFIG_USERNAME_LENGTH) -#message(INFO "uname <${GIT_CONFIG_USERNAME}>") -#message(INFO "length ${GIT_CONFIG_USERNAME_LENGTH}") -if(GIT_CONFIG_USERNAME_LENGTH EQUAL 0) - set(GIT_CONFIG_RESULT -1) -endif() - -if(GIT_CONFIG_RESULT EQUAL -1) - if(WIN32) - set(PKG_USERNAME "$ENV{USERNAME}") - else() - set(PKG_USERNAME "$ENV{USER}") - endif() -else() - set(PKG_USERNAME "${GIT_CONFIG_USERNAME}") -endif() -#message(INFO "user ${PKG_USERNAME}") \ No newline at end of file diff --git a/rtags/cmake/Uninstall.cmake.in b/rtags/cmake/Uninstall.cmake.in deleted file mode 100644 index 1f17834..0000000 --- a/rtags/cmake/Uninstall.cmake.in +++ /dev/null @@ -1,39 +0,0 @@ -set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") - -if(NOT EXISTS ${MANIFEST}) - message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") -endif() - -file(STRINGS ${MANIFEST} files) -foreach(file ${files}) - if(IS_SYMLINK ${file} OR EXISTS ${file}) - message(STATUS "Removing file: '${file}'.") - exec_program(${CMAKE_COMMAND} ARGS "-E remove ${file}" OUTPUT_VARIABLE stdout RETURN_VALUE result) - if(NOT "${result}" STREQUAL 0) - message(FATAL_ERROR "Failed to remove file: '${file}'.") - endif() - else() - message(STATUS "File '${file}' does not exist.") - endif() -endforeach() - -# We will not traverse back and delete "arbitrary" folders. -# An exception are directories which are rtags specific directories like, -# "rtags" under "INSTALL_PREFIX/usr/emacs/site-lisp/". -set(directories "@CMAKE_INSTALL_PREFIX@/share/emacs/site-lisp/rtags") -foreach(dir ${directories}) - if(IS_DIRECTORY ${dir} AND EXISTS ${dir}) - file(GLOB files "${dir}/*") - if(NOT files) - message(STATUS "Removing directory: '${dir}'.") - exec_program(${CMAKE_COMMAND} ARGS "-E remove_directory ${dir}" OUTPUT_VARIABLE stdout RETURN_VALUE result) - if(NOT "${result}" STREQUAL 0) - message(FATAL_ERROR "Failed to remove directory: '${dir}'.") - endif() - else() - message(STATUS "Directory '${dir}' not empty.") - endif() - else() - message(STATUS "Directory '${dir}' does not exist.") - endif() -endforeach() diff --git a/rtags/cmake/cotire.cmake b/rtags/cmake/cotire.cmake deleted file mode 100644 index a4fb533..0000000 --- a/rtags/cmake/cotire.cmake +++ /dev/null @@ -1,3827 +0,0 @@ -# - cotire (compile time reducer) -# -# See the cotire manual for usage hints. -# -#============================================================================= -# Copyright 2012-2015 Sascha Kratky -# -# 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. -#============================================================================= - -if(__COTIRE_INCLUDED) - return() -endif() -set(__COTIRE_INCLUDED TRUE) - -# call cmake_minimum_required, but prevent modification of the CMake policy stack in include mode -# cmake_minimum_required also sets the policy version as a side effect, which we have to avoid -if (NOT CMAKE_SCRIPT_MODE_FILE) - cmake_policy(PUSH) -endif() -cmake_minimum_required(VERSION 2.8.12) -if (NOT CMAKE_SCRIPT_MODE_FILE) - cmake_policy(POP) -endif() - -set (COTIRE_CMAKE_MODULE_FILE "${CMAKE_CURRENT_LIST_FILE}") -set (COTIRE_CMAKE_MODULE_VERSION "1.7.6") - -# activate select policies -if (POLICY CMP0025) - # Compiler id for Apple Clang is now AppleClang - cmake_policy(SET CMP0025 NEW) -endif() - -if (POLICY CMP0026) - # disallow use of the LOCATION target property - cmake_policy(SET CMP0026 NEW) -endif() - -if (POLICY CMP0038) - # targets may not link directly to themselves - cmake_policy(SET CMP0038 NEW) -endif() - -if (POLICY CMP0039) - # utility targets may not have link dependencies - cmake_policy(SET CMP0039 NEW) -endif() - -if (POLICY CMP0040) - # target in the TARGET signature of add_custom_command() must exist - cmake_policy(SET CMP0040 NEW) -endif() - -if (POLICY CMP0045) - # error on non-existent target in get_target_property - cmake_policy(SET CMP0045 NEW) -endif() - -if (POLICY CMP0046) - # error on non-existent dependency in add_dependencies - cmake_policy(SET CMP0046 NEW) -endif() - -if (POLICY CMP0049) - # do not expand variables in target source entries - cmake_policy(SET CMP0049 NEW) -endif() - -if (POLICY CMP0050) - # disallow add_custom_command SOURCE signatures - cmake_policy(SET CMP0050 NEW) -endif() - -if (POLICY CMP0051) - # include TARGET_OBJECTS expressions in a target's SOURCES property - cmake_policy(SET CMP0051 NEW) -endif() - -if (POLICY CMP0053) - # simplify variable reference and escape sequence evaluation - cmake_policy(SET CMP0053 NEW) -endif() - -if (POLICY CMP0054) - # only interpret if() arguments as variables or keywords when unquoted - cmake_policy(SET CMP0054 NEW) -endif() - -include(CMakeParseArguments) -include(ProcessorCount) - -function (cotire_get_configuration_types _configsVar) - set (_configs "") - if (CMAKE_CONFIGURATION_TYPES) - list (APPEND _configs ${CMAKE_CONFIGURATION_TYPES}) - endif() - if (CMAKE_BUILD_TYPE) - list (APPEND _configs "${CMAKE_BUILD_TYPE}") - endif() - if (_configs) - list (REMOVE_DUPLICATES _configs) - set (${_configsVar} ${_configs} PARENT_SCOPE) - else() - set (${_configsVar} "None" PARENT_SCOPE) - endif() -endfunction() - -function (cotire_get_source_file_extension _sourceFile _extVar) - # get_filename_component returns extension from first occurrence of . in file name - # this function computes the extension from last occurrence of . in file name - string (FIND "${_sourceFile}" "." _index REVERSE) - if (_index GREATER -1) - math (EXPR _index "${_index} + 1") - string (SUBSTRING "${_sourceFile}" ${_index} -1 _sourceExt) - else() - set (_sourceExt "") - endif() - set (${_extVar} "${_sourceExt}" PARENT_SCOPE) -endfunction() - -macro (cotire_check_is_path_relative_to _path _isRelativeVar) - set (${_isRelativeVar} FALSE) - if (IS_ABSOLUTE "${_path}") - foreach (_dir ${ARGN}) - file (RELATIVE_PATH _relPath "${_dir}" "${_path}") - if (NOT _relPath OR (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.")) - set (${_isRelativeVar} TRUE) - break() - endif() - endforeach() - endif() -endmacro() - -function (cotire_filter_language_source_files _language _target _sourceFilesVar _excludedSourceFilesVar _cotiredSourceFilesVar) - if (CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) - set (_languageExtensions "${CMAKE_${_language}_SOURCE_FILE_EXTENSIONS}") - else() - set (_languageExtensions "") - endif() - if (CMAKE_${_language}_IGNORE_EXTENSIONS) - set (_ignoreExtensions "${CMAKE_${_language}_IGNORE_EXTENSIONS}") - else() - set (_ignoreExtensions "") - endif() - if (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS) - set (_excludeExtensions "${COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS}") - else() - set (_excludeExtensions "") - endif() - if (COTIRE_DEBUG AND _languageExtensions) - message (STATUS "${_language} source file extensions: ${_languageExtensions}") - endif() - if (COTIRE_DEBUG AND _ignoreExtensions) - message (STATUS "${_language} ignore extensions: ${_ignoreExtensions}") - endif() - if (COTIRE_DEBUG AND _excludeExtensions) - message (STATUS "${_language} exclude extensions: ${_excludeExtensions}") - endif() - if (CMAKE_VERSION VERSION_LESS "3.1.0") - set (_allSourceFiles ${ARGN}) - else() - # as of CMake 3.1 target sources may contain generator expressions - # since we cannot obtain required property information about source files added - # through generator expressions at configure time, we filter them out - string (GENEX_STRIP "${ARGN}" _allSourceFiles) - endif() - set (_filteredSourceFiles "") - set (_excludedSourceFiles "") - foreach (_sourceFile ${_allSourceFiles}) - get_source_file_property(_sourceIsHeaderOnly "${_sourceFile}" HEADER_FILE_ONLY) - get_source_file_property(_sourceIsExternal "${_sourceFile}" EXTERNAL_OBJECT) - get_source_file_property(_sourceIsSymbolic "${_sourceFile}" SYMBOLIC) - if (NOT _sourceIsHeaderOnly AND NOT _sourceIsExternal AND NOT _sourceIsSymbolic) - cotire_get_source_file_extension("${_sourceFile}" _sourceExt) - if (_sourceExt) - list (FIND _ignoreExtensions "${_sourceExt}" _ignoreIndex) - if (_ignoreIndex LESS 0) - list (FIND _excludeExtensions "${_sourceExt}" _excludeIndex) - if (_excludeIndex GREATER -1) - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (FIND _languageExtensions "${_sourceExt}" _sourceIndex) - if (_sourceIndex GREATER -1) - # consider source file unless it is excluded explicitly - get_source_file_property(_sourceIsExcluded "${_sourceFile}" COTIRE_EXCLUDED) - if (_sourceIsExcluded) - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (APPEND _filteredSourceFiles "${_sourceFile}") - endif() - else() - get_source_file_property(_sourceLanguage "${_sourceFile}" LANGUAGE) - if ("${_sourceLanguage}" STREQUAL "${_language}") - # add to excluded sources, if file is not ignored and has correct language without having the correct extension - list (APPEND _excludedSourceFiles "${_sourceFile}") - endif() - endif() - endif() - endif() - endif() - endif() - endforeach() - # separate filtered source files from already cotired ones - # the COTIRE_TARGET property of a source file may be set while a target is being processed by cotire - set (_sourceFiles "") - set (_cotiredSourceFiles "") - foreach (_sourceFile ${_filteredSourceFiles}) - get_source_file_property(_sourceIsCotired "${_sourceFile}" COTIRE_TARGET) - if (_sourceIsCotired) - list (APPEND _cotiredSourceFiles "${_sourceFile}") - else() - get_source_file_property(_sourceCompileFlags "${_sourceFile}" COMPILE_FLAGS) - if (_sourceCompileFlags) - # add to excluded sources, if file has custom compile flags - list (APPEND _excludedSourceFiles "${_sourceFile}") - else() - list (APPEND _sourceFiles "${_sourceFile}") - endif() - endif() - endforeach() - if (COTIRE_DEBUG) - if (_sourceFiles) - message (STATUS "Filtered ${_target} ${_language} sources: ${_sourceFiles}") - endif() - if (_excludedSourceFiles) - message (STATUS "Excluded ${_target} ${_language} sources: ${_excludedSourceFiles}") - endif() - if (_cotiredSourceFiles) - message (STATUS "Cotired ${_target} ${_language} sources: ${_cotiredSourceFiles}") - endif() - endif() - set (${_sourceFilesVar} ${_sourceFiles} PARENT_SCOPE) - set (${_excludedSourceFilesVar} ${_excludedSourceFiles} PARENT_SCOPE) - set (${_cotiredSourceFilesVar} ${_cotiredSourceFiles} PARENT_SCOPE) -endfunction() - -function (cotire_get_objects_with_property_on _filteredObjectsVar _property _type) - set (_filteredObjects "") - foreach (_object ${ARGN}) - get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (_propertyValue) - list (APPEND _filteredObjects "${_object}") - endif() - endif() - endforeach() - set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) -endfunction() - -function (cotire_get_objects_with_property_off _filteredObjectsVar _property _type) - set (_filteredObjects "") - foreach (_object ${ARGN}) - get_property(_isSet ${_type} "${_object}" PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (NOT _propertyValue) - list (APPEND _filteredObjects "${_object}") - endif() - endif() - endforeach() - set (${_filteredObjectsVar} ${_filteredObjects} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_file_property_values _valuesVar _property) - set (_values "") - foreach (_sourceFile ${ARGN}) - get_source_file_property(_propertyValue "${_sourceFile}" ${_property}) - if (_propertyValue) - list (APPEND _values "${_propertyValue}") - endif() - endforeach() - set (${_valuesVar} ${_values} PARENT_SCOPE) -endfunction() - -function (cotire_resolve_config_properites _configurations _propertiesVar) - set (_properties "") - foreach (_property ${ARGN}) - if ("${_property}" MATCHES "") - foreach (_config ${_configurations}) - string (TOUPPER "${_config}" _upperConfig) - string (REPLACE "" "${_upperConfig}" _configProperty "${_property}") - list (APPEND _properties ${_configProperty}) - endforeach() - else() - list (APPEND _properties ${_property}) - endif() - endforeach() - set (${_propertiesVar} ${_properties} PARENT_SCOPE) -endfunction() - -function (cotire_copy_set_properites _configurations _type _source _target) - cotire_resolve_config_properites("${_configurations}" _properties ${ARGN}) - foreach (_property ${_properties}) - get_property(_isSet ${_type} ${_source} PROPERTY ${_property} SET) - if (_isSet) - get_property(_propertyValue ${_type} ${_source} PROPERTY ${_property}) - set_property(${_type} ${_target} PROPERTY ${_property} "${_propertyValue}") - endif() - endforeach() -endfunction() - -function (cotire_get_target_usage_requirements _target _targetRequirementsVar) - set (_targetRequirements "") - get_target_property(_librariesToProcess ${_target} LINK_LIBRARIES) - while (_librariesToProcess) - # remove from head - list (GET _librariesToProcess 0 _library) - list (REMOVE_AT _librariesToProcess 0) - if (TARGET ${_library}) - list (FIND _targetRequirements ${_library} _index) - if (_index LESS 0) - list (APPEND _targetRequirements ${_library}) - # process transitive libraries - get_target_property(_libraries ${_library} INTERFACE_LINK_LIBRARIES) - if (_libraries) - list (APPEND _librariesToProcess ${_libraries}) - list (REMOVE_DUPLICATES _librariesToProcess) - endif() - endif() - endif() - endwhile() - set (${_targetRequirementsVar} ${_targetRequirements} PARENT_SCOPE) -endfunction() - -function (cotire_filter_compile_flags _language _flagFilter _matchedOptionsVar _unmatchedOptionsVar) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - set (_flagPrefix "[/-]") - else() - set (_flagPrefix "--?") - endif() - set (_optionFlag "") - set (_matchedOptions "") - set (_unmatchedOptions "") - foreach (_compileFlag ${ARGN}) - if (_compileFlag) - if (_optionFlag AND NOT "${_compileFlag}" MATCHES "^${_flagPrefix}") - # option with separate argument - list (APPEND _matchedOptions "${_compileFlag}") - set (_optionFlag "") - elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})$") - # remember option - set (_optionFlag "${CMAKE_MATCH_2}") - elseif ("${_compileFlag}" MATCHES "^(${_flagPrefix})(${_flagFilter})(.+)$") - # option with joined argument - list (APPEND _matchedOptions "${CMAKE_MATCH_3}") - set (_optionFlag "") - else() - # flush remembered option - if (_optionFlag) - list (APPEND _matchedOptions "${_optionFlag}") - set (_optionFlag "") - endif() - # add to unfiltered options - list (APPEND _unmatchedOptions "${_compileFlag}") - endif() - endif() - endforeach() - if (_optionFlag) - list (APPEND _matchedOptions "${_optionFlag}") - endif() - if (COTIRE_DEBUG AND _matchedOptions) - message (STATUS "Filter ${_flagFilter} matched: ${_matchedOptions}") - endif() - if (COTIRE_DEBUG AND _unmatchedOptions) - message (STATUS "Filter ${_flagFilter} unmatched: ${_unmatchedOptions}") - endif() - set (${_matchedOptionsVar} ${_matchedOptions} PARENT_SCOPE) - set (${_unmatchedOptionsVar} ${_unmatchedOptions} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compile_flags _config _language _target _flagsVar) - string (TOUPPER "${_config}" _upperConfig) - # collect options from CMake language variables - set (_compileFlags "") - if (CMAKE_${_language}_FLAGS) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS}") - endif() - if (CMAKE_${_language}_FLAGS_${_upperConfig}) - set (_compileFlags "${_compileFlags} ${CMAKE_${_language}_FLAGS_${_upperConfig}}") - endif() - if (_target) - # add target compile flags - get_target_property(_targetflags ${_target} COMPILE_FLAGS) - if (_targetflags) - set (_compileFlags "${_compileFlags} ${_targetflags}") - endif() - endif() - if (UNIX) - separate_arguments(_compileFlags UNIX_COMMAND "${_compileFlags}") - elseif(WIN32) - separate_arguments(_compileFlags WINDOWS_COMMAND "${_compileFlags}") - else() - separate_arguments(_compileFlags) - endif() - # target compile options - if (_target) - get_target_property(_targetOptions ${_target} COMPILE_OPTIONS) - if (_targetOptions) - list (APPEND _compileFlags ${_targetOptions}) - endif() - endif() - # interface compile options from linked library targets - if (_target) - set (_linkedTargets "") - cotire_get_target_usage_requirements(${_target} _linkedTargets) - foreach (_linkedTarget ${_linkedTargets}) - get_target_property(_targetOptions ${_linkedTarget} INTERFACE_COMPILE_OPTIONS) - if (_targetOptions) - list (APPEND _compileFlags ${_targetOptions}) - endif() - endforeach() - endif() - # handle language standard properties - if (_target) - get_target_property(_targetLanguageStandard ${_target} ${_language}_STANDARD) - get_target_property(_targetLanguageExtensions ${_target} ${_language}_EXTENSIONS) - get_target_property(_targetLanguageStandardRequired ${_target} ${_language}_STANDARD_REQUIRED) - if (_targetLanguageExtensions) - if (CMAKE_${_language}${_targetLanguageExtensions}_EXTENSION_COMPILE_OPTION) - list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageExtensions}_EXTENSION_COMPILE_OPTION}") - endif() - elseif (_targetLanguageStandard) - if (_targetLanguageStandardRequired) - if (CMAKE_${_language}${_targetLanguageStandard}_STANDARD_COMPILE_OPTION) - list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_STANDARD_COMPILE_OPTION}") - endif() - else() - if (CMAKE_${_language}${_targetLanguageStandard}_EXTENSION_COMPILE_OPTION) - list (APPEND _compileFlags "${CMAKE_${_language}${_targetLanguageStandard}_EXTENSION_COMPILE_OPTION}") - endif() - endif() - endif() - endif() - # handle the POSITION_INDEPENDENT_CODE target property - if (_target) - get_target_property(_targetPIC ${_target} POSITION_INDEPENDENT_CODE) - if (_targetPIC) - get_target_property(_targetType ${_target} TYPE) - if (_targetType STREQUAL "EXECUTABLE" AND CMAKE_${_language}_COMPILE_OPTIONS_PIE) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIE}") - elseif (CMAKE_${_language}_COMPILE_OPTIONS_PIC) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_PIC}") - endif() - endif() - endif() - # handle visibility target properties - if (_target) - get_target_property(_targetVisibility ${_target} ${_language}_VISIBILITY_PRESET) - if (_targetVisibility AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY}${_targetVisibility}") - endif() - get_target_property(_targetVisibilityInlines ${_target} VISIBILITY_INLINES_HIDDEN) - if (_targetVisibilityInlines AND CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN) - list (APPEND _compileFlags "${CMAKE_${_language}_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN}") - endif() - endif() - # platform specific flags - if (APPLE) - get_target_property(_architectures ${_target} OSX_ARCHITECTURES_${_upperConfig}) - if (NOT _architectures) - get_target_property(_architectures ${_target} OSX_ARCHITECTURES) - endif() - if (_architectures) - foreach (_arch ${_architectures}) - list (APPEND _compileFlags "-arch" "${_arch}") - endforeach() - endif() - if (CMAKE_OSX_SYSROOT) - if (CMAKE_${_language}_SYSROOT_FLAG) - list (APPEND _compileFlags "${CMAKE_${_language}_SYSROOT_FLAG}" "${CMAKE_OSX_SYSROOT}") - else() - list (APPEND _compileFlags "-isysroot" "${CMAKE_OSX_SYSROOT}") - endif() - endif() - if (CMAKE_OSX_DEPLOYMENT_TARGET) - if (CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG) - list (APPEND _compileFlags "${CMAKE_${_language}_OSX_DEPLOYMENT_TARGET_FLAG}${CMAKE_OSX_DEPLOYMENT_TARGET}") - else() - list (APPEND _compileFlags "-mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") - endif() - endif() - endif() - if (COTIRE_DEBUG AND _compileFlags) - message (STATUS "Target ${_target} compile flags: ${_compileFlags}") - endif() - set (${_flagsVar} ${_compileFlags} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_include_directories _config _language _target _includeDirsVar _systemIncludeDirsVar) - set (_includeDirs "") - set (_systemIncludeDirs "") - # default include dirs - if (CMAKE_INCLUDE_CURRENT_DIR) - list (APPEND _includeDirs "${CMAKE_CURRENT_BINARY_DIR}") - list (APPEND _includeDirs "${CMAKE_CURRENT_SOURCE_DIR}") - endif() - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - # parse additional include directories from target compile flags - if (CMAKE_INCLUDE_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_dirs "") - cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) - if (_dirs) - list (APPEND _includeDirs ${_dirs}) - endif() - endif() - endif() - # parse additional system include directories from target compile flags - if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_dirs "") - cotire_filter_compile_flags("${_language}" "${_includeFlag}" _dirs _ignore ${_targetFlags}) - if (_dirs) - list (APPEND _systemIncludeDirs ${_dirs}) - endif() - endif() - endif() - # target include directories - get_directory_property(_dirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" INCLUDE_DIRECTORIES) - if (_target) - get_target_property(_targetDirs ${_target} INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _systemIncludeDirs ${_targetDirs}) - endif() - endif() - # interface include directories from linked library targets - if (_target) - set (_linkedTargets "") - cotire_get_target_usage_requirements(${_target} _linkedTargets) - foreach (_linkedTarget ${_linkedTargets}) - get_target_property(_targetDirs ${_linkedTarget} INTERFACE_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _dirs ${_targetDirs}) - endif() - get_target_property(_targetDirs ${_linkedTarget} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) - if (_targetDirs) - list (APPEND _systemIncludeDirs ${_targetDirs}) - endif() - endforeach() - endif() - if (dirs) - list (REMOVE_DUPLICATES _dirs) - endif() - list (LENGTH _includeDirs _projectInsertIndex) - foreach (_dir ${_dirs}) - if (CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE) - cotire_check_is_path_relative_to("${_dir}" _isRelative "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}") - if (_isRelative) - list (LENGTH _includeDirs _len) - if (_len EQUAL _projectInsertIndex) - list (APPEND _includeDirs "${_dir}") - else() - list (INSERT _includeDirs _projectInsertIndex "${_dir}") - endif() - math (EXPR _projectInsertIndex "${_projectInsertIndex} + 1") - else() - list (APPEND _includeDirs "${_dir}") - endif() - else() - list (APPEND _includeDirs "${_dir}") - endif() - endforeach() - list (REMOVE_DUPLICATES _includeDirs) - list (REMOVE_DUPLICATES _systemIncludeDirs) - if (CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES) - list (REMOVE_ITEM _includeDirs ${CMAKE_${_language}_IMPLICIT_INCLUDE_DIRECTORIES}) - endif() - if (COTIRE_DEBUG AND _includeDirs) - message (STATUS "Target ${_target} include dirs: ${_includeDirs}") - endif() - set (${_includeDirsVar} ${_includeDirs} PARENT_SCOPE) - if (COTIRE_DEBUG AND _systemIncludeDirs) - message (STATUS "Target ${_target} system include dirs: ${_systemIncludeDirs}") - endif() - set (${_systemIncludeDirsVar} ${_systemIncludeDirs} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_export_symbol _target _exportSymbolVar) - set (_exportSymbol "") - get_target_property(_targetType ${_target} TYPE) - get_target_property(_enableExports ${_target} ENABLE_EXPORTS) - if (_targetType MATCHES "(SHARED|MODULE)_LIBRARY" OR - (_targetType STREQUAL "EXECUTABLE" AND _enableExports)) - get_target_property(_exportSymbol ${_target} DEFINE_SYMBOL) - if (NOT _exportSymbol) - set (_exportSymbol "${_target}_EXPORTS") - endif() - string (MAKE_C_IDENTIFIER "${_exportSymbol}" _exportSymbol) - endif() - set (${_exportSymbolVar} ${_exportSymbol} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compile_definitions _config _language _target _definitionsVar) - string (TOUPPER "${_config}" _upperConfig) - set (_configDefinitions "") - # CMAKE_INTDIR for multi-configuration build systems - if (NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") - list (APPEND _configDefinitions "CMAKE_INTDIR=\"${_config}\"") - endif() - # target export define symbol - cotire_get_target_export_symbol("${_target}" _defineSymbol) - if (_defineSymbol) - list (APPEND _configDefinitions "${_defineSymbol}") - endif() - # directory compile definitions - get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - get_directory_property(_definitions DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - # target compile definitions - get_target_property(_definitions ${_target} COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - get_target_property(_definitions ${_target} COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - # interface compile definitions from linked library targets - set (_linkedTargets "") - cotire_get_target_usage_requirements(${_target} _linkedTargets) - foreach (_linkedTarget ${_linkedTargets}) - get_target_property(_definitions ${_linkedTarget} INTERFACE_COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - endforeach() - # parse additional compile definitions from target compile flags - # and don't look at directory compile definitions, which we already handled - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "D" _definitions _ignore ${_targetFlags}) - if (_definitions) - list (APPEND _configDefinitions ${_definitions}) - endif() - list (REMOVE_DUPLICATES _configDefinitions) - if (COTIRE_DEBUG AND _configDefinitions) - message (STATUS "Target ${_target} compile definitions: ${_configDefinitions}") - endif() - set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_target_compiler_flags _config _language _target _compilerFlagsVar) - # parse target compile flags omitting compile definitions and include directives - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - set (_flagFilter "D") - if (CMAKE_INCLUDE_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_flagFilter "${_flagFilter}|${_includeFlag}") - endif() - endif() - if (CMAKE_INCLUDE_SYSTEM_FLAG_${_language}) - string (STRIP "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" _includeFlag) - string (REGEX REPLACE "^[-/]+" "" _includeFlag "${_includeFlag}") - if (_includeFlag) - set (_flagFilter "${_flagFilter}|${_includeFlag}") - endif() - endif() - set (_compilerFlags "") - cotire_filter_compile_flags("${_language}" "${_flagFilter}" _ignore _compilerFlags ${_targetFlags}) - if (COTIRE_DEBUG AND _compilerFlags) - message (STATUS "Target ${_target} compiler flags: ${_compilerFlags}") - endif() - set (${_compilerFlagsVar} ${_compilerFlags} PARENT_SCOPE) -endfunction() - -function (cotire_add_sys_root_paths _pathsVar) - if (APPLE) - if (CMAKE_OSX_SYSROOT AND CMAKE_${_language}_HAS_ISYSROOT) - foreach (_path IN LISTS ${_pathsVar}) - if (IS_ABSOLUTE "${_path}") - get_filename_component(_path "${CMAKE_OSX_SYSROOT}/${_path}" ABSOLUTE) - if (EXISTS "${_path}") - list (APPEND ${_pathsVar} "${_path}") - endif() - endif() - endforeach() - endif() - endif() - set (${_pathsVar} ${${_pathsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_extra_properties _sourceFile _pattern _resultVar) - set (_extraProperties ${ARGN}) - set (_result "") - if (_extraProperties) - list (FIND _extraProperties "${_sourceFile}" _index) - if (_index GREATER -1) - math (EXPR _index "${_index} + 1") - list (LENGTH _extraProperties _len) - math (EXPR _len "${_len} - 1") - foreach (_index RANGE ${_index} ${_len}) - list (GET _extraProperties ${_index} _value) - if (_value MATCHES "${_pattern}") - list (APPEND _result "${_value}") - else() - break() - endif() - endforeach() - endif() - endif() - set (${_resultVar} ${_result} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_compile_definitions _config _language _sourceFile _definitionsVar) - set (_compileDefinitions "") - if (NOT CMAKE_SCRIPT_MODE_FILE) - string (TOUPPER "${_config}" _upperConfig) - get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - get_source_file_property(_definitions "${_sourceFile}" COMPILE_DEFINITIONS_${_upperConfig}) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - endif() - cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+(=.*)?$" _definitions ${ARGN}) - if (_definitions) - list (APPEND _compileDefinitions ${_definitions}) - endif() - if (COTIRE_DEBUG AND _compileDefinitions) - message (STATUS "Source ${_sourceFile} compile definitions: ${_compileDefinitions}") - endif() - set (${_definitionsVar} ${_compileDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_files_compile_definitions _config _language _definitionsVar) - set (_configDefinitions "") - foreach (_sourceFile ${ARGN}) - cotire_get_source_compile_definitions("${_config}" "${_language}" "${_sourceFile}" _sourceDefinitions) - if (_sourceDefinitions) - list (APPEND _configDefinitions "${_sourceFile}" ${_sourceDefinitions} "-") - endif() - endforeach() - set (${_definitionsVar} ${_configDefinitions} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_undefs _sourceFile _property _sourceUndefsVar) - set (_sourceUndefs "") - if (NOT CMAKE_SCRIPT_MODE_FILE) - get_source_file_property(_undefs "${_sourceFile}" ${_property}) - if (_undefs) - list (APPEND _sourceUndefs ${_undefs}) - endif() - endif() - cotire_get_source_extra_properties("${_sourceFile}" "^[a-zA-Z0-9_]+$" _undefs ${ARGN}) - if (_undefs) - list (APPEND _sourceUndefs ${_undefs}) - endif() - if (COTIRE_DEBUG AND _sourceUndefs) - message (STATUS "Source ${_sourceFile} ${_property} undefs: ${_sourceUndefs}") - endif() - set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) -endfunction() - -function (cotire_get_source_files_undefs _property _sourceUndefsVar) - set (_sourceUndefs "") - foreach (_sourceFile ${ARGN}) - cotire_get_source_undefs("${_sourceFile}" ${_property} _undefs) - if (_undefs) - list (APPEND _sourceUndefs "${_sourceFile}" ${_undefs} "-") - endif() - endforeach() - set (${_sourceUndefsVar} ${_sourceUndefs} PARENT_SCOPE) -endfunction() - -macro (cotire_set_cmd_to_prologue _cmdVar) - set (${_cmdVar} "${CMAKE_COMMAND}") - if (COTIRE_DEBUG) - list (APPEND ${_cmdVar} "--warn-uninitialized") - endif() - list (APPEND ${_cmdVar} "-DCOTIRE_BUILD_TYPE:STRING=$") - if (COTIRE_VERBOSE) - list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=ON") - elseif("${CMAKE_GENERATOR}" MATCHES "Makefiles") - list (APPEND ${_cmdVar} "-DCOTIRE_VERBOSE:BOOL=$(VERBOSE)") - endif() -endmacro() - -function (cotire_init_compile_cmd _cmdVar _language _compilerExe _compilerArg1) - if (NOT _compilerExe) - set (_compilerExe "${CMAKE_${_language}_COMPILER}") - endif() - if (NOT _compilerArg1) - set (_compilerArg1 ${CMAKE_${_language}_COMPILER_ARG1}) - endif() - string (STRIP "${_compilerArg1}" _compilerArg1) - set (${_cmdVar} "${_compilerExe}" ${_compilerArg1} PARENT_SCOPE) -endfunction() - -macro (cotire_add_definitions_to_cmd _cmdVar _language) - foreach (_definition ${ARGN}) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - list (APPEND ${_cmdVar} "/D${_definition}") - else() - list (APPEND ${_cmdVar} "-D${_definition}") - endif() - endforeach() -endmacro() - -function (cotire_add_includes_to_cmd _cmdVar _language _includesVar _systemIncludesVar) - set (_includeDirs ${${_includesVar}} ${${_systemIncludesVar}}) - if (_includeDirs) - list (REMOVE_DUPLICATES _includeDirs) - foreach (_include ${_includeDirs}) - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - file (TO_NATIVE_PATH "${_include}" _include) - list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}") - else() - set (_index -1) - if ("${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}" MATCHES ".+") - list (FIND ${_systemIncludesVar} "${_include}" _index) - endif() - if (_index GREATER -1) - list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_SYSTEM_FLAG_${_language}}${_include}") - else() - list (APPEND ${_cmdVar} "${CMAKE_INCLUDE_FLAG_${_language}}${CMAKE_INCLUDE_FLAG_${_language}_SEP}${_include}") - endif() - endif() - endforeach() - endif() - set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) -endfunction() - -function (cotire_add_frameworks_to_cmd _cmdVar _language _includesVar _systemIncludesVar) - if (APPLE) - set (_frameworkDirs "") - foreach (_include ${${_includesVar}}) - if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") - get_filename_component(_frameworkDir "${_include}" DIRECTORY) - list (APPEND _frameworkDirs "${_frameworkDir}") - endif() - endforeach() - set (_systemFrameworkDirs "") - foreach (_include ${${_systemIncludesVar}}) - if (IS_ABSOLUTE "${_include}" AND _include MATCHES "\\.framework$") - get_filename_component(_frameworkDir "${_include}" DIRECTORY) - list (APPEND _systemFrameworkDirs "${_frameworkDir}") - endif() - endforeach() - if (_systemFrameworkDirs) - list (APPEND _frameworkDirs ${_systemFrameworkDirs}) - endif() - if (_frameworkDirs) - list (REMOVE_DUPLICATES _frameworkDirs) - foreach (_frameworkDir ${_frameworkDirs}) - set (_index -1) - if ("${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}" MATCHES ".+") - list (FIND _systemFrameworkDirs "${_frameworkDir}" _index) - endif() - if (_index GREATER -1) - list (APPEND ${_cmdVar} "${CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") - else() - list (APPEND ${_cmdVar} "${CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG}${_frameworkDir}") - endif() - endforeach() - endif() - endif() - set (${_cmdVar} ${${_cmdVar}} PARENT_SCOPE) -endfunction() - -macro (cotire_add_compile_flags_to_cmd _cmdVar) - foreach (_flag ${ARGN}) - list (APPEND ${_cmdVar} "${_flag}") - endforeach() -endmacro() - -function (cotire_check_file_up_to_date _fileIsUpToDateVar _file) - if (EXISTS "${_file}") - set (_triggerFile "") - foreach (_dependencyFile ${ARGN}) - if (EXISTS "${_dependencyFile}") - # IS_NEWER_THAN returns TRUE if both files have the same timestamp - # thus we do the comparison in both directions to exclude ties - if ("${_dependencyFile}" IS_NEWER_THAN "${_file}" AND - NOT "${_file}" IS_NEWER_THAN "${_dependencyFile}") - set (_triggerFile "${_dependencyFile}") - break() - endif() - endif() - endforeach() - if (_triggerFile) - if (COTIRE_VERBOSE) - get_filename_component(_fileName "${_file}" NAME) - message (STATUS "${_fileName} update triggered by ${_triggerFile} change.") - endif() - set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) - else() - if (COTIRE_VERBOSE) - get_filename_component(_fileName "${_file}" NAME) - message (STATUS "${_fileName} is up-to-date.") - endif() - set (${_fileIsUpToDateVar} TRUE PARENT_SCOPE) - endif() - else() - if (COTIRE_VERBOSE) - get_filename_component(_fileName "${_file}" NAME) - message (STATUS "${_fileName} does not exist yet.") - endif() - set (${_fileIsUpToDateVar} FALSE PARENT_SCOPE) - endif() -endfunction() - -macro (cotire_find_closest_relative_path _headerFile _includeDirs _relPathVar) - set (${_relPathVar} "") - foreach (_includeDir ${_includeDirs}) - if (IS_DIRECTORY "${_includeDir}") - file (RELATIVE_PATH _relPath "${_includeDir}" "${_headerFile}") - if (NOT IS_ABSOLUTE "${_relPath}" AND NOT "${_relPath}" MATCHES "^\\.\\.") - string (LENGTH "${${_relPathVar}}" _closestLen) - string (LENGTH "${_relPath}" _relLen) - if (_closestLen EQUAL 0 OR _relLen LESS _closestLen) - set (${_relPathVar} "${_relPath}") - endif() - endif() - elseif ("${_includeDir}" STREQUAL "${_headerFile}") - # if path matches exactly, return short non-empty string - set (${_relPathVar} "1") - break() - endif() - endforeach() -endmacro() - -macro (cotire_check_header_file_location _headerFile _insideIncludeDirs _outsideIncludeDirs _headerIsInside) - # check header path against ignored and honored include directories - cotire_find_closest_relative_path("${_headerFile}" "${_insideIncludeDirs}" _insideRelPath) - if (_insideRelPath) - # header is inside, but could be become outside if there is a shorter outside match - cotire_find_closest_relative_path("${_headerFile}" "${_outsideIncludeDirs}" _outsideRelPath) - if (_outsideRelPath) - string (LENGTH "${_insideRelPath}" _insideRelPathLen) - string (LENGTH "${_outsideRelPath}" _outsideRelPathLen) - if (_outsideRelPathLen LESS _insideRelPathLen) - set (${_headerIsInside} FALSE) - else() - set (${_headerIsInside} TRUE) - endif() - else() - set (${_headerIsInside} TRUE) - endif() - else() - # header is outside - set (${_headerIsInside} FALSE) - endif() -endmacro() - -macro (cotire_check_ignore_header_file_path _headerFile _headerIsIgnoredVar) - if (NOT EXISTS "${_headerFile}") - set (${_headerIsIgnoredVar} TRUE) - elseif (IS_DIRECTORY "${_headerFile}") - set (${_headerIsIgnoredVar} TRUE) - elseif ("${_headerFile}" MATCHES "\\.\\.|[_-]fixed" AND "${_headerFile}" MATCHES "\\.h$") - # heuristic: ignore C headers with embedded parent directory references or "-fixed" or "_fixed" in path - # these often stem from using GCC #include_next tricks, which may break the precompiled header compilation - # with the error message "error: no include path in which to search for header.h" - set (${_headerIsIgnoredVar} TRUE) - else() - set (${_headerIsIgnoredVar} FALSE) - endif() -endmacro() - -macro (cotire_check_ignore_header_file_ext _headerFile _ignoreExtensionsVar _headerIsIgnoredVar) - # check header file extension - cotire_get_source_file_extension("${_headerFile}" _headerFileExt) - set (${_headerIsIgnoredVar} FALSE) - if (_headerFileExt) - list (FIND ${_ignoreExtensionsVar} "${_headerFileExt}" _index) - if (_index GREATER -1) - set (${_headerIsIgnoredVar} TRUE) - endif() - endif() -endmacro() - -macro (cotire_parse_line _line _headerFileVar _headerDepthVar) - if (MSVC) - # cl.exe /showIncludes output looks different depending on the language pack used, e.g.: - # English: "Note: including file: C:\directory\file" - # German: "Hinweis: Einlesen der Datei: C:\directory\file" - # We use a very general regular expression, relying on the presence of the : characters - if (_line MATCHES "( +)([a-zA-Z]:[^:]+)$") - # Visual Studio compiler output - string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) - get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" ABSOLUTE) - else() - set (${_headerFileVar} "") - set (${_headerDepthVar} 0) - endif() - else() - if (_line MATCHES "^(\\.+) (.*)$") - # GCC like output - string (LENGTH "${CMAKE_MATCH_1}" ${_headerDepthVar}) - if (IS_ABSOLUTE "${CMAKE_MATCH_2}") - set (${_headerFileVar} "${CMAKE_MATCH_2}") - else() - get_filename_component(${_headerFileVar} "${CMAKE_MATCH_2}" REALPATH) - endif() - else() - set (${_headerFileVar} "") - set (${_headerDepthVar} 0) - endif() - endif() -endmacro() - -function (cotire_parse_includes _language _scanOutput _ignoredIncludeDirs _honoredIncludeDirs _ignoredExtensions _selectedIncludesVar _unparsedLinesVar) - if (WIN32) - # prevent CMake macro invocation errors due to backslash characters in Windows paths - string (REPLACE "\\" "/" _scanOutput "${_scanOutput}") - endif() - # canonize slashes - string (REPLACE "//" "/" _scanOutput "${_scanOutput}") - # prevent semicolon from being interpreted as a line separator - string (REPLACE ";" "\\;" _scanOutput "${_scanOutput}") - # then separate lines - string (REGEX REPLACE "\n" ";" _scanOutput "${_scanOutput}") - list (LENGTH _scanOutput _len) - # remove duplicate lines to speed up parsing - list (REMOVE_DUPLICATES _scanOutput) - list (LENGTH _scanOutput _uniqueLen) - if (COTIRE_VERBOSE OR COTIRE_DEBUG) - message (STATUS "Scanning ${_uniqueLen} unique lines of ${_len} for includes") - if (_ignoredExtensions) - message (STATUS "Ignored extensions: ${_ignoredExtensions}") - endif() - if (_ignoredIncludeDirs) - message (STATUS "Ignored paths: ${_ignoredIncludeDirs}") - endif() - if (_honoredIncludeDirs) - message (STATUS "Included paths: ${_honoredIncludeDirs}") - endif() - endif() - set (_sourceFiles ${ARGN}) - set (_selectedIncludes "") - set (_unparsedLines "") - # stack keeps track of inside/outside project status of processed header files - set (_headerIsInsideStack "") - foreach (_line IN LISTS _scanOutput) - if (_line) - cotire_parse_line("${_line}" _headerFile _headerDepth) - if (_headerFile) - cotire_check_header_file_location("${_headerFile}" "${_ignoredIncludeDirs}" "${_honoredIncludeDirs}" _headerIsInside) - if (COTIRE_DEBUG) - message (STATUS "${_headerDepth}: ${_headerFile} ${_headerIsInside}") - endif() - # update stack - list (LENGTH _headerIsInsideStack _stackLen) - if (_headerDepth GREATER _stackLen) - math (EXPR _stackLen "${_stackLen} + 1") - foreach (_index RANGE ${_stackLen} ${_headerDepth}) - list (APPEND _headerIsInsideStack ${_headerIsInside}) - endforeach() - else() - foreach (_index RANGE ${_headerDepth} ${_stackLen}) - list (REMOVE_AT _headerIsInsideStack -1) - endforeach() - list (APPEND _headerIsInsideStack ${_headerIsInside}) - endif() - if (COTIRE_DEBUG) - message (STATUS "${_headerIsInsideStack}") - endif() - # header is a candidate if it is outside project - if (NOT _headerIsInside) - # get parent header file's inside/outside status - if (_headerDepth GREATER 1) - math (EXPR _index "${_headerDepth} - 2") - list (GET _headerIsInsideStack ${_index} _parentHeaderIsInside) - else() - set (_parentHeaderIsInside TRUE) - endif() - # select header file if parent header file is inside project - # (e.g., a project header file that includes a standard header file) - if (_parentHeaderIsInside) - cotire_check_ignore_header_file_path("${_headerFile}" _headerIsIgnored) - if (NOT _headerIsIgnored) - cotire_check_ignore_header_file_ext("${_headerFile}" _ignoredExtensions _headerIsIgnored) - if (NOT _headerIsIgnored) - list (APPEND _selectedIncludes "${_headerFile}") - else() - # fix header's inside status on stack, it is ignored by extension now - list (REMOVE_AT _headerIsInsideStack -1) - list (APPEND _headerIsInsideStack TRUE) - endif() - endif() - if (COTIRE_DEBUG) - message (STATUS "${_headerFile} ${_ignoredExtensions} ${_headerIsIgnored}") - endif() - endif() - endif() - else() - if (MSVC) - # for cl.exe do not keep unparsed lines which solely consist of a source file name - string (FIND "${_sourceFiles}" "${_line}" _index) - if (_index LESS 0) - list (APPEND _unparsedLines "${_line}") - endif() - else() - list (APPEND _unparsedLines "${_line}") - endif() - endif() - endif() - endforeach() - list (REMOVE_DUPLICATES _selectedIncludes) - set (${_selectedIncludesVar} ${_selectedIncludes} PARENT_SCOPE) - set (${_unparsedLinesVar} ${_unparsedLines} PARENT_SCOPE) -endfunction() - -function (cotire_scan_includes _includesVar) - set(_options "") - set(_oneValueArgs COMPILER_ID COMPILER_EXECUTABLE COMPILER_VERSION LANGUAGE UNPARSED_LINES) - set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES - IGNORE_PATH INCLUDE_PATH IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_LANGUAGE) - set (_option_LANGUAGE "CXX") - endif() - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - if (NOT _option_COMPILER_VERSION) - set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") - endif() - cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") - cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) - cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) - cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_makedep_flags("${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" _cmd) - # only consider existing source files for scanning - set (_existingSourceFiles "") - foreach (_sourceFile ${_sourceFiles}) - if (EXISTS "${_sourceFile}") - list (APPEND _existingSourceFiles "${_sourceFile}") - endif() - endforeach() - if (NOT _existingSourceFiles) - set (${_includesVar} "" PARENT_SCOPE) - return() - endif() - list (APPEND _cmd ${_existingSourceFiles}) - if (COTIRE_VERBOSE) - message (STATUS "execute_process: ${_cmd}") - endif() - if (_option_COMPILER_ID MATCHES "MSVC") - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - endif() - execute_process( - COMMAND ${_cmd} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE _result - OUTPUT_QUIET - ERROR_VARIABLE _output) - if (_result) - message (STATUS "Result ${_result} scanning includes of ${_existingSourceFiles}.") - endif() - cotire_parse_includes( - "${_option_LANGUAGE}" "${_output}" - "${_option_IGNORE_PATH}" "${_option_INCLUDE_PATH}" - "${_option_IGNORE_EXTENSIONS}" - _includes _unparsedLines - ${_sourceFiles}) - if (_option_INCLUDE_PRIORITY_PATH) - set (_sortedIncludes "") - foreach (_priorityPath ${_option_INCLUDE_PRIORITY_PATH}) - foreach (_include ${_includes}) - string (FIND ${_include} ${_priorityPath} _position) - if (_position GREATER -1) - list (APPEND _sortedIncludes ${_include}) - endif() - endforeach() - endforeach() - if (_sortedIncludes) - list (INSERT _includes 0 ${_sortedIncludes}) - list (REMOVE_DUPLICATES _includes) - endif() - endif() - set (${_includesVar} ${_includes} PARENT_SCOPE) - if (_option_UNPARSED_LINES) - set (${_option_UNPARSED_LINES} ${_unparsedLines} PARENT_SCOPE) - endif() -endfunction() - -macro (cotire_append_undefs _contentsVar) - set (_undefs ${ARGN}) - if (_undefs) - list (REMOVE_DUPLICATES _undefs) - foreach (_definition ${_undefs}) - list (APPEND ${_contentsVar} "#undef ${_definition}") - endforeach() - endif() -endmacro() - -macro (cotire_comment_str _language _commentText _commentVar) - if ("${_language}" STREQUAL "CMAKE") - set (${_commentVar} "# ${_commentText}") - else() - set (${_commentVar} "/* ${_commentText} */") - endif() -endmacro() - -function (cotire_write_file _language _file _contents _force) - get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) - cotire_comment_str("${_language}" "${_moduleName} ${COTIRE_CMAKE_MODULE_VERSION} generated file" _header1) - cotire_comment_str("${_language}" "${_file}" _header2) - set (_contents "${_header1}\n${_header2}\n${_contents}") - if (COTIRE_DEBUG) - message (STATUS "${_contents}") - endif() - if (_force OR NOT EXISTS "${_file}") - file (WRITE "${_file}" "${_contents}") - else() - file (READ "${_file}" _oldContents) - if (NOT "${_oldContents}" STREQUAL "${_contents}") - file (WRITE "${_file}" "${_contents}") - else() - if (COTIRE_DEBUG) - message (STATUS "${_file} unchanged") - endif() - endif() - endif() -endfunction() - -function (cotire_generate_unity_source _unityFile) - set(_options "") - set(_oneValueArgs LANGUAGE) - set(_multiValueArgs - DEPENDS SOURCES_COMPILE_DEFINITIONS - PRE_UNDEFS SOURCES_PRE_UNDEFS POST_UNDEFS SOURCES_POST_UNDEFS PROLOGUE EPILOGUE) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (_option_DEPENDS) - cotire_check_file_up_to_date(_unityFileIsUpToDate "${_unityFile}" ${_option_DEPENDS}) - if (_unityFileIsUpToDate) - return() - endif() - endif() - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - if (NOT _option_PRE_UNDEFS) - set (_option_PRE_UNDEFS "") - endif() - if (NOT _option_SOURCES_PRE_UNDEFS) - set (_option_SOURCES_PRE_UNDEFS "") - endif() - if (NOT _option_POST_UNDEFS) - set (_option_POST_UNDEFS "") - endif() - if (NOT _option_SOURCES_POST_UNDEFS) - set (_option_SOURCES_POST_UNDEFS "") - endif() - set (_contents "") - if (_option_PROLOGUE) - list (APPEND _contents ${_option_PROLOGUE}) - endif() - if (_option_LANGUAGE AND _sourceFiles) - if ("${_option_LANGUAGE}" STREQUAL "CXX") - list (APPEND _contents "#ifdef __cplusplus") - elseif ("${_option_LANGUAGE}" STREQUAL "C") - list (APPEND _contents "#ifndef __cplusplus") - endif() - endif() - set (_compileUndefinitions "") - foreach (_sourceFile ${_sourceFiles}) - cotire_get_source_compile_definitions( - "${_option_CONFIGURATION}" "${_option_LANGUAGE}" "${_sourceFile}" _compileDefinitions - ${_option_SOURCES_COMPILE_DEFINITIONS}) - cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_PRE_UNDEFS _sourcePreUndefs ${_option_SOURCES_PRE_UNDEFS}) - cotire_get_source_undefs("${_sourceFile}" COTIRE_UNITY_SOURCE_POST_UNDEFS _sourcePostUndefs ${_option_SOURCES_POST_UNDEFS}) - if (_option_PRE_UNDEFS) - list (APPEND _compileUndefinitions ${_option_PRE_UNDEFS}) - endif() - if (_sourcePreUndefs) - list (APPEND _compileUndefinitions ${_sourcePreUndefs}) - endif() - if (_compileUndefinitions) - cotire_append_undefs(_contents ${_compileUndefinitions}) - set (_compileUndefinitions "") - endif() - if (_sourcePostUndefs) - list (APPEND _compileUndefinitions ${_sourcePostUndefs}) - endif() - if (_option_POST_UNDEFS) - list (APPEND _compileUndefinitions ${_option_POST_UNDEFS}) - endif() - foreach (_definition ${_compileDefinitions}) - if (_definition MATCHES "^([a-zA-Z0-9_]+)=(.+)$") - list (APPEND _contents "#define ${CMAKE_MATCH_1} ${CMAKE_MATCH_2}") - list (INSERT _compileUndefinitions 0 "${CMAKE_MATCH_1}") - else() - list (APPEND _contents "#define ${_definition}") - list (INSERT _compileUndefinitions 0 "${_definition}") - endif() - endforeach() - # use absolute path as source file location - get_filename_component(_sourceFileLocation "${_sourceFile}" ABSOLUTE) - if (WIN32) - file (TO_NATIVE_PATH "${_sourceFileLocation}" _sourceFileLocation) - endif() - list (APPEND _contents "#include \"${_sourceFileLocation}\"") - endforeach() - if (_compileUndefinitions) - cotire_append_undefs(_contents ${_compileUndefinitions}) - set (_compileUndefinitions "") - endif() - if (_option_LANGUAGE AND _sourceFiles) - list (APPEND _contents "#endif") - endif() - if (_option_EPILOGUE) - list (APPEND _contents ${_option_EPILOGUE}) - endif() - list (APPEND _contents "") - string (REPLACE ";" "\n" _contents "${_contents}") - if (COTIRE_VERBOSE) - message ("${_contents}") - endif() - cotire_write_file("${_option_LANGUAGE}" "${_unityFile}" "${_contents}" TRUE) -endfunction() - -function (cotire_generate_prefix_header _prefixFile) - set(_options "") - set(_oneValueArgs LANGUAGE COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION) - set(_multiValueArgs DEPENDS COMPILE_DEFINITIONS COMPILE_FLAGS - INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES IGNORE_PATH INCLUDE_PATH - IGNORE_EXTENSIONS INCLUDE_PRIORITY_PATH) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - if (NOT _option_COMPILER_VERSION) - set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") - endif() - if (_option_DEPENDS) - cotire_check_file_up_to_date(_prefixFileIsUpToDate "${_prefixFile}" ${_option_DEPENDS}) - if (_prefixFileIsUpToDate) - # create empty log file - set (_unparsedLinesFile "${_prefixFile}.log") - file (WRITE "${_unparsedLinesFile}" "") - return() - endif() - endif() - set (_prologue "") - set (_epilogue "") - if (_option_COMPILER_ID MATCHES "Clang") - set (_prologue "#pragma clang system_header") - elseif (_option_COMPILER_ID MATCHES "GNU") - set (_prologue "#pragma GCC system_header") - elseif (_option_COMPILER_ID MATCHES "MSVC") - set (_prologue "#pragma warning(push, 0)") - set (_epilogue "#pragma warning(pop)") - elseif (_option_COMPILER_ID MATCHES "Intel") - # Intel compiler requires hdrstop pragma to stop generating PCH file - set (_epilogue "#pragma hdrstop") - endif() - set (_sourceFiles ${_option_UNPARSED_ARGUMENTS}) - cotire_scan_includes(_selectedHeaders ${_sourceFiles} - LANGUAGE "${_option_LANGUAGE}" - COMPILER_EXECUTABLE "${_option_COMPILER_EXECUTABLE}" - COMPILER_ID "${_option_COMPILER_ID}" - COMPILER_VERSION "${_option_COMPILER_VERSION}" - COMPILE_DEFINITIONS ${_option_COMPILE_DEFINITIONS} - COMPILE_FLAGS ${_option_COMPILE_FLAGS} - INCLUDE_DIRECTORIES ${_option_INCLUDE_DIRECTORIES} - SYSTEM_INCLUDE_DIRECTORIES ${_option_SYSTEM_INCLUDE_DIRECTORIES} - IGNORE_PATH ${_option_IGNORE_PATH} - INCLUDE_PATH ${_option_INCLUDE_PATH} - IGNORE_EXTENSIONS ${_option_IGNORE_EXTENSIONS} - INCLUDE_PRIORITY_PATH ${_option_INCLUDE_PRIORITY_PATH} - UNPARSED_LINES _unparsedLines) - cotire_generate_unity_source("${_prefixFile}" - PROLOGUE ${_prologue} EPILOGUE ${_epilogue} LANGUAGE "${_option_LANGUAGE}" ${_selectedHeaders}) - set (_unparsedLinesFile "${_prefixFile}.log") - if (_unparsedLines) - if (COTIRE_VERBOSE OR NOT _selectedHeaders) - list (LENGTH _unparsedLines _skippedLineCount) - message (STATUS "${_skippedLineCount} line(s) skipped, see ${_unparsedLinesFile}") - endif() - string (REPLACE ";" "\n" _unparsedLines "${_unparsedLines}") - endif() - file (WRITE "${_unparsedLinesFile}" "${_unparsedLines}") -endfunction() - -function (cotire_add_makedep_flags _language _compilerID _compilerVersion _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - # cl.exe options used - # /nologo suppresses display of sign-on banner - # /TC treat all files named on the command line as C source files - # /TP treat all files named on the command line as C++ source files - # /EP preprocess to stdout without #line directives - # /showIncludes list include files - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /showIncludes) - else() - # return as a flag string - set (_flags "${_sourceFileType${_language}} /EP /showIncludes") - endif() - elseif (_compilerID MATCHES "GNU") - # GCC options used - # -H print the name of each header file used - # -E invoke preprocessor - # -fdirectives-only do not expand macros, requires GCC >= 4.3 - if (_flags) - # append to list - list (APPEND _flags -H -E) - if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") - list (APPEND _flags "-fdirectives-only") - endif() - else() - # return as a flag string - set (_flags "-H -E") - if (NOT "${_compilerVersion}" VERSION_LESS "4.3.0") - set (_flags "${_flags} -fdirectives-only") - endif() - endif() - elseif (_compilerID MATCHES "Clang") - # Clang options used - # -H print the name of each header file used - # -E invoke preprocessor - # -fno-color-diagnostics don't prints diagnostics in color - if (_flags) - # append to list - list (APPEND _flags -H -E -fno-color-diagnostics) - else() - # return as a flag string - set (_flags "-H -E -fno-color-diagnostics") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - # Windows Intel options used - # /nologo do not display compiler version information - # /QH display the include file order - # /EP preprocess to stdout, omitting #line directives - # /TC process all source or unrecognized file types as C source files - # /TP process all source or unrecognized file types as C++ source files - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" /EP /QH) - else() - # return as a flag string - set (_flags "${_sourceFileType${_language}} /EP /QH") - endif() - else() - # Linux / Mac OS X Intel options used - # -H print the name of each header file used - # -EP preprocess to stdout, omitting #line directives - # -Kc++ process all source or unrecognized file types as C++ source files - if (_flags) - # append to list - if ("${_language}" STREQUAL "CXX") - list (APPEND _flags -Kc++) - endif() - list (APPEND _flags -H -EP) - else() - # return as a flag string - if ("${_language}" STREQUAL "CXX") - set (_flags "-Kc++ ") - endif() - set (_flags "${_flags}-H -EP") - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_add_pch_compilation_flags _language _compilerID _compilerVersion _prefixFile _pchFile _hostFile _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) - # cl.exe options used - # /Yc creates a precompiled header file - # /Fp specifies precompiled header binary file name - # /FI forces inclusion of file - # /TC treat all files named on the command line as C source files - # /TP treat all files named on the command line as C++ source files - # /Zs syntax check only - # /Zm precompiled header memory allocation scaling factor - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" - "/Yc${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - else() - # return as a flag string - set (_flags "/Yc\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - endif() - elseif (_compilerID MATCHES "GNU|Clang") - # GCC / Clang options used - # -x specify the source language - # -c compile but do not link - # -o place output in file - # note that we cannot use -w to suppress all warnings upon pre-compiling, because turning off a warning may - # alter compile flags as a side effect (e.g., -Wwrite-string implies -fconst-strings) - set (_xLanguage_C "c-header") - set (_xLanguage_CXX "c++-header") - if (_flags) - # append to list - list (APPEND _flags "-x" "${_xLanguage_${_language}}" "-c" "${_prefixFile}" -o "${_pchFile}") - else() - # return as a flag string - set (_flags "-x ${_xLanguage_${_language}} -c \"${_prefixFile}\" -o \"${_pchFile}\"") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - file (TO_NATIVE_PATH "${_hostFile}" _hostFileNative) - # Windows Intel options used - # /nologo do not display compiler version information - # /Yc create a precompiled header (PCH) file - # /Fp specify a path or file name for precompiled header files - # /FI tells the preprocessor to include a specified file name as the header file - # /TC process all source or unrecognized file types as C source files - # /TP process all source or unrecognized file types as C++ source files - # /Zs syntax check only - # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - set (_sourceFileTypeC "/TC") - set (_sourceFileTypeCXX "/TP") - if (_flags) - # append to list - list (APPEND _flags /nologo "${_sourceFileType${_language}}" - "/Yc" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}" /Zs "${_hostFileNative}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "/Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "/Yc /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} /Wpch-messages") - endif() - endif() - else() - # Linux / Mac OS X Intel options used - # -pch-dir location for precompiled header files - # -pch-create name of the precompiled header (PCH) to create - # -Kc++ process all source or unrecognized file types as C++ source files - # -fsyntax-only check only for correct syntax - # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - get_filename_component(_pchDir "${_pchFile}" DIRECTORY) - get_filename_component(_pchName "${_pchFile}" NAME) - set (_xLanguage_C "c-header") - set (_xLanguage_CXX "c++-header") - if (_flags) - # append to list - if ("${_language}" STREQUAL "CXX") - list (APPEND _flags -Kc++) - endif() - list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-create" "${_pchName}" "-fsyntax-only" "${_hostFile}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "-Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-create \"${_pchName}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} -Wpch-messages") - endif() - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_add_prefix_pch_inclusion_flags _language _compilerID _compilerVersion _prefixFile _pchFile _flagsVar) - set (_flags ${${_flagsVar}}) - if (_compilerID MATCHES "MSVC") - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - # cl.exe options used - # /Yu uses a precompiled header file during build - # /Fp specifies precompiled header binary file name - # /FI forces inclusion of file - # /Zm precompiled header memory allocation scaling factor - if (_pchFile) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - if (_flags) - # append to list - list (APPEND _flags "/Yu${_prefixFileNative}" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - list (APPEND _flags "/Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - else() - # return as a flag string - set (_flags "/Yu\"${_prefixFileNative}\" /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (COTIRE_PCH_MEMORY_SCALING_FACTOR) - set (_flags "${_flags} /Zm${COTIRE_PCH_MEMORY_SCALING_FACTOR}") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/FI\"${_prefixFileNative}\"") - endif() - endif() - elseif (_compilerID MATCHES "GNU") - # GCC options used - # -include process include file as the first line of the primary source file - # -Winvalid-pch warns if precompiled header is found but cannot be used - # note: ccache requires the -include flag to be used in order to process precompiled header correctly - if (_flags) - # append to list - list (APPEND _flags "-Winvalid-pch" "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-Winvalid-pch -include \"${_prefixFile}\"") - endif() - elseif (_compilerID MATCHES "Clang") - # Clang options used - # -include process include file as the first line of the primary source file - # -include-pch include precompiled header file - # -Qunused-arguments don't emit warning for unused driver arguments - # note: ccache requires the -include flag to be used in order to process precompiled header correctly - if (_flags) - # append to list - list (APPEND _flags "-Qunused-arguments" "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-Qunused-arguments -include \"${_prefixFile}\"") - endif() - elseif (_compilerID MATCHES "Intel") - if (WIN32) - file (TO_NATIVE_PATH "${_prefixFile}" _prefixFileNative) - # Windows Intel options used - # /Yu use a precompiled header (PCH) file - # /Fp specify a path or file name for precompiled header files - # /FI tells the preprocessor to include a specified file name as the header file - # /Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - if (_pchFile) - file (TO_NATIVE_PATH "${_pchFile}" _pchFileNative) - if (_flags) - # append to list - list (APPEND _flags "/Yu" "/Fp${_pchFileNative}" "/FI${_prefixFileNative}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "/Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "/Yu /Fp\"${_pchFileNative}\" /FI\"${_prefixFileNative}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} /Wpch-messages") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "/FI${_prefixFileNative}") - else() - # return as a flag string - set (_flags "/FI\"${_prefixFileNative}\"") - endif() - endif() - else() - # Linux / Mac OS X Intel options used - # -pch-dir location for precompiled header files - # -pch-use name of the precompiled header (PCH) to use - # -include process include file as the first line of the primary source file - # -Wpch-messages enable diagnostics related to pre-compiled headers (requires Intel XE 2013 Update 2) - if (_pchFile) - get_filename_component(_pchDir "${_pchFile}" DIRECTORY) - get_filename_component(_pchName "${_pchFile}" NAME) - if (_flags) - # append to list - list (APPEND _flags "-include" "${_prefixFile}" "-pch-dir" "${_pchDir}" "-pch-use" "${_pchName}") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - list (APPEND _flags "-Wpch-messages") - endif() - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\" -pch-dir \"${_pchDir}\" -pch-use \"${_pchName}\"") - if (NOT "${_compilerVersion}" VERSION_LESS "13.1.0") - set (_flags "${_flags} -Wpch-messages") - endif() - endif() - else() - # no precompiled header, force inclusion of prefix header - if (_flags) - # append to list - list (APPEND _flags "-include" "${_prefixFile}") - else() - # return as a flag string - set (_flags "-include \"${_prefixFile}\"") - endif() - endif() - endif() - else() - message (FATAL_ERROR "cotire: unsupported ${_language} compiler ${_compilerID} version ${_compilerVersion}.") - endif() - set (${_flagsVar} ${_flags} PARENT_SCOPE) -endfunction() - -function (cotire_precompile_prefix_header _prefixFile _pchFile _hostFile) - set(_options "") - set(_oneValueArgs COMPILER_EXECUTABLE COMPILER_ID COMPILER_VERSION LANGUAGE) - set(_multiValueArgs COMPILE_DEFINITIONS COMPILE_FLAGS INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES SYS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_LANGUAGE) - set (_option_LANGUAGE "CXX") - endif() - if (NOT _option_COMPILER_ID) - set (_option_COMPILER_ID "${CMAKE_${_option_LANGUAGE}_ID}") - endif() - if (NOT _option_COMPILER_VERSION) - set (_option_COMPILER_VERSION "${CMAKE_${_option_LANGUAGE}_COMPILER_VERSION}") - endif() - cotire_init_compile_cmd(_cmd "${_option_LANGUAGE}" "${_option_COMPILER_EXECUTABLE}" "${_option_COMPILER_ARG1}") - cotire_add_definitions_to_cmd(_cmd "${_option_LANGUAGE}" ${_option_COMPILE_DEFINITIONS}) - cotire_add_compile_flags_to_cmd(_cmd ${_option_COMPILE_FLAGS}) - cotire_add_includes_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_frameworks_to_cmd(_cmd "${_option_LANGUAGE}" _option_INCLUDE_DIRECTORIES _option_SYSTEM_INCLUDE_DIRECTORIES) - cotire_add_pch_compilation_flags( - "${_option_LANGUAGE}" "${_option_COMPILER_ID}" "${_option_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" "${_hostFile}" _cmd) - if (COTIRE_VERBOSE) - message (STATUS "execute_process: ${_cmd}") - endif() - if (_option_COMPILER_ID MATCHES "MSVC") - # cl.exe messes with the output streams unless the environment variable VS_UNICODE_OUTPUT is cleared - unset (ENV{VS_UNICODE_OUTPUT}) - endif() - execute_process( - COMMAND ${_cmd} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - RESULT_VARIABLE _result) - if (_result) - message (FATAL_ERROR "cotire: error ${_result} precompiling ${_prefixFile}.") - endif() -endfunction() - -function (cotire_check_precompiled_header_support _language _target _msgVar) - set (_unsupportedCompiler - "Precompiled headers not supported for ${_language} compiler ${CMAKE_${_language}_COMPILER_ID}") - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") - # supported since Visual Studio C++ 6.0 - # and CMake does not support an earlier version - set (${_msgVar} "" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") - # GCC PCH support requires version >= 3.4 - if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "3.4.0") - set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) - else() - set (${_msgVar} "" PARENT_SCOPE) - endif() - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") - # all Clang versions have PCH support - set (${_msgVar} "" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") - # Intel PCH support requires version >= 8.0.0 - if ("${CMAKE_${_language}_COMPILER_VERSION}" VERSION_LESS "8.0.0") - set (${_msgVar} "${_unsupportedCompiler} version ${CMAKE_${_language}_COMPILER_VERSION}." PARENT_SCOPE) - else() - set (${_msgVar} "" PARENT_SCOPE) - endif() - else() - set (${_msgVar} "${_unsupportedCompiler}." PARENT_SCOPE) - endif() - if (CMAKE_${_language}_COMPILER MATCHES "ccache") - if (NOT "$ENV{CCACHE_SLOPPINESS}" MATCHES "time_macros|pch_defines") - set (${_msgVar} - "ccache requires the environment variable CCACHE_SLOPPINESS to be set to \"pch_defines,time_macros\"." - PARENT_SCOPE) - endif() - endif() - if (APPLE) - # PCH compilation not supported by GCC / Clang for multi-architecture builds (e.g., i386, x86_64) - cotire_get_configuration_types(_configs) - foreach (_config ${_configs}) - set (_targetFlags "") - cotire_get_target_compile_flags("${_config}" "${_language}" "${_target}" _targetFlags) - cotire_filter_compile_flags("${_language}" "arch" _architectures _ignore ${_targetFlags}) - list (LENGTH _architectures _numberOfArchitectures) - if (_numberOfArchitectures GREATER 1) - string (REPLACE ";" ", " _architectureStr "${_architectures}") - set (${_msgVar} - "Precompiled headers not supported on Darwin for multi-architecture builds (${_architectureStr})." - PARENT_SCOPE) - break() - endif() - endforeach() - endif() -endfunction() - -macro (cotire_get_intermediate_dir _cotireDir) - # ${CMAKE_CFG_INTDIR} may reference a build-time variable when using a generator which supports configuration types - get_filename_component(${_cotireDir} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${COTIRE_INTDIR}" ABSOLUTE) -endmacro() - -macro (cotire_setup_file_extension_variables) - set (_unityFileExt_C ".c") - set (_unityFileExt_CXX ".cxx") - set (_prefixFileExt_C ".h") - set (_prefixFileExt_CXX ".hxx") - set (_prefixSourceFileExt_C ".c") - set (_prefixSourceFileExt_CXX ".cxx") -endmacro() - -function (cotire_make_single_unity_source_file_path _language _target _unityFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _unityFileExt_${_language}) - set (${_unityFileVar} "" PARENT_SCOPE) - return() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - set (_unityFileName "${_unityFileBaseName}${_unityFileExt_${_language}}") - cotire_get_intermediate_dir(_baseDir) - set (_unityFile "${_baseDir}/${_unityFileName}") - set (${_unityFileVar} "${_unityFile}" PARENT_SCOPE) -endfunction() - -function (cotire_make_unity_source_file_paths _language _target _maxIncludes _unityFilesVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _unityFileExt_${_language}) - set (${_unityFileVar} "" PARENT_SCOPE) - return() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - cotire_get_intermediate_dir(_baseDir) - set (_startIndex 0) - set (_index 0) - set (_unityFiles "") - set (_sourceFiles ${ARGN}) - foreach (_sourceFile ${_sourceFiles}) - get_source_file_property(_startNew "${_sourceFile}" COTIRE_START_NEW_UNITY_SOURCE) - math (EXPR _unityFileCount "${_index} - ${_startIndex}") - if (_startNew OR (_maxIncludes GREATER 0 AND NOT _unityFileCount LESS _maxIncludes)) - if (_index GREATER 0) - # start new unity file segment - math (EXPR _endIndex "${_index} - 1") - set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") - list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") - endif() - set (_startIndex ${_index}) - endif() - math (EXPR _index "${_index} + 1") - endforeach() - list (LENGTH _sourceFiles _numberOfSources) - if (_startIndex EQUAL 0) - # there is only a single unity file - cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFiles) - elseif (_startIndex LESS _numberOfSources) - # end with final unity file segment - math (EXPR _endIndex "${_index} - 1") - set (_unityFileName "${_unityFileBaseName}_${_startIndex}_${_endIndex}${_unityFileExt_${_language}}") - list (APPEND _unityFiles "${_baseDir}/${_unityFileName}") - endif() - set (${_unityFilesVar} ${_unityFiles} PARENT_SCOPE) - if (COTIRE_DEBUG AND _unityFiles) - message (STATUS "unity files: ${_unityFiles}") - endif() -endfunction() - -function (cotire_unity_to_prefix_file_path _language _target _unityFile _prefixFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _unityFileExt_${_language}) - set (${_prefixFileVar} "" PARENT_SCOPE) - return() - endif() - set (_unityFileBaseName "${_target}_${_language}${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}") - set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - string (REPLACE "${_unityFileBaseName}" "${_prefixFileBaseName}" _prefixFile "${_unityFile}") - string (REGEX REPLACE "${_unityFileExt_${_language}}$" "${_prefixFileExt_${_language}}" _prefixFile "${_prefixFile}") - set (${_prefixFileVar} "${_prefixFile}" PARENT_SCOPE) -endfunction() - -function (cotire_prefix_header_to_source_file_path _language _prefixHeaderFile _prefixSourceFileVar) - cotire_setup_file_extension_variables() - if (NOT DEFINED _prefixSourceFileExt_${_language}) - set (${_prefixSourceFileVar} "" PARENT_SCOPE) - return() - endif() - string (REGEX REPLACE "${_prefixFileExt_${_language}}$" "${_prefixSourceFileExt_${_language}}" _prefixSourceFile "${_prefixHeaderFile}") - set (${_prefixSourceFileVar} "${_prefixSourceFile}" PARENT_SCOPE) -endfunction() - -function (cotire_make_prefix_file_name _language _target _prefixFileBaseNameVar _prefixFileNameVar) - cotire_setup_file_extension_variables() - if (NOT _language) - set (_prefixFileBaseName "${_target}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_C}") - elseif (DEFINED _prefixFileExt_${_language}) - set (_prefixFileBaseName "${_target}_${_language}${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}") - set (_prefixFileName "${_prefixFileBaseName}${_prefixFileExt_${_language}}") - else() - set (_prefixFileBaseName "") - set (_prefixFileName "") - endif() - set (${_prefixFileBaseNameVar} "${_prefixFileBaseName}" PARENT_SCOPE) - set (${_prefixFileNameVar} "${_prefixFileName}" PARENT_SCOPE) -endfunction() - -function (cotire_make_prefix_file_path _language _target _prefixFileVar) - cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) - set (${_prefixFileVar} "" PARENT_SCOPE) - if (_prefixFileName) - if (NOT _language) - set (_language "C") - endif() - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang|Intel|MSVC") - cotire_get_intermediate_dir(_baseDir) - set (${_prefixFileVar} "${_baseDir}/${_prefixFileName}" PARENT_SCOPE) - endif() - endif() -endfunction() - -function (cotire_make_pch_file_path _language _target _pchFileVar) - cotire_make_prefix_file_name("${_language}" "${_target}" _prefixFileBaseName _prefixFileName) - set (${_pchFileVar} "" PARENT_SCOPE) - if (_prefixFileBaseName AND _prefixFileName) - cotire_check_precompiled_header_support("${_language}" "${_target}" _msg) - if (NOT _msg) - if (XCODE) - # For Xcode, we completely hand off the compilation of the prefix header to the IDE - return() - endif() - cotire_get_intermediate_dir(_baseDir) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC") - # MSVC uses the extension .pch added to the prefix header base name - set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Clang") - # Clang looks for a precompiled header corresponding to the prefix header with the extension .pch appended - set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.pch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "GNU") - # GCC looks for a precompiled header corresponding to the prefix header with the extension .gch appended - set (${_pchFileVar} "${_baseDir}/${_prefixFileName}.gch" PARENT_SCOPE) - elseif (CMAKE_${_language}_COMPILER_ID MATCHES "Intel") - # Intel uses the extension .pchi added to the prefix header base name - set (${_pchFileVar} "${_baseDir}/${_prefixFileBaseName}.pchi" PARENT_SCOPE) - endif() - endif() - endif() -endfunction() - -function (cotire_select_unity_source_files _unityFile _sourcesVar) - set (_sourceFiles ${ARGN}) - if (_sourceFiles AND "${_unityFile}" MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}_([0-9]+)_([0-9]+)") - set (_startIndex ${CMAKE_MATCH_1}) - set (_endIndex ${CMAKE_MATCH_2}) - list (LENGTH _sourceFiles _numberOfSources) - if (NOT _startIndex LESS _numberOfSources) - math (EXPR _startIndex "${_numberOfSources} - 1") - endif() - if (NOT _endIndex LESS _numberOfSources) - math (EXPR _endIndex "${_numberOfSources} - 1") - endif() - set (_files "") - foreach (_index RANGE ${_startIndex} ${_endIndex}) - list (GET _sourceFiles ${_index} _file) - list (APPEND _files "${_file}") - endforeach() - else() - set (_files ${_sourceFiles}) - endif() - set (${_sourcesVar} ${_files} PARENT_SCOPE) -endfunction() - -function (cotire_get_unity_source_dependencies _language _target _dependencySourcesVar) - set (_dependencySources "") - # depend on target's generated source files - get_target_property(_targetSourceFiles ${_target} SOURCES) - cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) - if (_generatedSources) - # but omit all generated source files that have the COTIRE_EXCLUDED property set to true - cotire_get_objects_with_property_on(_excludedGeneratedSources COTIRE_EXCLUDED SOURCE ${_generatedSources}) - if (_excludedGeneratedSources) - list (REMOVE_ITEM _generatedSources ${_excludedGeneratedSources}) - endif() - # and omit all generated source files that have the COTIRE_DEPENDENCY property set to false explicitly - cotire_get_objects_with_property_off(_excludedNonDependencySources COTIRE_DEPENDENCY SOURCE ${_generatedSources}) - if (_excludedNonDependencySources) - list (REMOVE_ITEM _generatedSources ${_excludedNonDependencySources}) - endif() - if (_generatedSources) - list (APPEND _dependencySources ${_generatedSources}) - endif() - endif() - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_language} ${_target} unity source dependencies: ${_dependencySources}") - endif() - set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) -endfunction() - -function (cotire_get_prefix_header_dependencies _language _target _dependencySourcesVar) - set (_dependencySources "") - # depend on target source files marked with custom COTIRE_DEPENDENCY property - get_target_property(_targetSourceFiles ${_target} SOURCES) - cotire_get_objects_with_property_on(_dependencySources COTIRE_DEPENDENCY SOURCE ${_targetSourceFiles}) - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_language} ${_target} prefix header dependencies: ${_dependencySources}") - endif() - set (${_dependencySourcesVar} ${_dependencySources} PARENT_SCOPE) -endfunction() - -function (cotire_generate_target_script _language _configurations _target _targetScriptVar _targetConfigScriptVar) - set (_targetSources ${ARGN}) - cotire_get_prefix_header_dependencies(${_language} ${_target} COTIRE_TARGET_PREFIX_DEPENDS ${_targetSources}) - cotire_get_unity_source_dependencies(${_language} ${_target} COTIRE_TARGET_UNITY_DEPENDS ${_targetSources}) - # set up variables to be configured - set (COTIRE_TARGET_LANGUAGE "${_language}") - get_target_property(COTIRE_TARGET_IGNORE_PATH ${_target} COTIRE_PREFIX_HEADER_IGNORE_PATH) - cotire_add_sys_root_paths(COTIRE_TARGET_IGNORE_PATH) - get_target_property(COTIRE_TARGET_INCLUDE_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PATH) - cotire_add_sys_root_paths(COTIRE_TARGET_INCLUDE_PATH) - get_target_property(COTIRE_TARGET_PRE_UNDEFS ${_target} COTIRE_UNITY_SOURCE_PRE_UNDEFS) - get_target_property(COTIRE_TARGET_POST_UNDEFS ${_target} COTIRE_UNITY_SOURCE_POST_UNDEFS) - get_target_property(COTIRE_TARGET_MAXIMUM_NUMBER_OF_INCLUDES ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) - get_target_property(COTIRE_TARGET_INCLUDE_PRIORITY_PATH ${_target} COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH) - cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_PRE_UNDEFS COTIRE_TARGET_SOURCES_PRE_UNDEFS ${_targetSources}) - cotire_get_source_files_undefs(COTIRE_UNITY_SOURCE_POST_UNDEFS COTIRE_TARGET_SOURCES_POST_UNDEFS ${_targetSources}) - set (COTIRE_TARGET_CONFIGURATION_TYPES "${_configurations}") - foreach (_config ${_configurations}) - string (TOUPPER "${_config}" _upperConfig) - cotire_get_target_include_directories( - "${_config}" "${_language}" "${_target}" COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig} COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}) - cotire_get_target_compile_definitions( - "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}) - cotire_get_target_compiler_flags( - "${_config}" "${_language}" "${_target}" COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}) - cotire_get_source_files_compile_definitions( - "${_config}" "${_language}" COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig} ${_targetSources}) - endforeach() - # set up COTIRE_TARGET_SOURCES - set (COTIRE_TARGET_SOURCES "") - foreach (_sourceFile ${_targetSources}) - get_source_file_property(_generated "${_sourceFile}" GENERATED) - if (_generated) - # use absolute paths for generated files only, retrieving the LOCATION property is an expensive operation - get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) - list (APPEND COTIRE_TARGET_SOURCES "${_sourceLocation}") - else() - list (APPEND COTIRE_TARGET_SOURCES "${_sourceFile}") - endif() - endforeach() - # copy variable definitions to cotire target script - get_cmake_property(_vars VARIABLES) - string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+" _matchVars "${_vars}") - # omit COTIRE_*_INIT variables - string (REGEX MATCHALL "COTIRE_[A-Za-z0-9_]+_INIT" _initVars "${_matchVars}") - if (_initVars) - list (REMOVE_ITEM _matchVars ${_initVars}) - endif() - # omit COTIRE_VERBOSE which is passed as a CMake define on command line - list (REMOVE_ITEM _matchVars COTIRE_VERBOSE) - set (_contents "") - set (_contentsHasGeneratorExpressions FALSE) - foreach (_var IN LISTS _matchVars ITEMS - XCODE MSVC CMAKE_GENERATOR CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES - CMAKE_${_language}_COMPILER_ID CMAKE_${_language}_COMPILER_VERSION - CMAKE_${_language}_COMPILER CMAKE_${_language}_COMPILER_ARG1 - CMAKE_INCLUDE_FLAG_${_language} CMAKE_INCLUDE_FLAG_${_language}_SEP - CMAKE_INCLUDE_SYSTEM_FLAG_${_language} - CMAKE_${_language}_FRAMEWORK_SEARCH_FLAG - CMAKE_${_language}_SYSTEM_FRAMEWORK_SEARCH_FLAG - CMAKE_${_language}_SOURCE_FILE_EXTENSIONS) - if (DEFINED ${_var}) - string (REPLACE "\"" "\\\"" _value "${${_var}}") - set (_contents "${_contents}set (${_var} \"${_value}\")\n") - if (NOT _contentsHasGeneratorExpressions) - if ("${_value}" MATCHES "\\$<.*>") - set (_contentsHasGeneratorExpressions TRUE) - endif() - endif() - endif() - endforeach() - # generate target script file - get_filename_component(_moduleName "${COTIRE_CMAKE_MODULE_FILE}" NAME) - set (_targetCotireScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_moduleName}") - cotire_write_file("CMAKE" "${_targetCotireScript}" "${_contents}" FALSE) - if (_contentsHasGeneratorExpressions) - # use file(GENERATE ...) to expand generator expressions in the target script at CMake generate-time - set (_configNameOrNoneGeneratorExpression "$<$:None>$<$>:$>") - set (_targetCotireConfigScript "${CMAKE_CURRENT_BINARY_DIR}/${_target}_${_language}_${_configNameOrNoneGeneratorExpression}_${_moduleName}") - file (GENERATE OUTPUT "${_targetCotireConfigScript}" INPUT "${_targetCotireScript}") - else() - set (_targetCotireConfigScript "${_targetCotireScript}") - endif() - set (${_targetScriptVar} "${_targetCotireScript}" PARENT_SCOPE) - set (${_targetConfigScriptVar} "${_targetCotireConfigScript}" PARENT_SCOPE) -endfunction() - -function (cotire_setup_pch_file_compilation _language _target _targetScript _prefixFile _pchFile _hostFile) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # for Visual Studio and Intel, we attach the precompiled header compilation to the host file - # the remaining files include the precompiled header, see cotire_setup_pch_file_inclusion - if (_sourceFiles) - set (_flags "") - cotire_add_pch_compilation_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" "${_hostFile}" _flags) - set_property (SOURCE ${_hostFile} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_OUTPUTS "${_pchFile}") - # make object file generated from host file depend on prefix header - set_property (SOURCE ${_hostFile} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") - # mark host file as cotired to prevent it from being used in another cotired target - set_property (SOURCE ${_hostFile} PROPERTY COTIRE_TARGET "${_target}") - endif() - elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # for makefile based generator, we add a custom command to precompile the prefix header - if (_targetScript) - cotire_set_cmd_to_prologue(_cmds) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "precompile" "${_targetScript}" "${_prefixFile}" "${_pchFile}" "${_hostFile}") - file (RELATIVE_PATH _pchFileRelPath "${CMAKE_BINARY_DIR}" "${_pchFile}") - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_pchFile} ${_cmds} DEPENDS ${_prefixFile} IMPLICIT_DEPENDS ${_language} ${_prefixFile}") - endif() - set_property (SOURCE "${_pchFile}" PROPERTY GENERATED TRUE) - add_custom_command( - OUTPUT "${_pchFile}" - COMMAND ${_cmds} - DEPENDS "${_prefixFile}" - IMPLICIT_DEPENDS ${_language} "${_prefixFile}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Building ${_language} precompiled header ${_pchFileRelPath}" - VERBATIM) - endif() - endif() -endfunction() - -function (cotire_setup_pch_file_inclusion _language _target _wholeTarget _prefixFile _pchFile _hostFile) - if (CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # for Visual Studio and Intel, we include the precompiled header in all but the host file - # the host file does the precompiled header compilation, see cotire_setup_pch_file_compilation - set (_sourceFiles ${ARGN}) - list (LENGTH _sourceFiles _numberOfSourceFiles) - if (_numberOfSourceFiles GREATER 0) - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - set (_flags "") - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # make object files generated from source files depend on precompiled header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") - endif() - elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - set (_sourceFiles ${_hostFile} ${ARGN}) - if (NOT _wholeTarget) - # for makefile based generator, we force the inclusion of the prefix header for a subset - # of the source files, if this is a multi-language target or has excluded files - set (_flags "") - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - endif() - # make object files generated from source files depend on precompiled header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_pchFile}") - endif() -endfunction() - -function (cotire_setup_prefix_file_inclusion _language _target _prefixFile) - set (_sourceFiles ${ARGN}) - # force the inclusion of the prefix header for the given source files - set (_flags "") - set (_pchFile "") - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _flags) - set_property (SOURCE ${_sourceFiles} APPEND_STRING PROPERTY COMPILE_FLAGS " ${_flags} ") - # mark sources as cotired to prevent them from being used in another cotired target - set_source_files_properties(${_sourceFiles} PROPERTIES COTIRE_TARGET "${_target}") - # make object files generated from source files depend on prefix header - set_property (SOURCE ${_sourceFiles} APPEND PROPERTY OBJECT_DEPENDS "${_prefixFile}") -endfunction() - -function (cotire_get_first_set_property_value _propertyValueVar _type _object) - set (_properties ${ARGN}) - foreach (_property ${_properties}) - get_property(_propertyValue ${_type} "${_object}" PROPERTY ${_property}) - if (_propertyValue) - set (${_propertyValueVar} ${_propertyValue} PARENT_SCOPE) - return() - endif() - endforeach() - set (${_propertyValueVar} "" PARENT_SCOPE) -endfunction() - -function (cotire_setup_combine_command _language _targetScript _joinedFile _cmdsVar) - set (_files ${ARGN}) - set (_filesPaths "") - foreach (_file ${_files}) - get_filename_component(_filePath "${_file}" ABSOLUTE) - list (APPEND _filesPaths "${_filePath}") - endforeach() - cotire_set_cmd_to_prologue(_prefixCmd) - list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "combine") - if (_targetScript) - list (APPEND _prefixCmd "${_targetScript}") - endif() - list (APPEND _prefixCmd "${_joinedFile}" ${_filesPaths}) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_joinedFile} COMMAND ${_prefixCmd} DEPENDS ${_files}") - endif() - set_property (SOURCE "${_joinedFile}" PROPERTY GENERATED TRUE) - file (RELATIVE_PATH _joinedFileRelPath "${CMAKE_BINARY_DIR}" "${_joinedFile}") - get_filename_component(_joinedFileBaseName "${_joinedFile}" NAME_WE) - get_filename_component(_joinedFileExt "${_joinedFile}" EXT) - if (_language AND _joinedFileBaseName MATCHES "${COTIRE_UNITY_SOURCE_FILENAME_SUFFIX}$") - set (_comment "Generating ${_language} unity source ${_joinedFileRelPath}") - elseif (_language AND _joinedFileBaseName MATCHES "${COTIRE_PREFIX_HEADER_FILENAME_SUFFIX}$") - if (_joinedFileExt MATCHES "^\\.c") - set (_comment "Generating ${_language} prefix source ${_joinedFileRelPath}") - else() - set (_comment "Generating ${_language} prefix header ${_joinedFileRelPath}") - endif() - else() - set (_comment "Generating ${_joinedFileRelPath}") - endif() - add_custom_command( - OUTPUT "${_joinedFile}" - COMMAND ${_prefixCmd} - DEPENDS ${_files} - COMMENT "${_comment}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_target_pch_usage _languages _target _wholeTarget) - if (XCODE) - # for Xcode, we attach a pre-build action to generate the unity sources and prefix headers - set (_prefixFiles "") - foreach (_language ${_languages}) - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_prefixFile) - list (APPEND _prefixFiles "${_prefixFile}") - endif() - endforeach() - set (_cmds ${ARGN}) - list (LENGTH _prefixFiles _numberOfPrefixFiles) - if (_numberOfPrefixFiles GREATER 1) - # we also generate a generic, single prefix header which includes all language specific prefix headers - set (_language "") - set (_targetScript "") - cotire_make_prefix_file_path("${_language}" ${_target} _prefixHeader) - cotire_setup_combine_command("${_language}" "${_targetScript}" "${_prefixHeader}" _cmds ${_prefixFiles}) - else() - set (_prefixHeader "${_prefixFiles}") - endif() - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: TARGET ${_target} PRE_BUILD ${_cmds}") - endif() - # because CMake PRE_BUILD command does not support dependencies, - # we check dependencies explicity in cotire script mode when the pre-build action is run - add_custom_command( - TARGET "${_target}" - PRE_BUILD ${_cmds} - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Updating target ${_target} prefix headers" - VERBATIM) - # make Xcode precompile the generated prefix header with ProcessPCH and ProcessPCH++ - set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES") - set_target_properties(${_target} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${_prefixHeader}") - elseif ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # for makefile based generator, we force inclusion of the prefix header for all target source files - # if this is a single-language target without any excluded files - if (_wholeTarget) - set (_language "${_languages}") - # for Visual Studio and Intel, precompiled header inclusion is always done on the source file level - # see cotire_setup_pch_file_inclusion - if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_prefixFile) - get_property(_pchFile TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER) - set (_options COMPILE_OPTIONS) - cotire_add_prefix_pch_inclusion_flags( - "${_language}" "${CMAKE_${_language}_COMPILER_ID}" "${CMAKE_${_language}_COMPILER_VERSION}" - "${_prefixFile}" "${_pchFile}" _options) - set_property(TARGET ${_target} APPEND PROPERTY ${_options}) - endif() - endif() - endif() - endif() -endfunction() - -function (cotire_setup_unity_generation_commands _language _target _targetScript _targetConfigScript _unityFiles _cmdsVar) - set (_dependencySources "") - cotire_get_unity_source_dependencies(${_language} ${_target} _dependencySources ${ARGN}) - foreach (_unityFile ${_unityFiles}) - set_property (SOURCE "${_unityFile}" PROPERTY GENERATED TRUE) - # set up compiled unity source dependencies via OBJECT_DEPENDS - # this ensures that missing source files are generated before the unity file is compiled - if (COTIRE_DEBUG AND _dependencySources) - message (STATUS "${_unityFile} OBJECT_DEPENDS ${_dependencySources}") - endif() - if (_dependencySources) - # the OBJECT_DEPENDS property requires a list of full paths - set (_objectDependsPaths "") - foreach (_sourceFile ${_dependencySources}) - get_source_file_property(_sourceLocation "${_sourceFile}" LOCATION) - list (APPEND _objectDependsPaths "${_sourceLocation}") - endforeach() - set_property (SOURCE "${_unityFile}" PROPERTY OBJECT_DEPENDS ${_objectDependsPaths}) - endif() - if (WIN32 AND CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # unity file compilation results in potentially huge object file, thus use /bigobj by default unter MSVC and Windows Intel - set_property (SOURCE "${_unityFile}" APPEND_STRING PROPERTY COMPILE_FLAGS "/bigobj") - endif() - cotire_set_cmd_to_prologue(_unityCmd) - list (APPEND _unityCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "unity" "${_targetConfigScript}" "${_unityFile}") - if (CMAKE_VERSION VERSION_LESS "3.1.0") - set (_unityCmdDepends "${_targetScript}") - else() - # CMake 3.1.0 supports generator expressions in arguments to DEPENDS - set (_unityCmdDepends "${_targetConfigScript}") - endif() - file (RELATIVE_PATH _unityFileRelPath "${CMAKE_BINARY_DIR}" "${_unityFile}") - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_unityFile} COMMAND ${_unityCmd} DEPENDS ${_unityCmdDepends}") - endif() - add_custom_command( - OUTPUT "${_unityFile}" - COMMAND ${_unityCmd} - DEPENDS ${_unityCmdDepends} - COMMENT "Generating ${_language} unity source ${_unityFileRelPath}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_unityCmd}) - endforeach() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) - set (_sourceFiles ${ARGN}) - set (_dependencySources "") - cotire_get_prefix_header_dependencies(${_language} ${_target} _dependencySources ${_sourceFiles}) - cotire_set_cmd_to_prologue(_prefixCmd) - list (APPEND _prefixCmd -P "${COTIRE_CMAKE_MODULE_FILE}" "prefix" "${_targetScript}" "${_prefixFile}" ${_unityFiles}) - set_property (SOURCE "${_prefixFile}" PROPERTY GENERATED TRUE) - if (COTIRE_DEBUG) - message (STATUS "add_custom_command: OUTPUT ${_prefixFile} COMMAND ${_prefixCmd} DEPENDS ${_unityFile} ${_dependencySources}") - endif() - file (RELATIVE_PATH _prefixFileRelPath "${CMAKE_BINARY_DIR}" "${_prefixFile}") - get_filename_component(_prefixFileExt "${_prefixFile}" EXT) - if (_prefixFileExt MATCHES "^\\.c") - set (_comment "Generating ${_language} prefix source ${_prefixFileRelPath}") - else() - set (_comment "Generating ${_language} prefix header ${_prefixFileRelPath}") - endif() - # prevent pre-processing errors upon generating the prefix header when a target's generated include file does not yet exist - # we do not add a file-level dependency for the target's generated files though, because we only want to depend on their existence - # thus we make the prefix header generation depend on a custom helper target which triggers the generation of the files - set (_preTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}_pre") - if (TARGET ${_preTargetName}) - # custom helper target has already been generated while processing a different language - list (APPEND _dependencySources ${_preTargetName}) - else() - get_target_property(_targetSourceFiles ${_target} SOURCES) - cotire_get_objects_with_property_on(_generatedSources GENERATED SOURCE ${_targetSourceFiles}) - if (_generatedSources) - add_custom_target("${_preTargetName}" DEPENDS ${_generatedSources}) - cotire_init_target("${_preTargetName}") - list (APPEND _dependencySources ${_preTargetName}) - endif() - endif() - add_custom_command( - OUTPUT "${_prefixFile}" "${_prefixFile}.log" - COMMAND ${_prefixCmd} - DEPENDS ${_unityFiles} ${_dependencySources} - COMMENT "${_comment}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - VERBATIM) - list (APPEND ${_cmdsVar} COMMAND ${_prefixCmd}) - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_from_unity_command _language _target _targetScript _prefixFile _unityFiles _cmdsVar) - set (_sourceFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma - cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) - else() - set (_prefixSourceFile "${_prefixFile}") - endif() - cotire_setup_prefix_generation_command( - ${_language} ${_target} "${_targetScript}" - "${_prefixSourceFile}" "${_unityFiles}" ${_cmdsVar} ${_sourceFiles}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # set up generation of a prefix source file which includes the prefix header - cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_setup_prefix_generation_from_provided_command _language _target _targetScript _prefixFile _cmdsVar) - set (_prefixHeaderFiles ${ARGN}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # GNU and Clang require indirect compilation of the prefix header to make them honor the system_header pragma - cotire_prefix_header_to_source_file_path(${_language} "${_prefixFile}" _prefixSourceFile) - else() - set (_prefixSourceFile "${_prefixFile}") - endif() - cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixSourceFile}" _cmds ${_prefixHeaderFiles}) - if (CMAKE_${_language}_COMPILER_ID MATCHES "GNU|Clang") - # set up generation of a prefix source file which includes the prefix header - cotire_setup_combine_command(${_language} "${_targetScript}" "${_prefixFile}" _cmds ${_prefixSourceFile}) - endif() - set (${_cmdsVar} ${${_cmdsVar}} PARENT_SCOPE) -endfunction() - -function (cotire_init_cotire_target_properties _target) - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER TRUE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD TRUE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_CLEAN FALSE) - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_SOURCE_DIR}") - cotire_check_is_path_relative_to("${CMAKE_BINARY_DIR}" _isRelative "${CMAKE_SOURCE_DIR}") - if (NOT _isRelative) - set_property(TARGET ${_target} APPEND PROPERTY COTIRE_PREFIX_HEADER_IGNORE_PATH "${CMAKE_BINARY_DIR}") - endif() - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PATH "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_PRE_UNDEFS "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_POST_UNDEFS "") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT SET) - if (NOT _isSet) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_LINK_LIBRARIES_INIT "COPY_UNITY") - endif() - get_property(_isSet TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES SET) - if (NOT _isSet) - if (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}") - else() - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "") - endif() - endif() -endfunction() - -function (cotire_make_target_message _target _languages _disableMsg _targetMsgVar) - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - string (REPLACE ";" " " _languagesStr "${_languages}") - math (EXPR _numberOfExcludedFiles "${ARGC} - 4") - if (_numberOfExcludedFiles EQUAL 0) - set (_excludedStr "") - elseif (COTIRE_VERBOSE OR _numberOfExcludedFiles LESS 4) - string (REPLACE ";" ", " _excludedStr "excluding ${ARGN}") - else() - set (_excludedStr "excluding ${_numberOfExcludedFiles} files") - endif() - set (_targetMsg "") - if (NOT _languages) - set (_targetMsg "Target ${_target} cannot be cotired.") - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetUsePCH AND NOT _targetAddSCU) - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build and precompiled header.") - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetUsePCH) - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired without precompiled header.") - endif() - if (_disableMsg) - set (_targetMsg "${_targetMsg} ${_disableMsg}") - endif() - elseif (NOT _targetAddSCU) - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired without unity build.") - endif() - else() - if (_excludedStr) - set (_targetMsg "${_languagesStr} target ${_target} cotired ${_excludedStr}.") - else() - set (_targetMsg "${_languagesStr} target ${_target} cotired.") - endif() - endif() - set (${_targetMsgVar} "${_targetMsg}" PARENT_SCOPE) -endfunction() - -function (cotire_choose_target_languages _target _targetLanguagesVar _wholeTargetVar) - set (_languages ${ARGN}) - set (_allSourceFiles "") - set (_allExcludedSourceFiles "") - set (_allCotiredSourceFiles "") - set (_targetLanguages "") - set (_pchEligibleTargetLanguages "") - get_target_property(_targetType ${_target} TYPE) - get_target_property(_targetSourceFiles ${_target} SOURCES) - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - set (_disableMsg "") - foreach (_language ${_languages}) - get_target_property(_prefixHeader ${_target} COTIRE_${_language}_PREFIX_HEADER) - get_target_property(_unityBuildFile ${_target} COTIRE_${_language}_UNITY_SOURCE) - if (_prefixHeader OR _unityBuildFile) - message (STATUS "cotire: target ${_target} has already been cotired.") - set (${_targetLanguagesVar} "" PARENT_SCOPE) - return() - endif() - if (_targetUsePCH AND "${_language}" MATCHES "^C|CXX$") - cotire_check_precompiled_header_support("${_language}" "${_target}" _disableMsg) - if (_disableMsg) - set (_targetUsePCH FALSE) - endif() - endif() - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (_sourceFiles OR _excludedSources OR _cotiredSources) - list (APPEND _targetLanguages ${_language}) - endif() - if (_sourceFiles) - list (APPEND _allSourceFiles ${_sourceFiles}) - endif() - list (LENGTH _sourceFiles _numberOfSources) - if (NOT _numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) - list (APPEND _pchEligibleTargetLanguages ${_language}) - endif() - if (_excludedSources) - list (APPEND _allExcludedSourceFiles ${_excludedSources}) - endif() - if (_cotiredSources) - list (APPEND _allCotiredSourceFiles ${_cotiredSources}) - endif() - endforeach() - set (_targetMsgLevel STATUS) - if (NOT _targetLanguages) - string (REPLACE ";" " or " _languagesStr "${_languages}") - set (_disableMsg "No ${_languagesStr} source files.") - set (_targetUsePCH FALSE) - set (_targetAddSCU FALSE) - endif() - if (_targetUsePCH) - if (_allCotiredSourceFiles) - cotire_get_source_file_property_values(_cotireTargets COTIRE_TARGET ${_allCotiredSourceFiles}) - list (REMOVE_DUPLICATES _cotireTargets) - string (REPLACE ";" ", " _cotireTargetsStr "${_cotireTargets}") - set (_disableMsg "Target sources already include a precompiled header for target(s) ${_cotireTargets}.") - set (_disableMsg "${_disableMsg} Set target property COTIRE_ENABLE_PRECOMPILED_HEADER to FALSE for targets ${_target},") - set (_disableMsg "${_disableMsg} ${_cotireTargetsStr} to get a workable build system.") - set (_targetMsgLevel SEND_ERROR) - set (_targetUsePCH FALSE) - elseif (NOT _pchEligibleTargetLanguages) - set (_disableMsg "Too few applicable sources.") - set (_targetUsePCH FALSE) - elseif (XCODE AND _allExcludedSourceFiles) - # for Xcode, we cannot apply the precompiled header to individual sources, only to the whole target - set (_disableMsg "Exclusion of source files not supported for generator Xcode.") - set (_targetUsePCH FALSE) - elseif (XCODE AND "${_targetType}" STREQUAL "OBJECT_LIBRARY") - # for Xcode, we cannot apply the required PRE_BUILD action to generate the prefix header to an OBJECT_LIBRARY target - set (_disableMsg "Required PRE_BUILD action not supported for OBJECT_LIBRARY targets for generator Xcode.") - set (_targetUsePCH FALSE) - endif() - endif() - set_property(TARGET ${_target} PROPERTY COTIRE_ENABLE_PRECOMPILED_HEADER ${_targetUsePCH}) - set_property(TARGET ${_target} PROPERTY COTIRE_ADD_UNITY_BUILD ${_targetAddSCU}) - cotire_make_target_message(${_target} "${_targetLanguages}" "${_disableMsg}" _targetMsg ${_allExcludedSourceFiles}) - if (_targetMsg) - if (NOT DEFINED COTIREMSG_${_target}) - set (COTIREMSG_${_target} "") - endif() - if (COTIRE_VERBOSE OR NOT "${_targetMsgLevel}" STREQUAL "STATUS" OR - NOT "${COTIREMSG_${_target}}" STREQUAL "${_targetMsg}") - # cache message to avoid redundant messages on re-configure - set (COTIREMSG_${_target} "${_targetMsg}" CACHE INTERNAL "${_target} cotire message.") - message (${_targetMsgLevel} "${_targetMsg}") - endif() - endif() - list (LENGTH _targetLanguages _numberOfLanguages) - if (_numberOfLanguages GREATER 1 OR _allExcludedSourceFiles) - set (${_wholeTargetVar} FALSE PARENT_SCOPE) - else() - set (${_wholeTargetVar} TRUE PARENT_SCOPE) - endif() - set (${_targetLanguagesVar} ${_targetLanguages} PARENT_SCOPE) -endfunction() - -function (cotire_compute_unity_max_number_of_includes _target _maxIncludesVar) - set (_sourceFiles ${ARGN}) - get_target_property(_maxIncludes ${_target} COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES) - if (_maxIncludes MATCHES "(-j|--parallel|--jobs) ?([0-9]*)") - set (_numberOfThreads "${CMAKE_MATCH_2}") - if (NOT _numberOfThreads) - # use all available cores - ProcessorCount(_numberOfThreads) - endif() - list (LENGTH _sourceFiles _numberOfSources) - math (EXPR _maxIncludes "(${_numberOfSources} + ${_numberOfThreads} - 1) / ${_numberOfThreads}") - elseif (NOT _maxIncludes MATCHES "[0-9]+") - set (_maxIncludes 0) - endif() - if (COTIRE_DEBUG) - message (STATUS "${_target} unity source max includes: ${_maxIncludes}") - endif() - set (${_maxIncludesVar} ${_maxIncludes} PARENT_SCOPE) -endfunction() - -function (cotire_process_target_language _language _configurations _target _wholeTarget _cmdsVar) - set (${_cmdsVar} "" PARENT_SCOPE) - get_target_property(_targetSourceFiles ${_target} SOURCES) - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (NOT _sourceFiles AND NOT _cotiredSources) - return() - endif() - set (_cmds "") - # check for user provided unity source file list - get_property(_unitySourceFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE_INIT) - if (NOT _unitySourceFiles) - set (_unitySourceFiles ${_sourceFiles} ${_cotiredSources}) - endif() - cotire_generate_target_script( - ${_language} "${_configurations}" ${_target} _targetScript _targetConfigScript ${_unitySourceFiles}) - # set up unity files for parallel compilation - cotire_compute_unity_max_number_of_includes(${_target} _maxIncludes ${_unitySourceFiles}) - cotire_make_unity_source_file_paths(${_language} ${_target} ${_maxIncludes} _unityFiles ${_unitySourceFiles}) - list (LENGTH _unityFiles _numberOfUnityFiles) - if (_numberOfUnityFiles EQUAL 0) - return() - elseif (_numberOfUnityFiles GREATER 1) - cotire_setup_unity_generation_commands( - ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFiles}" _cmds ${_unitySourceFiles}) - endif() - # set up single unity file for prefix header generation - cotire_make_single_unity_source_file_path(${_language} ${_target} _unityFile) - cotire_setup_unity_generation_commands( - ${_language} ${_target} "${_targetScript}" "${_targetConfigScript}" "${_unityFile}" _cmds ${_unitySourceFiles}) - cotire_make_prefix_file_path(${_language} ${_target} _prefixFile) - # set up prefix header - if (_prefixFile) - # check for user provided prefix header files - get_property(_prefixHeaderFiles TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) - if (_prefixHeaderFiles) - cotire_setup_prefix_generation_from_provided_command( - ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" _cmds ${_prefixHeaderFiles}) - else() - cotire_setup_prefix_generation_from_unity_command( - ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_unityFile}" _cmds ${_unitySourceFiles}) - endif() - # check if selected language has enough sources at all - list (LENGTH _sourceFiles _numberOfSources) - if (_numberOfSources LESS ${COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES}) - set (_targetUsePCH FALSE) - else() - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - endif() - if (_targetUsePCH) - cotire_make_pch_file_path(${_language} ${_target} _pchFile) - if (_pchFile) - # first file in _sourceFiles is passed as the host file - cotire_setup_pch_file_compilation( - ${_language} ${_target} "${_targetConfigScript}" "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) - cotire_setup_pch_file_inclusion( - ${_language} ${_target} ${_wholeTarget} "${_prefixFile}" "${_pchFile}" ${_sourceFiles}) - endif() - elseif (_prefixHeaderFiles) - # user provided prefix header must be included unconditionally - cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_sourceFiles}) - endif() - endif() - # mark target as cotired for language - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE "${_unityFiles}") - if (_prefixFile) - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER "${_prefixFile}") - if (_targetUsePCH AND _pchFile) - set_property(TARGET ${_target} PROPERTY COTIRE_${_language}_PRECOMPILED_HEADER "${_pchFile}") - endif() - endif() - set (${_cmdsVar} ${_cmds} PARENT_SCOPE) -endfunction() - -function (cotire_setup_clean_target _target) - set (_cleanTargetName "${_target}${COTIRE_CLEAN_TARGET_SUFFIX}") - if (NOT TARGET "${_cleanTargetName}") - cotire_set_cmd_to_prologue(_cmds) - get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}" ABSOLUTE) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${_outputDir}" "${COTIRE_INTDIR}" "${_target}") - add_custom_target(${_cleanTargetName} - COMMAND ${_cmds} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - COMMENT "Cleaning up target ${_target} cotire generated files" - VERBATIM) - cotire_init_target("${_cleanTargetName}") - endif() -endfunction() - -function (cotire_setup_pch_target _languages _configurations _target) - if ("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") - # for makefile based generators, we add a custom target to trigger the generation of the cotire related files - set (_dependsFiles "") - foreach (_language ${_languages}) - set (_props COTIRE_${_language}_PREFIX_HEADER COTIRE_${_language}_UNITY_SOURCE) - if (NOT CMAKE_${_language}_COMPILER_ID MATCHES "MSVC|Intel") - # Visual Studio and Intel only create precompiled header as a side effect - list (INSERT _props 0 COTIRE_${_language}_PRECOMPILED_HEADER) - endif() - cotire_get_first_set_property_value(_dependsFile TARGET ${_target} ${_props}) - if (_dependsFile) - list (APPEND _dependsFiles "${_dependsFile}") - endif() - endforeach() - if (_dependsFiles) - set (_pchTargetName "${_target}${COTIRE_PCH_TARGET_SUFFIX}") - add_custom_target("${_pchTargetName}" DEPENDS ${_dependsFiles}) - cotire_init_target("${_pchTargetName}") - cotire_add_to_pch_all_target(${_pchTargetName}) - endif() - else() - # for other generators, we add the "clean all" target to clean up the precompiled header - cotire_setup_clean_all_target() - endif() -endfunction() - -function (cotire_collect_unity_target_sources _target _languages _unityTargetSourcesVar) - get_target_property(_targetSourceFiles ${_target} SOURCES) - set (_unityTargetSources ${_targetSourceFiles}) - foreach (_language ${_languages}) - get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) - if (_unityFiles) - # remove source files that are included in the unity source - set (_sourceFiles "") - set (_excludedSources "") - set (_cotiredSources "") - cotire_filter_language_source_files(${_language} ${_target} _sourceFiles _excludedSources _cotiredSources ${_targetSourceFiles}) - if (_sourceFiles OR _cotiredSources) - list (REMOVE_ITEM _unityTargetSources ${_sourceFiles} ${_cotiredSources}) - endif() - # add unity source files instead - list (APPEND _unityTargetSources ${_unityFiles}) - endif() - endforeach() - set (${_unityTargetSourcesVar} ${_unityTargetSources} PARENT_SCOPE) -endfunction() - -function (cotire_setup_unity_target_pch_usage _languages _target) - foreach (_language ${_languages}) - get_property(_unityFiles TARGET ${_target} PROPERTY COTIRE_${_language}_UNITY_SOURCE) - if (_unityFiles) - get_property(_userPrefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER_INIT) - get_property(_prefixFile TARGET ${_target} PROPERTY COTIRE_${_language}_PREFIX_HEADER) - if (_userPrefixFile AND _prefixFile) - # user provided prefix header must be included unconditionally by unity sources - cotire_setup_prefix_file_inclusion(${_language} ${_target} "${_prefixFile}" ${_unityFiles}) - endif() - endif() - endforeach() -endfunction() - -function (cotire_setup_unity_build_target _languages _configurations _target) - get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) - if (NOT _unityTargetName) - set (_unityTargetName "${_target}${COTIRE_UNITY_BUILD_TARGET_SUFFIX}") - endif() - # determine unity target sub type - get_target_property(_targetType ${_target} TYPE) - if ("${_targetType}" STREQUAL "EXECUTABLE") - set (_unityTargetSubType "") - elseif (_targetType MATCHES "(STATIC|SHARED|MODULE|OBJECT)_LIBRARY") - set (_unityTargetSubType "${CMAKE_MATCH_1}") - else() - message (WARNING "cotire: target ${_target} has unknown target type ${_targetType}.") - return() - endif() - # determine unity target sources - set (_unityTargetSources "") - cotire_collect_unity_target_sources(${_target} "${_languages}" _unityTargetSources) - # handle automatic Qt processing - get_target_property(_targetAutoMoc ${_target} AUTOMOC) - get_target_property(_targetAutoUic ${_target} AUTOUIC) - get_target_property(_targetAutoRcc ${_target} AUTORCC) - if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) - # if the original target sources are subject to CMake's automatic Qt processing, - # also include implicitly generated _automoc.cpp file - list (APPEND _unityTargetSources "${_target}_automoc.cpp") - set_property (SOURCE "${_target}_automoc.cpp" PROPERTY GENERATED TRUE) - endif() - # prevent AUTOMOC, AUTOUIC and AUTORCC properties from being set when the unity target is created - set (CMAKE_AUTOMOC OFF) - set (CMAKE_AUTOUIC OFF) - set (CMAKE_AUTORCC OFF) - if (COTIRE_DEBUG) - message (STATUS "add target ${_targetType} ${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}") - endif() - # generate unity target - if ("${_targetType}" STREQUAL "EXECUTABLE") - add_executable(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) - else() - add_library(${_unityTargetName} ${_unityTargetSubType} EXCLUDE_FROM_ALL ${_unityTargetSources}) - endif() - if (_targetAutoMoc OR _targetAutoUic OR _targetAutoRcc) - # depend on the original target's implicity generated _automoc target - add_dependencies(${_unityTargetName} ${_target}_automoc) - endif() - # copy output location properties - set (_outputDirProperties - ARCHIVE_OUTPUT_DIRECTORY ARCHIVE_OUTPUT_DIRECTORY_ - LIBRARY_OUTPUT_DIRECTORY LIBRARY_OUTPUT_DIRECTORY_ - RUNTIME_OUTPUT_DIRECTORY RUNTIME_OUTPUT_DIRECTORY_) - if (COTIRE_UNITY_OUTPUT_DIRECTORY) - set (_setDefaultOutputDir TRUE) - if (IS_ABSOLUTE "${COTIRE_UNITY_OUTPUT_DIRECTORY}") - set (_outputDir "${COTIRE_UNITY_OUTPUT_DIRECTORY}") - else() - # append relative COTIRE_UNITY_OUTPUT_DIRECTORY to target's actual output directory - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} ${_outputDirProperties}) - cotire_resolve_config_properites("${_configurations}" _properties ${_outputDirProperties}) - foreach (_property ${_properties}) - get_property(_outputDir TARGET ${_target} PROPERTY ${_property}) - if (_outputDir) - get_filename_component(_outputDir "${_outputDir}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) - set_property(TARGET ${_unityTargetName} PROPERTY ${_property} "${_outputDir}") - set (_setDefaultOutputDir FALSE) - endif() - endforeach() - if (_setDefaultOutputDir) - get_filename_component(_outputDir "${CMAKE_CURRENT_BINARY_DIR}/${COTIRE_UNITY_OUTPUT_DIRECTORY}" ABSOLUTE) - endif() - endif() - if (_setDefaultOutputDir) - set_target_properties(${_unityTargetName} PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${_outputDir}" - LIBRARY_OUTPUT_DIRECTORY "${_outputDir}" - RUNTIME_OUTPUT_DIRECTORY "${_outputDir}") - endif() - else() - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ${_outputDirProperties}) - endif() - # copy output name - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ARCHIVE_OUTPUT_NAME ARCHIVE_OUTPUT_NAME_ - LIBRARY_OUTPUT_NAME LIBRARY_OUTPUT_NAME_ - OUTPUT_NAME OUTPUT_NAME_ - RUNTIME_OUTPUT_NAME RUNTIME_OUTPUT_NAME_ - PREFIX _POSTFIX SUFFIX - IMPORT_PREFIX IMPORT_SUFFIX) - # copy compile stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - COMPILE_DEFINITIONS COMPILE_DEFINITIONS_ - COMPILE_FLAGS COMPILE_OPTIONS - Fortran_FORMAT Fortran_MODULE_DIRECTORY - INCLUDE_DIRECTORIES - INTERPROCEDURAL_OPTIMIZATION INTERPROCEDURAL_OPTIMIZATION_ - POSITION_INDEPENDENT_CODE - C_COMPILER_LAUNCHER CXX_COMPILER_LAUNCHER - C_INCLUDE_WHAT_YOU_USE CXX_INCLUDE_WHAT_YOU_USE - C_VISIBILITY_PRESET CXX_VISIBILITY_PRESET VISIBILITY_INLINES_HIDDEN) - # copy compile features - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - C_EXTENSIONS C_STANDARD C_STANDARD_REQUIRED - CXX_EXTENSIONS CXX_STANDARD CXX_STANDARD_REQUIRED - COMPILE_FEATURES) - # copy interface stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - COMPATIBLE_INTERFACE_BOOL COMPATIBLE_INTERFACE_NUMBER_MAX COMPATIBLE_INTERFACE_NUMBER_MIN - COMPATIBLE_INTERFACE_STRING - INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS - INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SOURCES - INTERFACE_POSITION_INDEPENDENT_CODE INTERFACE_SYSTEM_INCLUDE_DIRECTORIES - INTERFACE_AUTOUIC_OPTIONS NO_SYSTEM_FROM_IMPORTED) - # copy link stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - BUILD_WITH_INSTALL_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH SKIP_BUILD_RPATH - LINKER_LANGUAGE LINK_DEPENDS LINK_DEPENDS_NO_SHARED - LINK_FLAGS LINK_FLAGS_ - LINK_INTERFACE_LIBRARIES LINK_INTERFACE_LIBRARIES_ - LINK_INTERFACE_MULTIPLICITY LINK_INTERFACE_MULTIPLICITY_ - LINK_SEARCH_START_STATIC LINK_SEARCH_END_STATIC - STATIC_LIBRARY_FLAGS STATIC_LIBRARY_FLAGS_ - NO_SONAME SOVERSION VERSION) - # copy cmake stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - IMPLICIT_DEPENDS_INCLUDE_TRANSFORM RULE_LAUNCH_COMPILE RULE_LAUNCH_CUSTOM RULE_LAUNCH_LINK) - # copy Apple platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - BUNDLE BUNDLE_EXTENSION FRAMEWORK FRAMEWORK_VERSION INSTALL_NAME_DIR - MACOSX_BUNDLE MACOSX_BUNDLE_INFO_PLIST MACOSX_FRAMEWORK_INFO_PLIST MACOSX_RPATH - OSX_ARCHITECTURES OSX_ARCHITECTURES_ PRIVATE_HEADER PUBLIC_HEADER RESOURCE XCTEST) - # copy Windows platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - GNUtoMS - COMPILE_PDB_NAME COMPILE_PDB_NAME_ - COMPILE_PDB_OUTPUT_DIRECTORY COMPILE_PDB_OUTPUT_DIRECTORY_ - PDB_NAME PDB_NAME_ PDB_OUTPUT_DIRECTORY PDB_OUTPUT_DIRECTORY_ - VS_DESKTOP_EXTENSIONS_VERSION VS_DOTNET_REFERENCES VS_DOTNET_TARGET_FRAMEWORK_VERSION - VS_GLOBAL_KEYWORD VS_GLOBAL_PROJECT_TYPES VS_GLOBAL_ROOTNAMESPACE - VS_IOT_EXTENSIONS_VERSION VS_IOT_STARTUP_TASK - VS_KEYWORD VS_MOBILE_EXTENSIONS_VERSION - VS_SCC_AUXPATH VS_SCC_LOCALPATH VS_SCC_PROJECTNAME VS_SCC_PROVIDER - VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION - VS_WINRT_COMPONENT VS_WINRT_EXTENSIONS VS_WINRT_REFERENCES - WIN32_EXECUTABLE WINDOWS_EXPORT_ALL_SYMBOLS) - # copy Android platform specific stuff - cotire_copy_set_properites("${_configurations}" TARGET ${_target} ${_unityTargetName} - ANDROID_API ANDROID_API_MIN ANDROID_GUI - ANDROID_ANT_ADDITIONAL_OPTIONS ANDROID_ARCH ANDROID_ASSETS_DIRECTORIES - ANDROID_JAR_DEPENDENCIES ANDROID_JAR_DIRECTORIES ANDROID_JAVA_SOURCE_DIR - ANDROID_NATIVE_LIB_DEPENDENCIES ANDROID_NATIVE_LIB_DIRECTORIES - ANDROID_PROCESS_MAX ANDROID_PROGUARD ANDROID_PROGUARD_CONFIG_PATH - ANDROID_SECURE_PROPS_PATH ANDROID_SKIP_ANT_STEP ANDROID_STL_TYPE) - # use output name from original target - get_target_property(_targetOutputName ${_unityTargetName} OUTPUT_NAME) - if (NOT _targetOutputName) - set_property(TARGET ${_unityTargetName} PROPERTY OUTPUT_NAME "${_target}") - endif() - # use export symbol from original target - cotire_get_target_export_symbol("${_target}" _defineSymbol) - if (_defineSymbol) - set_property(TARGET ${_unityTargetName} PROPERTY DEFINE_SYMBOL "${_defineSymbol}") - if ("${_targetType}" STREQUAL "EXECUTABLE") - set_property(TARGET ${_unityTargetName} PROPERTY ENABLE_EXPORTS TRUE) - endif() - endif() - cotire_init_target(${_unityTargetName}) - cotire_add_to_unity_all_target(${_unityTargetName}) - set_property(TARGET ${_target} PROPERTY COTIRE_UNITY_TARGET_NAME "${_unityTargetName}") -endfunction(cotire_setup_unity_build_target) - -function (cotire_target _target) - set(_options "") - set(_oneValueArgs "") - set(_multiValueArgs LANGUAGES CONFIGURATIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - if (NOT _option_LANGUAGES) - get_property (_option_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) - endif() - if (NOT _option_CONFIGURATIONS) - cotire_get_configuration_types(_option_CONFIGURATIONS) - endif() - # trivial checks - get_target_property(_imported ${_target} IMPORTED) - if (_imported) - message (WARNING "cotire: imported target ${_target} cannot be cotired.") - return() - endif() - # resolve alias - get_target_property(_aliasName ${_target} ALIASED_TARGET) - if (_aliasName) - if (COTIRE_DEBUG) - message (STATUS "${_target} is an alias. Applying cotire to aliased target ${_aliasName} instead.") - endif() - set (_target ${_aliasName}) - endif() - # check if target needs to be cotired for build type - # when using configuration types, the test is performed at build time - cotire_init_cotire_target_properties(${_target}) - if (NOT CMAKE_CONFIGURATION_TYPES) - if (CMAKE_BUILD_TYPE) - list (FIND _option_CONFIGURATIONS "${CMAKE_BUILD_TYPE}" _index) - else() - list (FIND _option_CONFIGURATIONS "None" _index) - endif() - if (_index EQUAL -1) - if (COTIRE_DEBUG) - message (STATUS "CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} not cotired (${_option_CONFIGURATIONS})") - endif() - return() - endif() - endif() - # when not using configuration types, immediately create cotire intermediate dir - if (NOT CMAKE_CONFIGURATION_TYPES) - cotire_get_intermediate_dir(_baseDir) - file (MAKE_DIRECTORY "${_baseDir}") - endif() - # choose languages that apply to the target - cotire_choose_target_languages("${_target}" _targetLanguages _wholeTarget ${_option_LANGUAGES}) - if (NOT _targetLanguages) - return() - endif() - set (_cmds "") - foreach (_language ${_targetLanguages}) - cotire_process_target_language("${_language}" "${_option_CONFIGURATIONS}" ${_target} ${_wholeTarget} _cmd) - if (_cmd) - list (APPEND _cmds ${_cmd}) - endif() - endforeach() - get_target_property(_targetAddSCU ${_target} COTIRE_ADD_UNITY_BUILD) - if (_targetAddSCU) - cotire_setup_unity_build_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) - endif() - get_target_property(_targetUsePCH ${_target} COTIRE_ENABLE_PRECOMPILED_HEADER) - if (_targetUsePCH) - cotire_setup_target_pch_usage("${_targetLanguages}" ${_target} ${_wholeTarget} ${_cmds}) - cotire_setup_pch_target("${_targetLanguages}" "${_option_CONFIGURATIONS}" ${_target}) - if (_targetAddSCU) - cotire_setup_unity_target_pch_usage("${_targetLanguages}" ${_target}) - endif() - endif() - get_target_property(_targetAddCleanTarget ${_target} COTIRE_ADD_CLEAN) - if (_targetAddCleanTarget) - cotire_setup_clean_target(${_target}) - endif() -endfunction(cotire_target) - -function (cotire_map_libraries _strategy _mappedLibrariesVar) - set (_mappedLibraries "") - foreach (_library ${ARGN}) - if (TARGET "${_library}" AND "${_strategy}" MATCHES "COPY_UNITY") - # use target's corresponding unity target, if available - get_target_property(_libraryUnityTargetName ${_library} COTIRE_UNITY_TARGET_NAME) - if (TARGET "${_libraryUnityTargetName}") - list (APPEND _mappedLibraries "${_libraryUnityTargetName}") - else() - list (APPEND _mappedLibraries "${_library}") - endif() - else() - list (APPEND _mappedLibraries "${_library}") - endif() - endforeach() - list (REMOVE_DUPLICATES _mappedLibraries) - set (${_mappedLibrariesVar} ${_mappedLibraries} PARENT_SCOPE) -endfunction() - -function (cotire_target_link_libraries _target) - get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME) - if (TARGET "${_unityTargetName}") - get_target_property(_linkLibrariesStrategy ${_target} COTIRE_UNITY_LINK_LIBRARIES_INIT) - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} link strategy: ${_linkLibrariesStrategy}") - endif() - if ("${_linkLibrariesStrategy}" MATCHES "^(COPY|COPY_UNITY)$") - set (_unityLinkLibraries "") - get_target_property(_linkLibraries ${_target} LINK_LIBRARIES) - if (_linkLibraries) - list (APPEND _unityLinkLibraries ${_linkLibraries}) - endif() - get_target_property(_interfaceLinkLibraries ${_target} INTERFACE_LINK_LIBRARIES) - if (_interfaceLinkLibraries) - list (APPEND _unityLinkLibraries ${_interfaceLinkLibraries}) - endif() - cotire_map_libraries("${_linkLibrariesStrategy}" _unityLinkLibraries ${_unityLinkLibraries}) - if (COTIRE_DEBUG) - message (STATUS "unity target ${_unityTargetName} libraries: ${_unityLinkLibraries}") - endif() - if (_unityLinkLibraries) - target_link_libraries(${_unityTargetName} ${_unityLinkLibraries}) - endif() - endif() - endif() -endfunction(cotire_target_link_libraries) - -function (cotire_cleanup _binaryDir _cotireIntermediateDirName _targetName) - if (_targetName) - file (GLOB_RECURSE _cotireFiles "${_binaryDir}/${_targetName}*.*") - else() - file (GLOB_RECURSE _cotireFiles "${_binaryDir}/*.*") - endif() - # filter files in intermediate directory - set (_filesToRemove "") - foreach (_file ${_cotireFiles}) - get_filename_component(_dir "${_file}" DIRECTORY) - get_filename_component(_dirName "${_dir}" NAME) - if ("${_dirName}" STREQUAL "${_cotireIntermediateDirName}") - list (APPEND _filesToRemove "${_file}") - endif() - endforeach() - if (_filesToRemove) - if (COTIRE_VERBOSE) - message (STATUS "cleaning up ${_filesToRemove}") - endif() - file (REMOVE ${_filesToRemove}) - endif() -endfunction() - -function (cotire_init_target _targetName) - if (COTIRE_TARGETS_FOLDER) - set_target_properties(${_targetName} PROPERTIES FOLDER "${COTIRE_TARGETS_FOLDER}") - endif() - set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_ALL TRUE) - if (MSVC_IDE) - set_target_properties(${_targetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) - endif() -endfunction() - -function (cotire_add_to_pch_all_target _pchTargetName) - set (_targetName "${COTIRE_PCH_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - add_custom_target("${_targetName}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - VERBATIM) - cotire_init_target("${_targetName}") - endif() - cotire_setup_clean_all_target() - add_dependencies(${_targetName} ${_pchTargetName}) -endfunction() - -function (cotire_add_to_unity_all_target _unityTargetName) - set (_targetName "${COTIRE_UNITY_BUILD_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - add_custom_target("${_targetName}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - VERBATIM) - cotire_init_target("${_targetName}") - endif() - cotire_setup_clean_all_target() - add_dependencies(${_targetName} ${_unityTargetName}) -endfunction() - -function (cotire_setup_clean_all_target) - set (_targetName "${COTIRE_CLEAN_ALL_TARGET_NAME}") - if (NOT TARGET "${_targetName}") - cotire_set_cmd_to_prologue(_cmds) - list (APPEND _cmds -P "${COTIRE_CMAKE_MODULE_FILE}" "cleanup" "${CMAKE_BINARY_DIR}" "${COTIRE_INTDIR}") - add_custom_target(${_targetName} - COMMAND ${_cmds} - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - COMMENT "Cleaning up all cotire generated files" - VERBATIM) - cotire_init_target("${_targetName}") - endif() -endfunction() - -function (cotire) - set(_options "") - set(_oneValueArgs "") - set(_multiValueArgs LANGUAGES CONFIGURATIONS) - cmake_parse_arguments(_option "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) - set (_targets ${_option_UNPARSED_ARGUMENTS}) - foreach (_target ${_targets}) - if (TARGET ${_target}) - cotire_target(${_target} LANGUAGES ${_option_LANGUAGES} CONFIGURATIONS ${_option_CONFIGURATIONS}) - else() - message (WARNING "cotire: ${_target} is not a target.") - endif() - endforeach() - foreach (_target ${_targets}) - if (TARGET ${_target}) - cotire_target_link_libraries(${_target}) - endif() - endforeach() -endfunction() - -if (CMAKE_SCRIPT_MODE_FILE) - - # cotire is being run in script mode - # locate -P on command args - set (COTIRE_ARGC -1) - foreach (_index RANGE ${CMAKE_ARGC}) - if (COTIRE_ARGC GREATER -1) - set (COTIRE_ARGV${COTIRE_ARGC} "${CMAKE_ARGV${_index}}") - math (EXPR COTIRE_ARGC "${COTIRE_ARGC} + 1") - elseif ("${CMAKE_ARGV${_index}}" STREQUAL "-P") - set (COTIRE_ARGC 0) - endif() - endforeach() - - # include target script if available - if ("${COTIRE_ARGV2}" MATCHES "\\.cmake$") - # the included target scripts sets up additional variables relating to the target (e.g., COTIRE_TARGET_SOURCES) - include("${COTIRE_ARGV2}") - endif() - - if (COTIRE_DEBUG) - message (STATUS "${COTIRE_ARGV0} ${COTIRE_ARGV1} ${COTIRE_ARGV2} ${COTIRE_ARGV3} ${COTIRE_ARGV4} ${COTIRE_ARGV5}") - endif() - - if (NOT COTIRE_BUILD_TYPE) - set (COTIRE_BUILD_TYPE "None") - endif() - string (TOUPPER "${COTIRE_BUILD_TYPE}" _upperConfig) - set (_includeDirs ${COTIRE_TARGET_INCLUDE_DIRECTORIES_${_upperConfig}}) - set (_systemIncludeDirs ${COTIRE_TARGET_SYSTEM_INCLUDE_DIRECTORIES_${_upperConfig}}) - set (_compileDefinitions ${COTIRE_TARGET_COMPILE_DEFINITIONS_${_upperConfig}}) - set (_compileFlags ${COTIRE_TARGET_COMPILE_FLAGS_${_upperConfig}}) - # check if target has been cotired for actual build type COTIRE_BUILD_TYPE - list (FIND COTIRE_TARGET_CONFIGURATION_TYPES "${COTIRE_BUILD_TYPE}" _index) - if (_index GREATER -1) - set (_sources ${COTIRE_TARGET_SOURCES}) - set (_sourcesDefinitions ${COTIRE_TARGET_SOURCES_COMPILE_DEFINITIONS_${_upperConfig}}) - else() - if (COTIRE_DEBUG) - message (STATUS "COTIRE_BUILD_TYPE=${COTIRE_BUILD_TYPE} not cotired (${COTIRE_TARGET_CONFIGURATION_TYPES})") - endif() - set (_sources "") - set (_sourcesDefinitions "") - endif() - set (_targetPreUndefs ${COTIRE_TARGET_PRE_UNDEFS}) - set (_targetPostUndefs ${COTIRE_TARGET_POST_UNDEFS}) - set (_sourcesPreUndefs ${COTIRE_TARGET_SOURCES_PRE_UNDEFS}) - set (_sourcesPostUndefs ${COTIRE_TARGET_SOURCES_POST_UNDEFS}) - - if ("${COTIRE_ARGV1}" STREQUAL "unity") - - if (XCODE) - # executing pre-build action under Xcode, check dependency on target script - set (_dependsOption DEPENDS "${COTIRE_ARGV2}") - else() - # executing custom command, no need to re-check for dependencies - set (_dependsOption "") - endif() - - cotire_select_unity_source_files("${COTIRE_ARGV3}" _sources ${_sources}) - - cotire_generate_unity_source( - "${COTIRE_ARGV3}" ${_sources} - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - SOURCES_COMPILE_DEFINITIONS ${_sourcesDefinitions} - PRE_UNDEFS ${_targetPreUndefs} - POST_UNDEFS ${_targetPostUndefs} - SOURCES_PRE_UNDEFS ${_sourcesPreUndefs} - SOURCES_POST_UNDEFS ${_sourcesPostUndefs} - ${_dependsOption}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "prefix") - - if (XCODE) - # executing pre-build action under Xcode, check dependency on unity file and prefix dependencies - set (_dependsOption DEPENDS "${COTIRE_ARGV4}" ${COTIRE_TARGET_PREFIX_DEPENDS}) - else() - # executing custom command, no need to re-check for dependencies - set (_dependsOption "") - endif() - - set (_files "") - foreach (_index RANGE 4 ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - cotire_generate_prefix_header( - "${COTIRE_ARGV3}" ${_files} - COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" - COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} - COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" - COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - IGNORE_PATH "${COTIRE_TARGET_IGNORE_PATH};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH}" - INCLUDE_PATH ${COTIRE_TARGET_INCLUDE_PATH} - IGNORE_EXTENSIONS "${CMAKE_${COTIRE_TARGET_LANGUAGE}_SOURCE_FILE_EXTENSIONS};${COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS}" - INCLUDE_PRIORITY_PATH ${COTIRE_TARGET_INCLUDE_PRIORITY_PATH} - INCLUDE_DIRECTORIES ${_includeDirs} - SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} - COMPILE_DEFINITIONS ${_compileDefinitions} - COMPILE_FLAGS ${_compileFlags} - ${_dependsOption}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "precompile") - - set (_files "") - foreach (_index RANGE 5 ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - cotire_precompile_prefix_header( - "${COTIRE_ARGV3}" "${COTIRE_ARGV4}" "${COTIRE_ARGV5}" - COMPILER_EXECUTABLE "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER}" - COMPILER_ARG1 ${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ARG1} - COMPILER_ID "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_ID}" - COMPILER_VERSION "${CMAKE_${COTIRE_TARGET_LANGUAGE}_COMPILER_VERSION}" - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - INCLUDE_DIRECTORIES ${_includeDirs} - SYSTEM_INCLUDE_DIRECTORIES ${_systemIncludeDirs} - COMPILE_DEFINITIONS ${_compileDefinitions} - COMPILE_FLAGS ${_compileFlags}) - - elseif ("${COTIRE_ARGV1}" STREQUAL "combine") - - if (COTIRE_TARGET_LANGUAGE) - set (_combinedFile "${COTIRE_ARGV3}") - set (_startIndex 4) - else() - set (_combinedFile "${COTIRE_ARGV2}") - set (_startIndex 3) - endif() - set (_files "") - foreach (_index RANGE ${_startIndex} ${COTIRE_ARGC}) - if (COTIRE_ARGV${_index}) - list (APPEND _files "${COTIRE_ARGV${_index}}") - endif() - endforeach() - - if (XCODE) - # executing pre-build action under Xcode, check dependency on files to be combined - set (_dependsOption DEPENDS ${_files}) - else() - # executing custom command, no need to re-check for dependencies - set (_dependsOption "") - endif() - - if (COTIRE_TARGET_LANGUAGE) - cotire_generate_unity_source( - "${_combinedFile}" ${_files} - LANGUAGE "${COTIRE_TARGET_LANGUAGE}" - ${_dependsOption}) - else() - cotire_generate_unity_source("${_combinedFile}" ${_files} ${_dependsOption}) - endif() - - elseif ("${COTIRE_ARGV1}" STREQUAL "cleanup") - - cotire_cleanup("${COTIRE_ARGV2}" "${COTIRE_ARGV3}" "${COTIRE_ARGV4}") - - else() - message (FATAL_ERROR "cotire: unknown command \"${COTIRE_ARGV1}\".") - endif() - -else() - - # cotire is being run in include mode - # set up all variable and property definitions - - if (NOT DEFINED COTIRE_DEBUG_INIT) - if (DEFINED COTIRE_DEBUG) - set (COTIRE_DEBUG_INIT ${COTIRE_DEBUG}) - else() - set (COTIRE_DEBUG_INIT FALSE) - endif() - endif() - option (COTIRE_DEBUG "Enable cotire debugging output?" ${COTIRE_DEBUG_INIT}) - - if (NOT DEFINED COTIRE_VERBOSE_INIT) - if (DEFINED COTIRE_VERBOSE) - set (COTIRE_VERBOSE_INIT ${COTIRE_VERBOSE}) - else() - set (COTIRE_VERBOSE_INIT FALSE) - endif() - endif() - option (COTIRE_VERBOSE "Enable cotire verbose output?" ${COTIRE_VERBOSE_INIT}) - - set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS "inc;inl;ipp" CACHE STRING - "Ignore headers with the listed file extensions from the generated prefix header.") - - set (COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH "" CACHE STRING - "Ignore headers from these directories when generating the prefix header.") - - set (COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS "m;mm" CACHE STRING - "Ignore sources with the listed file extensions from the generated unity source.") - - set (COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES "3" CACHE STRING - "Minimum number of sources in target required to enable use of precompiled header.") - - if (NOT DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT) - if (DEFINED COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT ${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES}) - elseif ("${CMAKE_GENERATOR}" MATCHES "JOM|Ninja|Visual Studio") - # enable parallelization for generators that run multiple jobs by default - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "-j") - else() - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT "0") - endif() - endif() - set (COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES "${COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES_INIT}" CACHE STRING - "Maximum number of source files to include in a single unity source file.") - - if (NOT COTIRE_PREFIX_HEADER_FILENAME_SUFFIX) - set (COTIRE_PREFIX_HEADER_FILENAME_SUFFIX "_prefix") - endif() - if (NOT COTIRE_UNITY_SOURCE_FILENAME_SUFFIX) - set (COTIRE_UNITY_SOURCE_FILENAME_SUFFIX "_unity") - endif() - if (NOT COTIRE_INTDIR) - set (COTIRE_INTDIR "cotire") - endif() - if (NOT COTIRE_PCH_ALL_TARGET_NAME) - set (COTIRE_PCH_ALL_TARGET_NAME "all_pch") - endif() - if (NOT COTIRE_UNITY_BUILD_ALL_TARGET_NAME) - set (COTIRE_UNITY_BUILD_ALL_TARGET_NAME "all_unity") - endif() - if (NOT COTIRE_CLEAN_ALL_TARGET_NAME) - set (COTIRE_CLEAN_ALL_TARGET_NAME "clean_cotire") - endif() - if (NOT COTIRE_CLEAN_TARGET_SUFFIX) - set (COTIRE_CLEAN_TARGET_SUFFIX "_clean_cotire") - endif() - if (NOT COTIRE_PCH_TARGET_SUFFIX) - set (COTIRE_PCH_TARGET_SUFFIX "_pch") - endif() - if (MSVC) - # MSVC default PCH memory scaling factor of 100 percent (75 MB) is too small for template heavy C++ code - # use a bigger default factor of 170 percent (128 MB) - if (NOT DEFINED COTIRE_PCH_MEMORY_SCALING_FACTOR) - set (COTIRE_PCH_MEMORY_SCALING_FACTOR "170") - endif() - endif() - if (NOT COTIRE_UNITY_BUILD_TARGET_SUFFIX) - set (COTIRE_UNITY_BUILD_TARGET_SUFFIX "_unity") - endif() - if (NOT DEFINED COTIRE_TARGETS_FOLDER) - set (COTIRE_TARGETS_FOLDER "cotire") - endif() - if (NOT DEFINED COTIRE_UNITY_OUTPUT_DIRECTORY) - if ("${CMAKE_GENERATOR}" MATCHES "Ninja") - # generated Ninja build files do not work if the unity target produces the same output file as the cotired target - set (COTIRE_UNITY_OUTPUT_DIRECTORY "unity") - else() - set (COTIRE_UNITY_OUTPUT_DIRECTORY "") - endif() - endif() - - # define cotire cache variables - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_PATH" - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "The variable can be set to a semicolon separated list of include directories." - "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." - "If not defined, defaults to empty list." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_ADDITIONAL_PREFIX_HEADER_IGNORE_EXTENSIONS" - BRIEF_DOCS "Ignore includes with the listed file extensions from the generated prefix header." - FULL_DOCS - "The variable can be set to a semicolon separated list of file extensions." - "If a header file extension matches one in the list, it will be excluded from the generated prefix header." - "Includes with an extension in CMAKE__SOURCE_FILE_EXTENSIONS are always ignored." - "If not defined, defaults to inc;inl;ipp." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_UNITY_SOURCE_EXCLUDE_EXTENSIONS" - BRIEF_DOCS "Exclude sources with the listed file extensions from the generated unity source." - FULL_DOCS - "The variable can be set to a semicolon separated list of file extensions." - "If a source file extension matches one in the list, it will be excluded from the generated unity source file." - "Source files with an extension in CMAKE__IGNORE_EXTENSIONS are always excluded." - "If not defined, defaults to m;mm." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_MINIMUM_NUMBER_OF_TARGET_SOURCES" - BRIEF_DOCS "Minimum number of sources in target required to enable use of precompiled header." - FULL_DOCS - "The variable can be set to an integer > 0." - "If a target contains less than that number of source files, cotire will not enable the use of the precompiled header for the target." - "If not defined, defaults to 3." - ) - - define_property( - CACHED_VARIABLE PROPERTY "COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES" - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "This may be set to an integer >= 0." - "If 0, cotire will only create a single unity source file." - "If a target contains more than that number of source files, cotire will create multiple unity source files for it." - "Can be set to \"-j\" to optimize the count of unity source files for the number of available processor cores." - "Can be set to \"-j jobs\" to optimize the number of unity source files for the given number of simultaneous jobs." - "Is used to initialize the target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." - "Defaults to \"-j\" for the generators Visual Studio, JOM or Ninja. Defaults to 0 otherwise." - ) - - # define cotire directory properties - - define_property( - DIRECTORY PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" - BRIEF_DOCS "Modify build command of cotired targets added in this directory to make use of the generated precompiled header." - FULL_DOCS - "See target property COTIRE_ENABLE_PRECOMPILED_HEADER." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_ADD_UNITY_BUILD" - BRIEF_DOCS "Add a new target that performs a unity build for cotired targets added in this directory." - FULL_DOCS - "See target property COTIRE_ADD_UNITY_BUILD." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_ADD_CLEAN" - BRIEF_DOCS "Add a new target that cleans all cotire generated files for cotired targets added in this directory." - FULL_DOCS - "See target property COTIRE_ADD_CLEAN." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_IGNORE_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" - BRIEF_DOCS "Honor headers from these directories when generating the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_INCLUDE_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" - BRIEF_DOCS "Header paths matching one of these directories are put at the top of the prefix header." - FULL_DOCS - "See target property COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_PRE_UNDEFS." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_POST_UNDEFS." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "See target property COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES." - ) - - define_property( - DIRECTORY PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" - BRIEF_DOCS "Define strategy for setting up the unity target's link libraries." - FULL_DOCS - "See target property COTIRE_UNITY_LINK_LIBRARIES_INIT." - ) - - # define cotire target properties - - define_property( - TARGET PROPERTY "COTIRE_ENABLE_PRECOMPILED_HEADER" INHERITED - BRIEF_DOCS "Modify this target's build command to make use of the generated precompiled header." - FULL_DOCS - "If this property is set to TRUE, cotire will modify the build command to make use of the generated precompiled header." - "Irrespective of the value of this property, cotire will setup custom commands to generate the unity source and prefix header for the target." - "For makefile based generators cotire will also set up a custom target to manually invoke the generation of the precompiled header." - "The target name will be set to this target's name with the suffix _pch appended." - "Inherited from directory." - "Defaults to TRUE." - ) - - define_property( - TARGET PROPERTY "COTIRE_ADD_UNITY_BUILD" INHERITED - BRIEF_DOCS "Add a new target that performs a unity build for this target." - FULL_DOCS - "If this property is set to TRUE, cotire creates a new target of the same type that uses the generated unity source file instead of the target sources." - "Most of the relevant target properties will be copied from this target to the new unity build target." - "Target dependencies and linked libraries have to be manually set up for the new unity build target." - "The unity target name will be set to this target's name with the suffix _unity appended." - "Inherited from directory." - "Defaults to TRUE." - ) - - define_property( - TARGET PROPERTY "COTIRE_ADD_CLEAN" INHERITED - BRIEF_DOCS "Add a new target that cleans all cotire generated files for this target." - FULL_DOCS - "If this property is set to TRUE, cotire creates a new target that clean all files (unity source, prefix header, precompiled header)." - "The clean target name will be set to this target's name with the suffix _clean_cotire appended." - "Inherited from directory." - "Defaults to FALSE." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_IGNORE_PATH" INHERITED - BRIEF_DOCS "Ignore headers from these directories when generating the prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "If a header file is found in one of these directories or sub-directories, it will be excluded from the generated prefix header." - "Inherited from directory." - "If not set, this property is initialized to \${CMAKE_SOURCE_DIR};\${CMAKE_BINARY_DIR}." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PATH" INHERITED - BRIEF_DOCS "Honor headers from these directories when generating the prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "If a header file is found in one of these directories or sub-directories, it will be included in the generated prefix header." - "If a header file is both selected by COTIRE_PREFIX_HEADER_IGNORE_PATH and COTIRE_PREFIX_HEADER_INCLUDE_PATH," - "the option which yields the closer relative path match wins." - "Inherited from directory." - "If not set, this property is initialized to the empty list." - ) - - define_property( - TARGET PROPERTY "COTIRE_PREFIX_HEADER_INCLUDE_PRIORITY_PATH" INHERITED - BRIEF_DOCS "Header paths matching one of these directories are put at the top of prefix header." - FULL_DOCS - "The property can be set to a list of directories." - "Header file paths matching one of these directories will be inserted at the beginning of the generated prefix header." - "Header files are sorted according to the order of the directories in the property." - "If not set, this property is initialized to the empty list." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" INHERITED - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of each target source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file before each target source file." - "Inherited from directory." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" INHERITED - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of each target source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file after each target source file." - "Inherited from directory." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES" INHERITED - BRIEF_DOCS "Maximum number of source files to include in a single unity source file." - FULL_DOCS - "This may be set to an integer > 0." - "If a target contains more than that number of source files, cotire will create multiple unity build files for it." - "If not set, cotire will only create a single unity source file." - "Inherited from directory." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__UNITY_SOURCE_INIT" - BRIEF_DOCS "User provided unity source file to be used instead of the automatically generated one." - FULL_DOCS - "If set, cotire will only add the given file(s) to the generated unity source file." - "If not set, cotire will add all the target source files to the generated unity source file." - "The property can be set to a user provided unity source file." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__PREFIX_HEADER_INIT" - BRIEF_DOCS "User provided prefix header file to be used instead of the automatically generated one." - FULL_DOCS - "If set, cotire will add the given header file(s) to the generated prefix header file." - "If not set, cotire will generate a prefix header by tracking the header files included by the unity source file." - "The property can be set to a user provided prefix header file (e.g., stdafx.h)." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_LINK_LIBRARIES_INIT" INHERITED - BRIEF_DOCS "Define strategy for setting up unity target's link libraries." - FULL_DOCS - "If this property is empty or set to NONE, the generated unity target's link libraries have to be set up manually." - "If this property is set to COPY, the unity target's link libraries will be copied from this target." - "If this property is set to COPY_UNITY, the unity target's link libraries will be copied from this target with considering existing unity targets." - "Inherited from directory." - "Defaults to empty." - ) - - define_property( - TARGET PROPERTY "COTIRE__UNITY_SOURCE" - BRIEF_DOCS "Read-only property. The generated unity source file(s)." - FULL_DOCS - "cotire sets this property to the path of the generated single computation unit source file for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE__PREFIX_HEADER" - BRIEF_DOCS "Read-only property. The generated prefix header file." - FULL_DOCS - "cotire sets this property to the full path of the generated language prefix header for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE__PRECOMPILED_HEADER" - BRIEF_DOCS "Read-only property. The generated precompiled header file." - FULL_DOCS - "cotire sets this property to the full path of the generated language precompiled header binary for the target." - "Defaults to empty string." - ) - - define_property( - TARGET PROPERTY "COTIRE_UNITY_TARGET_NAME" - BRIEF_DOCS "The name of the generated unity build target corresponding to this target." - FULL_DOCS - "This property can be set to the desired name of the unity target that will be created by cotire." - "If not set, the unity target name will be set to this target's name with the suffix _unity appended." - "After this target has been processed by cotire, the property is set to the actual name of the generated unity target." - "Defaults to empty string." - ) - - # define cotire source properties - - define_property( - SOURCE PROPERTY "COTIRE_EXCLUDED" - BRIEF_DOCS "Do not modify source file's build command." - FULL_DOCS - "If this property is set to TRUE, the source file's build command will not be modified to make use of the precompiled header." - "The source file will also be excluded from the generated unity source file." - "Source files that have their COMPILE_FLAGS property set will be excluded by default." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_DEPENDENCY" - BRIEF_DOCS "Add this source file to dependencies of the automatically generated prefix header file." - FULL_DOCS - "If this property is set to TRUE, the source file is added to dependencies of the generated prefix header file." - "If the file is modified, cotire will re-generate the prefix header source upon build." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_UNITY_SOURCE_PRE_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file before the inclusion of this source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file before this file is included." - "Defaults to empty string." - ) - - define_property( - SOURCE PROPERTY "COTIRE_UNITY_SOURCE_POST_UNDEFS" - BRIEF_DOCS "Preprocessor undefs to place in the generated unity source file after the inclusion of this source file." - FULL_DOCS - "This may be set to a semicolon-separated list of preprocessor symbols." - "cotire will add corresponding #undef directives to the generated unit source file after this file is included." - "Defaults to empty string." - ) - - define_property( - SOURCE PROPERTY "COTIRE_START_NEW_UNITY_SOURCE" - BRIEF_DOCS "Start a new unity source file which includes this source file as the first one." - FULL_DOCS - "If this property is set to TRUE, cotire will complete the current unity file and start a new one." - "The new unity source file will include this source file as the first one." - "This property essentially works as a separator for unity source files." - "Defaults to FALSE." - ) - - define_property( - SOURCE PROPERTY "COTIRE_TARGET" - BRIEF_DOCS "Read-only property. Mark this source file as cotired for the given target." - FULL_DOCS - "cotire sets this property to the name of target, that the source file's build command has been altered for." - "Defaults to empty string." - ) - - message (STATUS "cotire ${COTIRE_CMAKE_MODULE_VERSION} loaded.") - -endif() diff --git a/rtags/configure b/rtags/configure deleted file mode 100755 index 1503f8e..0000000 --- a/rtags/configure +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash - -function usage () -{ - echo "configure [OPTIONS...]" - echo " --help|-h Display this help" - echo " --cmake [arg] Use arg instead of \"cmake\"" - echo " --cmake-argument [arg] Pass additional arguments to cmake" - echo " --cmake-generator [arg] Use this generator for cmake (e.g. Ninja)" - echo " --enable-dev-options Set certain development options (cpack)" - echo " --asan Enable -fsanitize=address and -fsanitize=undefined" - echo " --debug Compile RTags in debug mode" - echo " --release Compile RTags in release mode (default)" - echo " --system-clang Don't build llvm/clang as part of RTags' build process (default)" - echo " --build-tests Build tests" - echo " --build-clang Download and build llvm/clang as part of RTags' build process" - echo " --no-install Generate a build that isn't going to be installed" - echo " --prefix [arg] Set install prefix to arg" - echo " --clang-libraries [arg] Override what libraries RTags will use to link against clang/llvm" - echo " --clang-cxxflags [arg] Override what cxxflags RTags will use for compilation to be able to include clang headers." - echo " --clang-libdir [arg] Sets the libdir RTags will use for clang." - echo " --cotire Enable cotire when building RTags" - echo " --emacs Use arg instead of \"emacs\" when byte-compiling elisp" - echo " --lua-enabled Enable LUA AST scripting" - echo " --no-lua-files-install Don't install RTags lua files" - echo " --no-elisp-files-install Don't install RTags elisp files" - echo " --no-elisp-bytecompile Don't bytecompile RTags elisp files" - echo " --elisp-install-location [arg] Install elisp files to this location" -} - -CMAKE=cmake -CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=1" -BUILD= -while [ -n "$1" ]; do - case "$1" in - --help|-h) - usage > /dev/stdout - exit 0 - ;; - --cmake) - shift - CMAKE="$1" - ;; - --cmake-argument) - shift - CMAKE_ARGS="${CMAKE_ARGS} \"$1\"" - ;; - --cmake-generator) - shift - CMAKE_GENERATOR="$1" - ;; - --enable-dev-options) - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_ENABLE_DEV_OPTIONS=1" - ;; - --debug) - CMAKE_ARGS="${CMAKE_ARGS} -DCMAKE_BUILD_TYPE=Debug" - ;; - --release) - CMAKE_ARGS="${CMAKE_ARGS} -DCMAKE_BUILD_TYPE=Release" - ;; - --system-clang) - BUILD= - ;; - --build-clang) - BUILD=1 - ;; - --without-tests) - CMAKE_ARGS="${CMAKE_ARGS} -DBUILD_TESTING=0" - ;; - --no-install) - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_NO_INSTALL=1" - ;; - --prefix) - shift - CMAKE_ARGS="${CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX=\"$1\"" - ;; - --lua-enabled) - CMAKE_ARGS="${CMAKE_ARGS} -DLUA_ENABLED=1" - ;; - --clang-libraries) - shift - CMAKE_ARGS="${CMAKE_ARGS} -DLIBCLANG_LIBRARIES=\"$1\"" - ;; - --clang-cxxflags) - shift - CMAKE_ARGS="${CMAKE_ARGS} -DLIBCLANG_CXXFLAGS=\"$1\"" - ;; - --clang-libdir) - shift - CMAKE_ARGS="${CMAKE_ARGS} -DLIBCLANG_LIBDIR=\"$1\"" - ;; - --cotire) - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_COTIRE=1" - ;; - --emacs) - shift - CMAKE_ARGS="${CMAKE_ARGS} -DEMACS=\"$1\"" - ;; - --no-lua-files-install) - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_NO_LUA_FILES=1" - ;; - --no-elisp-files-install) - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_NO_ELISP_FILES=1" - ;; - --no-elisp-bytecompile) - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_NO_ELISP_BYTECOMPILE=1" - ;; - --asan) - CMAKE_ARGS="${CMAKE_ARGS} -DASAN=address,undefined" - ;; - --asan=*) - CMAKE_ARGS="${CMAKE_ARGS} -DASAN=`echo $1 | sed -e 's,--asan=,,'`" - ;; - --elisp-install-location) - shift - CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_ELISP_INSTALL_LOCATION=\"$1\"" - ;; - *) - usage > /dev/stderr - echo "Unknown option $1" - exit 1 - ;; - esac - shift -done - -[ -n "$CMAKE_GENERATOR" ] && CMAKE_ARGS="${CMAKE_ARGS} -G \"$CMAKE_GENERATOR\"" -[ -n "$BUILD" ] && CMAKE_ARGS="${CMAKE_ARGS} -DRTAGS_BUILD_CLANG=1" - -echo -e "Running cmake:\n\"$CMAKE\" \"$(dirname ${BASH_SOURCE[0]})\" ${CMAKE_ARGS}\n" -rm -f CMakeCache.txt -eval "$CMAKE" "$(dirname ${BASH_SOURCE[0]})" ${CMAKE_ARGS} diff --git a/rtags/man/man7/rc.7 b/rtags/man/man7/rc.7 deleted file mode 100644 index 3625fbc..0000000 --- a/rtags/man/man7/rc.7 +++ /dev/null @@ -1,386 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH RC "7" "June 2018" "rc 2.18.125" "User Commands" -.SH NAME -rc \- manual page for rc 2.18.125 -.SH SYNOPSIS -rc [OPTION]... -.SH DESCRIPTION -rc is the RTags client application. -.PP -.SH OPTIONS -.TP -\fB\-\-verbose\fR|\-v -Be more verbose. -.TP -\fB\-\-version\fR -Print current version. -.TP -\fB\-\-verify\-version\fR [arg] -Verify that the correct protocol version is used. -.TP -\fB\-\-silent\fR|\-Q -Be silent. -.TP -\fB\-\-help\fR|\-h -Display this help. -.TP -\fB\-\-config\fR [arg] -Use this file (instead of ~/.rcrc). -.TP -\fB\-\-no\-rc\fR -Don't load any rc files. -.SS "Rdm:" -.TP -\fB\-\-quit\-rdm\fR|\-q -Tell server to shut down with optional exit code as argument. -.TP -\fB\-\-connect\-timeout\fR [arg] -Timeout for connecting to rdm in ms (default 1000). -.SS "Project management:" -.TP -\fB\-\-clear\fR|\-C -Clear projects. -.TP -\fB\-\-project\fR|\-w [optional] -With arg, select project matching that if unique, otherwise list all projects. -.TP -\fB\-\-delete\-project\fR|\-W [arg] -Delete all projects matching regex. -.TP -\fB\-\-job\-count\fR|\-j [optional] -Set or query current job count. (Prefix with l to set low\-priority\-job\-count). -.SS "Indexing commands:" -.TP -\fB\-\-compile\fR|\-c [optional] -Pass compilation arguments to rdm. -.TP -\fB\-\-guess\-flags\fR -Guess compile flags (used with \fB\-c\fR). -.TP -\fB\-\-load\-compile\-commands\fR|\-J [optional] -Load compile_commands.json from directory -.TP -\fB\-\-suspend\fR|\-X [optional] -Dump suspended files (don't track changes in these files) with no arg. Otherwise toggle suspension for arg. -.SS "Query commands:" -.TP -\fB\-\-follow\-location\fR|\-f [arg] -Follow this location. -.TP -\fB\-\-references\-name\fR|\-R [arg] -Find references matching arg. -.TP -\fB\-\-references\fR|\-r [arg] -Find references matching this location. -.TP -\fB\-\-list\-symbols\fR|\-S [optional] -List symbol names matching arg. -.TP -\fB\-\-find\-symbols\fR|\-F [optional] -Find symbols matching arg. -.TP -\fB\-\-symbol\-info\fR|\-U [arg] -Get cursor info for this location. -.TP -\fB\-\-status\fR|\-s [optional] -Dump status of rdm. Arg can be symbols or symbolNames. -.TP -\fB\-\-diagnose\fR [arg] -Resend diagnostics for file. -.TP -\fB\-\-diagnose\-all\fR -Resend diagnostics for all files. -.TP -\fB\-\-last\-indexed\fR -Get timestamp of the last time indexing completed for the current project. -.TP -\fB\-\-is\-indexed\fR|\-T [arg] -Check if rtags knows about, and is ready to return information about, this source file. -.TP -\fB\-\-is\-indexing\fR -Check if rtags is currently indexing files. -.TP -\fB\-\-has\-filemanager\fR [optional] -Check if rtags has info about files in this directory. -.TP -\fB\-\-preprocess\fR|\-E [arg] -Preprocess file. -.TP -\fB\-\-reindex\fR|\-V [optional] -Reindex all files or all files matching pattern. -.TP -\fB\-\-check\-reindex\fR|\-x [optional] -Check if reindexing is necessary for all files matching pattern. -.TP -\fB\-\-path\fR|\-P [optional] -Print files matching pattern. -.TP -\fB\-\-current\-project\fR -Print path for current project. -.TP -\fB\-\-dump\-file\fR|\-d [arg] -Dump source file. -.TP -\fB\-\-check\-includes\fR [arg] -Check includes for source file. -.TP -\fB\-\-dump\-file\-maps\fR [arg] -Dump file maps for file. -.TP -\fB\-\-generate\-test\fR [arg] -Generate a test for a given source file. -.TP -\fB\-\-rdm\-log\fR|\-g -Receive logs from rdm. -.TP -\fB\-\-fixits\fR [arg] -Get fixits for file. -.TP -\fB\-\-remove\fR|\-D [arg] -Remove file from project. -.TP -\fB\-\-find\-project\-root\fR [arg] -Use to check behavior of find\-project\-root. -.TP -\fB\-\-find\-project\-build\-root\fR [arg] -Use to check behavior of find\-project\-root for builds. -.TP -\fB\-\-include\-file\fR [arg] -Use to generate include statement for symbol. -.TP -\fB\-\-sources\fR [optional] -Dump sources for source file. -.TP -\fB\-\-dependencies\fR [arg] -Dump dependencies for source file [(includes, included\-by, depends\-on, depended\-on, tree\-depends\-on, raw)]. -.TP -\fB\-\-all\-dependencies\fR -Dump dependencies for all source files [(includes, included\-by, depends\-on, depended\-on, tree\-depends\-on, raw)]. -.TP -\fB\-\-reload\-file\-manager\fR|\-B -Reload file manager. -.TP -\fB\-\-man\fR -Output XML for xmltoman to generate man page for rc :\-) -.TP -\fB\-\-code\-complete\-at\fR|\-l [arg] -Code complete at location: arg is file:line:col. -.TP -\fB\-\-send\-diagnostics\fR [arg] -Only for debugging. Send data to all \fB\-G\fR connections. -.TP -\fB\-\-dump\-completions\fR -Dump cached completions. -.TP -\fB\-\-dump\-compile\-commands\fR -Dump compilation database for project. -.TP -\fB\-\-set\-buffers\fR [optional] -Set active buffers (list of filenames for active buffers in editor). -.TP -\fB\-\-list\-buffers\fR -List active buffers. -.TP -\fB\-\-add\-buffers\fR [arg] -Add additional buffers. -.TP -\fB\-\-remove\-buffers\fR [arg] -Remove buffers. -.TP -\fB\-\-list\-cursor\-kinds\fR -List spelling for known cursor kinds. -.TP -\fB\-\-class\-hierarchy\fR [arg] -Dump class hierarcy for struct/class at location. -.TP -\fB\-\-debug\-locations\fR [optional] -Manipulate debug locations. -.TP -\fB\-\-validate\fR -Validate database files for current project. -.TP -\fB\-\-tokens\fR [arg] -Dump tokens for file. \fB\-\-tokens\fR file.cpp:123\-321 for range. -.SS "Command flags:" -.TP -\fB\-\-strip\-paren\fR|\-p -Strip parens in various contexts. -.TP -\fB\-\-max\fR|\-M [arg] -Max lines of output for queries. -.TP -\fB\-\-reverse\-sort\fR|\-O -Sort output reversed. -.TP -\fB\-\-rename\fR -Used for \fB\-\-references\fR to indicate that we're using the results to rename symbols. -.TP -\fB\-\-unsaved\-file\fR [arg] -Pass unsaved file on command line. E.g. \fB\-\-unsaved\-file\fR=\fI\,main\/\fR.cpp:1200 then write 1200 bytes on stdin. -.TP -\fB\-\-log\-file\fR|\-L [arg] -Log to this file. -.TP -\fB\-\-no\-context\fR|\-N -Don't print context for locations. -.TP -\fB\-\-path\-filter\fR|\-i [arg] -Filter out results not matching with arg. -.TP -\fB\-\-dependency\-filter\fR [arg] -Filter out results unless argument depends on them. -.TP -\fB\-\-range\-filter\fR [arg] -Filter out results not in the specified range. -.TP -\fB\-\-filter\-system\-headers\fR|\-H -Don't exempt system headers from path filters. -.TP -\fB\-\-all\-references\fR|\-e -Include definitions/declarations/constructors/destructors for references. Used for rename symbol. -.TP -\fB\-\-target\-usrs\fR -Print all matching usr targets for \fB\-f\fR. Used for debugging. -.TP -\fB\-\-all\-targets\fR -Print multiple targets for \fB\-f\fR. Sorted by best match. -.TP -\fB\-\-elisp\fR|\-Y -Output elisp: (list "one" "two" ...). -.TP -\fB\-\-json\fR -Output json. -.TP -\fB\-\-diagnostics\fR|\-m -Receive async formatted diagnostics from rdm. -.TP -\fB\-\-match\-regexp\fR|\-Z -Treat various text patterns as regexps (\fB\-P\fR, \fB\-i\fR, \fB\-V\fR, \fB\-F\fR). -.TP -\fB\-\-match\-icase\fR|\-I -Match case insensitively -.TP -\fB\-\-absolute\-path\fR|\-K -Print files with absolute path. -.TP -\fB\-\-socket\-file\fR|\-n [arg] -Use this socket file (default ~/.rdm). -.TP -\fB\-\-socket\-address\fR [arg] -Use this host:port combination (instead of \fB\-\-socket\-file\fR). -.TP -\fB\-\-timeout\fR|\-y [arg] -Max time in ms to wait for job to finish (default no timeout). -.TP -\fB\-\-find\-virtuals\fR|\-k -Use in combinations with \fB\-R\fR or \fB\-r\fR to show other implementations of this function. -.TP -\fB\-\-find\-file\-prefer\-exact\fR|\-A -Use to make \fB\-\-find\-file\fR prefer exact matches over partial matches. -.TP -\fB\-\-symbol\-info\-include\-parents\fR -Use to make \fB\-\-symbol\-info\fR include parent symbols. -.TP -\fB\-\-symbol\-info\-include\-targets\fR -Use to make \fB\-\-symbol\-info\fR include target symbols. -.TP -\fB\-\-symbol\-info\-include\-references\fR -Use to make \fB\-\-symbol\-info\fR include reference symbols. -.TP -\fB\-\-symbol\-info\-include\-base\-classes\fR -Use to make \fB\-\-symbol\-info\fR include baseclasses' symbols. -.TP -\fB\-\-cursor\-kind\fR -Include cursor kind in \fB\-\-find\-symbols\fR output. -.TP -\fB\-\-display\-name\fR -Include display name in \fB\-\-find\-symbols\fR output. -.TP -\fB\-\-current\-file\fR [arg] -Pass along which file is being edited to give rdm a better chance at picking the right project. -.TP -\fB\-\-declaration\-only\fR|\-G -Filter out definitions (unless inline). -.TP -\fB\-\-definition\-only\fR -Filter out declarations (unless inline). -.TP -\fB\-\-kind\-filter\fR [arg] -Only return results matching this kind. -.TP -\fB\-\-containing\-function\fR|\-o -Include name of containing function in output. -.TP -\fB\-\-containing\-function\-location\fR -Include location of containing function in output. -.TP -\fB\-\-build\-index\fR [arg] -For sources with multiple builds, use the arg'th. -.TP -\fB\-\-compilation\-flags\-only\fR -For \fB\-\-source\fR, only print compilation flags. -.TP -\fB\-\-compilation\-flags\-split\-line\fR -For \fB\-\-source\fR, print one compilation flag per line. -.TP -\fB\-\-compilation\-flags\-pwd\fR -For \fB\-\-source\fR, print pwd for compile command on the first line. -.TP -\fB\-\-dump\-include\-headers\fR -For \fB\-\-dump\-file\fR, also dump dependencies. -.TP -\fB\-\-silent\-query\fR -Don't log this request in rdm. -.TP -\fB\-\-synchronous\-completions\fR -Wait for completion results and print them to stdout. -.TP -\fB\-\-synchronous\-diagnostics\fR -Wait for diagnostics and print them to stdout. -.TP -\fB\-\-xml\fR -Output XML -.TP -\fB\-\-no\-sort\-references\-by\-input\fR -Don't sort references by input position. -.TP -\fB\-\-project\-root\fR [arg] -Override project root for compile commands. -.TP -\fB\-\-rtags\-config\fR [arg] -Print out .rtags\-config for argument. -.TP -\fB\-\-wildcard\-symbol\-names\fR|\-a -Expand * like wildcards in \fB\-\-list\-symbols\fR and \fB\-\-find\-symbols\fR. -.TP -\fB\-\-no\-color\fR|\-z -Don't colorize context. -.TP -\fB\-\-wait\fR -Wait for reindexing to finish. -.TP -\fB\-\-code\-complete\-include\-macros\fR -Include macros in code completion results. -.TP -\fB\-\-code\-complete\-includes\fR -Give includes in completion results. -.TP -\fB\-\-code\-complete\-no\-wait\fR -Don't wait for synchronous completion if the translation unit has to be created. -.TP -\fB\-\-code\-complete\-prefix\fR [arg] -Filter out code completion results that don't start with this prefix. -.TP -\fB\-\-code\-completion\-enabled\fR|\-b -Inform rdm that we're code\-completing. Use with \fB\-\-diagnose\fR -.TP -\fB\-\-no\-spell\-checking\fR -Don't produce spell check info in diagnostics. -.TP -\fB\-\-tokens\-include\-symbols\fR -Include symbols for tokens. -.TP -\fB\-\-no\-realpath\fR -Don't resolve paths using realpath(3). -.SH "SEE ALSO" -rdm(7) diff --git a/rtags/man/man7/rdm.7 b/rtags/man/man7/rdm.7 deleted file mode 100644 index b351d85..0000000 --- a/rtags/man/man7/rdm.7 +++ /dev/null @@ -1,272 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH RDM "7" "June 2018" "rdm 2.18.125" "User Commands" -.SH NAME -rdm \- manual page for rdm 2.18.125 -.SH SYNOPSIS -rdm [OPTION]... -.SH DESCRIPTION -RTags is a client/server application that indexes C/C++ code and keeps -a persistent file\-based database of references, declarations, -definitions, symbolnames etc. There's also limited support for -ObjC/ObjC++. It allows you to find symbols by name (including nested -class and namespace scope). Most importantly we give you proper -follow\-symbol and find\-references support. We also have neat little -things like rename\-symbol, integration with clang's "fixits" -(http://clang.llvm.org/diagnostics.html). We also integrate with -flymake using clang's vastly superior errors and warnings. Since -RTags constantly will reindex "dirty" files you get live updates of -compiler errors and warnings. Since we already know how to compile -your sources we have a way to quickly bring up the preprocessed output -of the current source file in a buffer. - -While existing taggers like gnu global, cscope, etags, ctags etc do a -decent job for C they often fall a little bit short for C++. With its -incredible lexical complexity, parsing C++ is an incredibly hard task -and we make no bones about the fact that the only reason we are able -to improve on the current tools is because of clang -(http://clang.llvm.org/). RTags is named RTags in recognition of -Roberto Raggi on whose C++ parser we intended to base this project but -he assured us clang was the way to go. The name stuck though. -.PP -.SH OPTIONS -.TP -\fB\-\-help\fR|\-h -Display this page. -.TP -\fB\-\-version\fR -Display version. -.TP -\fB\-\-include\-path\fR|\-I [arg] -Add additional include path to clang. -.TP -\fB\-\-no\-libclang\-include\-path\fR -Don't use the include path from libclang. -.TP -\fB\-\-isystem\fR|\-s [arg] -Add additional system include path to clang. -.TP -\fB\-\-define\fR|\-D [arg] -Add additional define directive to clang. -.TP -\fB\-\-default\-argument\fR [arg] -Add additional argument to clang. -.TP -\fB\-\-log\-file\fR|\-L [arg] -Log to this file. -.TP -\fB\-\-crash\-dump\-file\fR [arg] -File to dump crash log to (default is /crash.dump). -.TP -\fB\-\-setenv\fR|\-e [arg] -Set this environment variable (\fB\-\-setenv\fR "foobar=1"). -.TP -\fB\-\-no\-Wall\fR|\-W -Don't use \fB\-Wall\fR. -.TP -\fB\-\-Weverything\fR|\-u -Use \fB\-Weverything\fR. -.TP -\fB\-\-verbose\fR|\-v -Change verbosity, multiple \fB\-v\fR's are allowed. -.TP -\fB\-\-job\-count\fR|\-j [arg] -Spawn this many concurrent processes for indexing. -.TP -\fB\-\-header\-error\-job\-count\fR|\-H [arg] -Allow this many concurrent header error jobs (default std::max(1, \fB\-\-job\-count\fR / 2)). -.TP -\fB\-\-test\fR|\-t [arg] -Run this test. -.TP -\fB\-\-test\-timeout\fR|\-z [arg] -Timeout for test to complete. -.TP -\fB\-\-clean\-slate\fR|\-C -Clear out all data. -.TP -\fB\-\-disable\-sighandler\fR|\-x -Disable signal handler to dump stack for crashes. -.TP -\fB\-\-silent\fR|\-S -No logging to stdout/stderr. -.TP -\fB\-\-exclude\-filter\fR|\-X [arg] -Files to exclude from rdm, default "*/CMakeFiles/*;*/cmake*/Modules/*;*/conftest.c*;/tmp/*;/private/tmp/*;/private/var/*". -.TP -\fB\-\-socket\-file\fR|\-n [arg] -Use this file for the server socket (default ~/.rdm). -.TP -\fB\-\-data\-dir\fR|\-d [arg] -Use this directory to store persistent data (default \fI\,$XDG_CACHE_HOME/rtags\/\fP otherwise ~/.cache/rtags). -.TP -\fB\-\-ignore\-printf\-fixits\fR|\-F -Disregard any clang fixit that looks like it's trying to fix format for printf and friends. -.TP -\fB\-\-error\-limit\fR|\-f [arg] -Set error limit to argument (\fB\-ferror\-limit=\fR{arg} (default 50). -.TP -\fB\-\-block\-argument\fR|\-G [arg] -Block this argument from being passed to clang. E.g. rdm \fB\-\-block\-argument\fR \fB\-fno\-inline\fR -.TP -\fB\-\-no\-spell\-checking\fR|\-l -Don't pass \fB\-fspell\-checking\fR. -.TP -\fB\-\-large\-by\-value\-copy\fR|\-r [arg] -Use \fB\-Wlarge\-by\-value\-copy\fR=\fI\,[arg]\/\fR when invoking clang. -.TP -\fB\-\-allow\-multiple\-sources\fR|\-m -Don't merge source files added with \fB\-c\fR. -.TP -\fB\-\-no\-startup\-project\fR|\-o -Don't restore the last current project on startup. -.TP -\fB\-\-no\-no\-unknown\-warnings\-option\fR|\-Y -Don't pass \fB\-Wno\-unknown\-warning\-option\fR. -.TP -\fB\-\-ignore\-compiler\fR|\-b [arg] -Ignore this compiler. -.TP -\fB\-\-compiler\-wrappers\fR [arg] -Consider these filenames compiler wrappers (split on ;), default ccache". -.TP -\fB\-\-watch\-system\-paths\fR|\-w -Watch system paths for changes. -.TP -\fB\-\-rp\-visit\-file\-timeout\fR|\-Z [arg] -Timeout for rp visitfile commands in ms (0 means no timeout) (default 60000). -.TP -\fB\-\-rp\-indexer\-message\-timeout\fR|\-T [arg] -Timeout for rp indexer\-message in ms (0 means no timeout) (default 60000). -.TP -\fB\-\-rp\-connect\-timeout\fR|\-O [arg] -Timeout for connection from rp to rdm in ms (0 means no timeout) (default 0). -.TP -\fB\-\-rp\-connect\-attempts\fR [arg] -Number of times rp attempts to connect to rdm before giving up. (default 3). -.TP -\fB\-\-rp\-nice\-value\fR|\-a [arg] -Nice value to use for rp (nice(2)) (default is no nicing). -.TP -\fB\-\-suspend\-rp\-on\-crash\fR|\-q -Suspend rp in SIGSEGV handler (default off). -.TP -\fB\-\-rp\-log\-to\-syslog\fR -Make rp log to syslog. -.TP -\fB\-\-start\-suspended\fR|\-Q -Start out suspended (no reindexing enabled). -.TP -\fB\-\-separate\-debug\-and\-release\fR|\-E -Normally rdm doesn't consider release and debug as different builds. Pass this if you want it to. -.TP -\fB\-\-separate\-32\-bit\-and\-64\-bit\fR -Normally rdm doesn't consider \fB\-m32\fR and \fB\-m64\fR as different builds. Pass this if you want it to. -.HP -\fB\-\-ignore\-include\-path\-differences\-in\-usr\fR Don't consider sources that only differ in includepaths within \fI\,/usr\/\fP (not including /usr/home/) as different builds. -.TP -\fB\-\-max\-crash\-count\fR|\-K [arg] -Max number of crashes before giving up a sourcefile (default 5). -.TP -\fB\-\-max\-socket\-write\-buffer\-size\fR [arg] -Max number of bytes buffered after EAGAIN. -.TP -\fB\-\-completion\-cache\-size\fR|\-i [arg] -Number of translation units to cache (default 10). -.TP -\fB\-\-completion\-no\-filter\fR -Don't filter private members and destructors from completions. -.TP -\fB\-\-completion\-logs\fR -Log more info about completions. -.TP -\fB\-\-max\-include\-completion\-depth\fR [arg] -Max recursion depth for header completion (default 3). -.TP -\fB\-\-allow\-Wpedantic\fR|\-P -Don't strip out \fB\-Wpedantic\fR. This can cause problems in certain projects. -.TP -\fB\-\-allow\-Werror\fR -Don't strip out \fB\-Werror\fR and \fB\-Wfatal\-errors\fR. By default these are stripped out. -.TP -\fB\-\-enable\-compiler\-manager\fR|\-R -Query compilers for their actual include paths instead of letting clang use its own. -.TP -\fB\-\-enable\-NDEBUG\fR|\-g -Don't remove \fB\-DNDEBUG\fR from compile lines. -.TP -\fB\-\-progress\fR|\-p -Report compilation progress in diagnostics output. -.TP -\fB\-\-max\-file\-map\-cache\-size\fR|\-y [arg] -Max files to cache per query (Should not exceed maximum number of open file descriptors allowed per process) (default 500). -.TP -\fB\-\-no\-filemanager\-watch\fR|\-M -Don't use a file system watcher for filemanager. -.TP -\fB\-\-no\-filemanager\fR -Don't scan project directory for files. (rc \fB\-P\fR won't work). -.TP -\fB\-\-no\-file\-lock\fR -Disable file locking. Not entirely safe but might improve performance on certain systems. -.TP -\fB\-\-pch\-enabled\fR -Enable PCH (experimental). -.TP -\fB\-\-no\-filesystem\-watcher\fR|\-B -Disable file system watching altogether. Reindexing has to be triggered manually. -.TP -\fB\-\-arg\-transform\fR|\-V [arg] -Use arg to transform arguments. [arg] should be executable with (execv(3)). -.TP -\fB\-\-no\-comments\fR -Don't parse/store doxygen comments. -.TP -\fB\-\-inactivity\-timeout\fR [arg] -Time in seconds after which rdm will quit if there's been no activity (N.B., once rdm has quit, something will need to re\-run it!). -.TP -\fB\-\-daemon\fR -Run as daemon (detach from terminal). -.TP -\fB\-\-log\-file\-log\-level\fR [arg] -Log level for log file (default is error), options are: error, warning, debug or verbose\-debug. -.TP -\fB\-\-watch\-sources\-only\fR -Only watch source files (not dependencies). -.TP -\fB\-\-debug\-locations\fR -Set debug locations. -.TP -\fB\-\-validate\-file\-maps\fR -Spend some time validating project data on startup. -.TP -\fB\-\-tcp\-port\fR [arg] -Listen on this tcp socket (default none). -.TP -\fB\-\-rp\-path\fR [arg] -Path to rp. -.TP -\fB\-\-log\-timestamp\fR -Add timestamp to logs. -.TP -\fB\-\-log\-flush\fR -Flush stderr/stdout after each log. -.TP -\fB\-\-sandbox\-root\fR [arg] -Create index using relative paths by stripping dir (enables copying of tag index db files without need to reindex). -.TP -\fB\-\-poll\-timer\fR [arg] -Poll the database of the current project every seconds. -.TP -\fB\-\-no\-realpath\fR -Don't use realpath(3) for files -.TP -\fB\-\-translation\-unit\-cache\fR -Cache translation units. Not working yet. -.TP -\fB\-\-config\fR|\-c [arg] -Use this file (instead of ~/.rdmrc). -.TP -\fB\-\-no\-rc\fR|\-N -Don't load any rc files. -.SH "SEE ALSO" -rc(7) diff --git a/rtags/scripts/bump-version.sh b/rtags/scripts/bump-version.sh deleted file mode 100755 index 098559e..0000000 --- a/rtags/scripts/bump-version.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -SCRIPT="$(readlink -f ${BASH_SOURCE[0]})" -DIR="$(dirname $SCRIPT)" - -# echo "$SCRIPT $DIR" - -MAJOR=`echo $1 | awk -F. '{print $1}'` -MINOR=`echo $1 | awk -F. '{print $2}'` - -if ! echo "$1" | grep -q "^[0-9]\+\.[0-9]\+$"; then - echo "Bad argument: \"$1\"" - echo "Usage bump-version.sh 3.22" - exit 1 -fi - -SED=sed -[ -n "`which gsed`" ] && SED=gsed - -$SED -i"" -e "s,^set(RTAGS_VERSION_MAJOR [0-9]\+),set(RTAGS_VERSION_MAJOR $MAJOR)," -e "s,^set(RTAGS_VERSION_MINOR [0-9]\+),set(RTAGS_VERSION_MINOR $MINOR)," "$DIR/../CMakeLists.txt" -$SED -i"" -e "s,^(defconst rtags-package-version \"[0-9]\+\.[0-9]\+\"),(defconst rtags-package-version \"${MAJOR}.${MINOR}\")," "$DIR/../src/rtags.el" -$SED -i"" -e "s,https://andersbakken\.github\.io/rtags-releases/rtags-[0-9]\+\.[0-9]\+\.tar\.,https://andersbakken.github.io/rtags-releases/rtags-$MAJOR.$MINOR.tar.,g" "$DIR/../README.org" - -git commit -m "Bump version to ${MAJOR}.${MINOR}" $DIR/../README.org $DIR/../CMakeLists.txt $DIR/../src/rtags.el -git tag "v${MAJOR}.${MINOR}" diff --git a/rtags/scripts/fix-dylib.sh b/rtags/scripts/fix-dylib.sh deleted file mode 100755 index 83f4fe0..0000000 --- a/rtags/scripts/fix-dylib.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -#nstall_name_tool -change "@executable_path/../lib/libclang.3.2.dylib" "@executable_path/../3rdparty/clang_install/lib/libclang.3.2.dylib" rdm - -REAL=$(readlink "$1"/3rdparty/clang_install/lib/libclang.dylib) -install_name_tool -change "@executable_path/../lib/$(basename \"$REAL\")" "@executable_path/../3rdparty/clang_install/lib/$(basename \"$REAL\")" $2 diff --git a/rtags/scripts/gen-man-pages.sh b/rtags/scripts/gen-man-pages.sh deleted file mode 100755 index 8a394c6..0000000 --- a/rtags/scripts/gen-man-pages.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash -e -# gen-man-pages.sh --- generate man pages -# -# Copyright (c) Christian Schwarzgruber -# -# This file is part of RTags (http://rtags.net). -# -# RTags is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or (at -# your option) any later version. -# -# RTags is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Emacs. If not, see . */ -# -# Description: rc, rdm and help2man need to be in the PATH environment variable. -BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" - -if [ $# -lt 1 ]; then - echo "Usage: $(basename $0) RDM_RC_BIN_DIR" - exit 1 -fi - -MAN_BASE="$BASE_DIR/man/man7" - -# Force simply locale `C` -LC_TIME=C - -# Generate the rc manual page. -echo 'Generating manual page for "rc"' -help2man --no-info -s 7 \ - -i <(echo " -[SYNOPSIS] -rc [OPTION]... - -[DESCRIPTION] -rc is the RTags client application. - -[SEE ALSO] -rdm(7) -") "$1/rc" > "$MAN_BASE/rc.7" - -# Generate the rdm manual page. -echo 'Generating manual page for "rdm"' -help2man --no-info -s 7 \ - -i <(echo " -[SYNOPSIS] -rdm [OPTION]... - -[DESCRIPTION] -RTags is a client/server application that indexes C/C++ code and keeps -a persistent file\-based database of references, declarations, -definitions, symbolnames etc. There's also limited support for -ObjC/ObjC++. It allows you to find symbols by name (including nested -class and namespace scope). Most importantly we give you proper -follow\-symbol and find\-references support. We also have neat little -things like rename\-symbol, integration with clang's \"fixits\" -(http://clang.llvm.org/diagnostics.html). We also integrate with -flymake using clang's vastly superior errors and warnings. Since -RTags constantly will reindex \"dirty\" files you get live updates of -compiler errors and warnings. Since we already know how to compile -your sources we have a way to quickly bring up the preprocessed output -of the current source file in a buffer. - -While existing taggers like gnu global, cscope, etags, ctags etc do a -decent job for C they often fall a little bit short for C++. With its -incredible lexical complexity, parsing C++ is an incredibly hard task -and we make no bones about the fact that the only reason we are able -to improve on the current tools is because of clang -(http://clang.llvm.org/). RTags is named RTags in recognition of -Roberto Raggi on whose C++ parser we intended to base this project but -he assured us clang was the way to go. The name stuck though. - -[SEE ALSO] -rc(7) -") "$1/rdm" > "$MAN_BASE/rdm.7" - -# Fix-ups -sed -ri \ - -e '/^(rdm|rc) options...$/d' \ - -e 's/^Options:$/.SH OPTIONS/' \ - -e 's/^(Path to rp) \(default.*\).$/\1./' \ - -e '/job\\-count/{ - n - s/(.*indexing) \(default [0-9]+\).$/\1./ - }' \ - "$MAN_BASE/rc.7" "$MAN_BASE/rdm.7" -exit 0 diff --git a/rtags/scripts/getclang.sh b/rtags/scripts/getclang.sh deleted file mode 100755 index 136f32d..0000000 --- a/rtags/scripts/getclang.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -VERSION="$1" -[ -z "${VERSION}" ] && VERSION="3.8.1" - -CHECKSUMDIR=`dirname "${BASH_SOURCE[0]}"`/../llvm-checksums/ - -LLVM=llvm-${VERSION}.src -LLVM_FILE=${LLVM}.tar.xz -CLANG=cfe-${VERSION}.src -CLANG_FILE=${CLANG}.tar.xz -LIBCXX=libcxx-${VERSION}.src -LIBCXX_FILE=${LIBCXX}.tar.xz - -function dnload() -{ - local FILE=$1-${VERSION}.src.tar.xz - local URL=http://llvm.org/releases/${VERSION}/${FILE} - STATUS=`curl -L -w "%{http_code}" -z ${FILE} https://releases.llvm.org/${VERSION}/${FILE} -o ${FILE} 2>/dev/null` - echo ${STATUS} -} - -STATUS=`dnload llvm` -if [ "${STATUS}" == 200 ] || [ ! -d llvm ]; then - tar xf ${LLVM_FILE} - rm -rf llvm - mv ${LLVM} llvm - dnload cfe >/dev/null - tar xf ${CLANG_FILE} - rm -f llvm/tools/clang - mv ${CLANG} llvm/tools/clang - - if [ `uname -s` = Darwin ]; then - dnload libcxx >/dev/null - tar xf ${LIBCXX_FILE} - mv ${LIBCXX} llvm/projects/libcxx - fi -fi diff --git a/rtags/scripts/git-archive-all b/rtags/scripts/git-archive-all deleted file mode 100755 index 0f96f00..0000000 --- a/rtags/scripts/git-archive-all +++ /dev/null @@ -1,292 +0,0 @@ -#!/bin/bash - -# -# File: git-archive-all.sh -# -# Description: A utility script that builds an archive file(s) of all -# git repositories and submodules in the current path. -# Useful for creating a single tarfile of a git super- -# project that contains other submodules. -# -# Examples: Use git-archive-all.sh to create archive distributions -# from git repositories. To use, simply do: -# -# cd $GIT_DIR; git-archive-all.sh -# -# where $GIT_DIR is the root of your git superproject. -# -# License: GPL3 -# -############################################################################### -# -# 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 2 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, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -############################################################################### - -# DEBUGGING -set -e -set -C # noclobber - -# TRAP SIGNALS -trap 'cleanup' QUIT EXIT - -# For security reasons, explicitly set the internal field separator -# to newline, space, tab -OLD_IFS=$IFS -IFS=' - ' - -function cleanup () { - rm -f $TMPFILE - rm -f $TOARCHIVE - IFS="$OLD_IFS" -} - -function usage () { - echo "Usage is as follows:" - echo - echo "$PROGRAM <--version>" - echo " Prints the program version number on a line by itself and exits." - echo - echo "$PROGRAM <--usage|--help|-?>" - echo " Prints this usage output and exits." - echo - echo "$PROGRAM [--format ] [--prefix ] [--verbose|-v] [--separate|-s]" - echo " [--tree-ish|-t ] [output_file]" - echo " Creates an archive for the entire git superproject, and its submodules" - echo " using the passed parameters, described below." - echo - echo " If '--format' is specified, the archive is created with the named" - echo " git archiver backend. Obviously, this must be a backend that git archive" - echo " understands. The format defaults to 'tar' if not specified." - echo - echo " If '--prefix' is specified, the archive's superproject and all submodules" - echo " are created with the prefix named. The default is to not use one." - echo - echo " If '--separate' or '-s' is specified, individual archives will be created" - echo " for each of the superproject itself and its submodules. The default is to" - echo " concatenate individual archives into one larger archive." - echo - echo " If '--tree-ish' is specified, the archive will be created based on whatever" - echo " you define the tree-ish to be. Branch names, commit hash, etc. are acceptable." - echo " Defaults to HEAD if not specified. See git archive's documentation for more" - echo " information on what a tree-ish is." - echo - echo " If 'output_file' is specified, the resulting archive is created as the" - echo " file named. This parameter is essentially a path that must be writeable." - echo " When combined with '--separate' ('-s') this path must refer to a directory." - echo " Without this parameter or when combined with '--separate' the resulting" - echo " archive(s) are named with a dot-separated path of the archived directory and" - echo " a file extension equal to their format (e.g., 'superdir.submodule1dir.tar')." - echo - echo " The special value '-' (single dash) is treated as STDOUT and, when used, the" - echo " --separate option is ignored. Use a double-dash to separate the outfile from" - echo " the value of previous options. For example, to write a .zip file to STDOUT:" - echo - echo " ./$PROGRAM --format zip -- -" - echo - echo " If '--verbose' or '-v' is specified, progress will be printed." -} - -function version () { - echo "$PROGRAM version $VERSION" -} - -# Internal variables and initializations. -readonly PROGRAM=$(basename "$0") -readonly VERSION=0.3 - -SEPARATE=0 -VERBOSE=0 - -TARCMD=$(command -v gnutar || command -v gtar || command -v tar) -FORMAT=tar -PREFIX= -TREEISH=HEAD - -# RETURN VALUES/EXIT STATUS CODES -readonly E_BAD_OPTION=254 -readonly E_UNKNOWN=255 - -# Process command-line arguments. -while test $# -gt 0; do - if [ x"$1" == x"--" ]; then - # detect argument termination - shift - break - fi - case $1 in - --format ) - shift - FORMAT="$1" - shift - ;; - - --prefix ) - shift - PREFIX="$1" - shift - ;; - - --separate | -s ) - shift - SEPARATE=1 - ;; - - --tree-ish | -t ) - shift - TREEISH="$1" - shift - ;; - - --version ) - version - exit - ;; - - --verbose | -v ) - shift - VERBOSE=1 - ;; - - -? | --usage | --help ) - usage - exit - ;; - - -* ) - echo "Unrecognized option: $1" >&2 - usage - exit $E_BAD_OPTION - ;; - - * ) - break - ;; - esac -done - -OLD_PWD=$(pwd) -TMPDIR=${TMPDIR:-/tmp} -TMPFILE=$(mktemp "$TMPDIR/$PROGRAM.XXXXXX") # Create a place to store our work's progress -TOARCHIVE=$(mktemp "$TMPDIR/$PROGRAM.toarchive.XXXXXX") -OUT_FILE=$OLD_PWD # assume "this directory" without a name change by default - -if [ ! -z "$1" ]; then - OUT_FILE="$1" - if [ "-" == $OUT_FILE ]; then - SEPARATE=0 - fi - shift -fi - -# Validate parameters; error early, error often. -if [ "-" == $OUT_FILE -o $SEPARATE -ne 1 ] && [ "$FORMAT" == "tar" -a $($TARCMD --help | grep -q -- "--concatenate"; echo $?) -ne 0 ]; then - echo "Your 'tar' does not support the '--concatenate' option, which we need" - echo "to produce a single tarfile. Either install a compatible tar (such as" - echo "gnutar), or invoke $PROGRAM with the '--separate' option." - exit -elif [ $SEPARATE -eq 1 -a ! -d $OUT_FILE ]; then - echo "When creating multiple archives, your destination must be a directory." - echo "If it's not, you risk being surprised when your files are overwritten." - exit -elif [ $(git config -l | grep -q '^core\.bare=false'; echo $?) -ne 0 ]; then - echo "$PROGRAM must be run from a git working copy (i.e., not a bare repository)." - exit -fi - -# Create the superproject's git-archive -if [ $VERBOSE -eq 1 ]; then - echo -n "creating superproject archive..." -fi -git archive --format=$FORMAT --prefix="$PREFIX" $TREEISH > "$TMPDIR/$(basename "$(pwd)").$FORMAT" -if [ $VERBOSE -eq 1 ]; then - echo "done" -fi -echo "$TMPDIR/$(basename "$(pwd)").$FORMAT" >| $TMPFILE # clobber on purpose -superfile=$(head -n 1 $TMPFILE) - -if [ $VERBOSE -eq 1 ]; then - echo -n "looking for subprojects..." -fi -# find all '.git' dirs, these show us the remaining to-be-archived dirs -# we only want directories that are below the current directory -find . -mindepth 2 -name '.git' -type d -print | sed -e 's/^\.\///' -e 's/\.git$//' >> $TOARCHIVE -# as of version 1.7.8, git places the submodule .git directories under the superprojects .git dir -# the submodules get a .git file that points to their .git dir. we need to find all of these too -find . -mindepth 2 -name '.git' -type f -print0 | xargs -0 grep -l "gitdir" | sed -e 's/^\.\///' -e 's/\.git$//' >> $TOARCHIVE -if [ $VERBOSE -eq 1 ]; then - echo "done" - echo " found:" - while read arch - do - echo " $arch" - done < $TOARCHIVE -fi - -if [ $VERBOSE -eq 1 ]; then - echo -n "archiving submodules..." -fi -while read path; do - TREEISH=$(git submodule | grep "^ .*${path%/} " | cut -d ' ' -f 2) # git submodule does not list trailing slashes in $path - cd "$path" - git archive --format=$FORMAT --prefix="${PREFIX}$path" ${TREEISH:-HEAD} > "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT - if [ $FORMAT == 'zip' ]; then - # delete the empty directory entry; zipped submodules won't unzip if we don't do this - zip -d "$(tail -n 1 $TMPFILE)" "${PREFIX}${path%/}" >/dev/null # remove trailing '/' - fi - echo "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT >> $TMPFILE - cd "$OLD_PWD" -done < $TOARCHIVE -if [ $VERBOSE -eq 1 ]; then - echo "done" -fi - -if [ $VERBOSE -eq 1 ]; then - echo -n "concatenating archives into single archive..." -fi -# Concatenate archives into a super-archive. -if [ $SEPARATE -eq 0 -o "-" == $OUT_FILE ]; then - if [ $FORMAT == 'tar' ]; then - sed -e '1d' $TMPFILE | while read file; do - $TARCMD --concatenate -f "$superfile" "$file" && rm -f "$file" - done - elif [ $FORMAT == 'zip' ]; then - sed -e '1d' $TMPFILE | while read file; do - # zip incorrectly stores the full path, so cd and then grow - cd "$(dirname $file)" - zip -g "$superfile" "$(basename $file)" && rm -f "$file" - done - cd "$OLD_PWD" - fi - - echo "$superfile" >| $TMPFILE # clobber on purpose -fi -if [ $VERBOSE -eq 1 ]; then - echo "done" -fi - -if [ $VERBOSE -eq 1 ]; then - echo -n "moving archive to $OUT_FILE..." -fi -while read file; do - if [ "-" == $OUT_FILE ]; then - cat "$file" && rm -f "$file" - else - mv "$file" "$OUT_FILE" - fi -done < $TMPFILE -if [ $VERBOSE -eq 1 ]; then - echo "done" -fi diff --git a/rtags/scripts/llvm-osx/build.sh b/rtags/scripts/llvm-osx/build.sh deleted file mode 100755 index 107ad5b..0000000 --- a/rtags/scripts/llvm-osx/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -brew tap homebrew/versions -brew install llvm38 --with-libcxx --with-clang --without-assertions --rtti $@ diff --git a/rtags/scripts/rtags-release.sh b/rtags/scripts/rtags-release.sh deleted file mode 100755 index 0a1ff52..0000000 --- a/rtags/scripts/rtags-release.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -### TO RUN -### curl https://raw.githubusercontent.com/Andersbakken/rtags/master/scripts/rtags-release.sh | bash - -REPO=`mktemp -d` -RELEASES_REPO=`mktemp -d` -CMAKE_ARGS="-DRTAGS_ENABLE_DEV_OPTIONS=1" -FORCE= - -while [ -n "$1" ]; do - case "$1" in - --repo|-r) - shift - REPO="$1" - ;; - --releases-repo|-R) - shift - RELEASES_REPO="$1" - ;; - --force|-f) - FORCE=1 - ;; - --cmake-args|-C) - shift - CMAKE_ARGS="$CMAKE_ARGS $1" - ;; - *) - echo "Unknown option $1" - exit 1 - ;; - esac - shift -done - -git clone git@github.com:Andersbakken/rtags.git "$REPO" --recursive --depth 1 || exit 1 -cd "$REPO" - -branch_name="$(git symbolic-ref HEAD 2>/dev/null)" || branch_name="(unnamed branch)" # detached HEAD -branch_name=${branch_name##refs/heads/} -if [ "$branch_name" != "master" ]; then - echo wrong branch $branch_name - exit 1 -fi - -commit=$(git show --oneline --no-patch) -current=`curl --silent http://andersbakken.github.io/rtags-releases/commit | cut -d' ' -f1` -if [ "`echo "$commit" | cut -d' ' -f1`" = "$current" -a -z "$FORCE" ]; then - exit 0 -fi - -git clone git@github.com:Andersbakken/rtags-releases.git "$RELEASES_REPO" --recursive --depth 1 || exit 1 -cd "$RELEASES_REPO" -if ! git branch | grep --quiet "^\* *gh-pages$"; then - echo "wrong branch" - exit 1 -fi - -rm -rf .git/hooks/* - -cmake "$REPO" $CMAKE_ARGS >/dev/null || exit 1 -make package_source >/dev/null || exit 1 -cmake "$REPO" $CMAKE_ARGS -DCPACK_GENERATOR=TBZ2 >/dev/null 2>&1 || exit 1 -make package_source >/dev/null || exit 1 -echo "$commit" > commit -git add *.tar.gz *.tar.bz2 commit >/dev/null -git commit --amend -m "Release for $commit" >/dev/null -git push -f git@github.com:Andersbakken/rtags-releases.git gh-pages >/dev/null -rm -rf "$REPO" "$RELEASES_REPO" diff --git a/rtags/scripts/travis.sh b/rtags/scripts/travis.sh deleted file mode 100755 index 12948bc..0000000 --- a/rtags/scripts/travis.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash -e -# travis.sh --- setup and compile script for travis -# -# Copyright (c) Christian Schwarzgruber -# Author: Christian Schwarzgruber -# Created: Tue May 10 22:28:28 2016 (+0200) -# -# This file is part of RTags (http://rtags.net). -# -# RTags is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# RTags is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with RTags. If not, see . */ -# -# Description: The following variables can be changed from the build matrix: -# - ASAN (default value is "1") -# - LUA_VERSION (default value is "5.3.2") -# - LUA_DISABLE (default value is "", set it to anything to disable lua -# extension for that matrix) -declare -a CMAKE_PARAMS=("-DCMAKE_CXX_COMPILER=$CXX$COMPILER_VERSION" - "-DBUILD_TESTING=1" - "-DCMAKE_C_COMPILER=$CC$COMPILER_VERSION") - -if [ "$ASAN" ]; then - CMAKE_PARAMS+=("-DASAN=address,undefined") -fi - -LUA_DISABLE=${LUA_DISABLE:-""} -if [ ! $LUA_DISABLE ]; then - CMAKE_PARAMS+=("-DLUA_ENABLED=1") - echo "Running build with Lua extension." -else - echo "Running build without Lua extension." -fi # end ! $LUA_DISABLE - -function build() -{ - mkdir build && pushd build > /dev/null - cmake "${CMAKE_PARAMS[@]}" .. || cat CMakeFiles/CMakeError.log - make VERBOSE=1 -j2 -} - -# All arguments will be passed on to ctest -function run_tests() -{ - PATH=$(pwd)/bin:$PATH - ctest --output-on-failure --verbose $@ -} - -function osx() -{ - ## Step -- Setup - brew update - brew install llvm yarn cppunit - brew upgrade python3 - python3 -m pip install --upgrade pip - pip3 install --user --upgrade nose PyHamcrest - # Add nosetest bin dir to the env path var - PATH=$PATH:/Users/travis/Library/Python/3.6/bin - - ## Step -- Build - build - - ## Step -- Test - run_tests -} - -function gnu_linux() -{ - ## Step -- Setup - pip3 install --user --upgrade nose PyHamcrest - - ## Step -- Build - build - - ## Step -- Test - run_tests -} - -if [ $TRAVIS_OS_NAME = osx ]; then - osx -else - gnu_linux -fi - -exit 0 diff --git a/rtags/share/etc/init.d/rtags b/rtags/share/etc/init.d/rtags deleted file mode 100755 index 2bd5be6..0000000 --- a/rtags/share/etc/init.d/rtags +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# -# chkconfig: 35 90 12 -# description: Foo server -# - -# Get function from functions library -. /etc/init.d/functions - -# Start the service FOO -start() { - initlog -c "echo -n Starting FOO server: " - /path/to/FOO & - ### Create the lock file ### - touch /var/lock/subsys/FOO - success $"FOO server startup" - echo -} - -# Restart the service FOO -stop() { - initlog -c "echo -n Stopping FOO server: " - killproc FOO - ### Now, delete the lock file ### - rm -f /var/lock/subsys/FOO - echo -} - -### main logic ### -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status FOO - ;; - restart|reload|condrestart) - stop - start - ;; - *) - echo $"Usage: $0 {start|stop|restart|reload|status}" - exit 1 -esac - -exit 0 diff --git a/rtags/share/etc/services/system/rdm.service b/rtags/share/etc/services/system/rdm.service deleted file mode 100644 index c0f6fd6..0000000 --- a/rtags/share/etc/services/system/rdm.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=RTags daemon - -Requires=rdm.socket - -[Service] -Type=simple -ExecStart=$RDM -v --inactivity-timeout 300 --log-flush -ExecStartPost=/bin/sh -c "echo +19 > /proc/$MAINPID/autogroup" -Nice=19 -CPUSchedulingPolicy=idle diff --git a/rtags/share/etc/services/system/rdm.socket b/rtags/share/etc/services/system/rdm.socket deleted file mode 100644 index 68363b6..0000000 --- a/rtags/share/etc/services/system/rdm.socket +++ /dev/null @@ -1,8 +0,0 @@ -[Unit] -Description=RTags daemon socket - -[Socket] -ListenStream=%t/rdm.socket - -[Install] -WantedBy=default.target diff --git a/rtags/src/AST.cpp b/rtags/src/AST.cpp deleted file mode 100644 index 49a5057..0000000 --- a/rtags/src/AST.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "AST.h" -#include "ClangThread.h" -#include "selene.h" - -#define TO_STR1(x) #x -#define TO_STR(x) TO_STR1(x) - -struct UserData { - List parents; - AST *ast; -}; -CXChildVisitResult AST::visitor(CXCursor cursor, CXCursor, CXClientData u) -{ - UserData *userData = reinterpret_cast(u); - assert(userData); - Cursor::Data *p = userData->parents.isEmpty() ? 0 : userData->parents.back().data.get(); - Cursor c = userData->ast->construct(cursor, p); - userData->parents.push_back(Cursor { c.data } ); - clang_visitChildren(cursor, visitor, u); - if (userData->parents.size() > 1) - userData->parents.pop_back(); - return CXChildVisit_Continue; -} - -template static void assign(sel::Selector selector, const T &t) { selector = t; } -void assign(sel::Selector selector, const String &str) { selector = str.ref(); } - -template -static void exposeArray(sel::Selector selector, const std::vector &array) -{ - int i = 0; - for (const T &t : array) { - assign(selector[i++], t); - } -} - -static void registerClasses(sel::State &state) -{ - state["SourceLocation"].SetClass("line", &AST::SourceLocation::line, - "column", &AST::SourceLocation::column, - "file", &AST::SourceLocation::file, - "offset", &AST::SourceLocation::offset, - "toString", &AST::SourceLocation::toString); - state["SourceRange"].SetClass("start", &AST::SourceRange::start, - "end", &AST::SourceRange::end, - "length", &AST::SourceRange::length, - "toString", &AST::SourceRange::toString); - - auto cursors = state["Cursors"]; - cursors.SetClass("size", &AST::Cursors::size, - "at", &AST::Cursors::at); - auto cursor = state["Cursor"]; - cursor.SetClass("location", &AST::Cursor::location, - "usr", &AST::Cursor::usr, - "kind", &AST::Cursor::kind, - "linkage", &AST::Cursor::linkage, - "availability", &AST::Cursor::availability, - "language", &AST::Cursor::language, - "spelling", &AST::Cursor::spelling, - "displayName", &AST::Cursor::displayName, - "rawComment", &AST::Cursor::rawComment, - "briefComment", &AST::Cursor::briefComment, - "mangledName", &AST::Cursor::mangledName, - "templateKind", &AST::Cursor::templateKind, - "range", &AST::Cursor::range, - "children", &AST::Cursor::children, - "query", &AST::Cursor::query, - "None", &AST::Cursor::none, - "Add", &AST::Cursor::add, - "Recurse", &AST::Cursor::recurse, - "overriddenCount", &AST::Cursor::overriddenCount, - "overriddenCursors", &AST::Cursor::overriddenCursors, - "argumentCount", &AST::Cursor::argumentCount, - "arguments", &AST::Cursor::arguments, - "fieldBitWidth", &AST::Cursor::fieldBitWidth, - "typedefUnderlyingType", &AST::Cursor::typedefUnderlyingType, - "enumIntegerType", &AST::Cursor::enumIntegerType, - "enumConstantValue", &AST::Cursor::enumConstantValue, - "includedFile", &AST::Cursor::includedFile, - "templateArgumentCount", &AST::Cursor::templateArgumentCount, - "templateArgumentType", &AST::Cursor::templateArgumentType, - "templateArgumentValue", &AST::Cursor::templateArgumentValue, - "templateArgumentKind", &AST::Cursor::templateArgumentKind, - "referenced", &AST::Cursor::referenced, - "canonical", &AST::Cursor::canonical, - "lexicalParent", &AST::Cursor::lexicalParent, - "semanticParent", &AST::Cursor::semanticParent, - "definitionCursor", &AST::Cursor::definitionCursor, - "specializedCursorTemplate", &AST::Cursor::specializedCursorTemplate, - "childCount", &AST::Cursor::childCount, - "child", &AST::Cursor::child, - "isBitField", &AST::Cursor::isBitField, - "isVirtualBase", &AST::Cursor::isVirtualBase, - "isStatic", &AST::Cursor::isStatic, - "isVirtual", &AST::Cursor::isVirtual, - "isPureVirtual", &AST::Cursor::isPureVirtual, - "isConst", &AST::Cursor::isConst, - "isDefinition", &AST::Cursor::isDefinition, - "isDynamicCall", &AST::Cursor::isDynamicCall); -} - -std::shared_ptr AST::create(const Source &source, const String &sourceCode, CXTranslationUnit unit) -{ - std::shared_ptr ast(new AST); - ast->mState.reset(new sel::State {true}); - sel::State &state = *ast->mState; - registerClasses(state); - ast->mSourceCode = sourceCode; - state["sourceFile"] = source.sourceFile().ref(); - state["sourceCode"] = sourceCode.ref(); - state["write"] = [ast](const std::string &str) { - // error() << "writing" << str; - ast->mReturnValues.append(str); - }; - - exposeArray(state["commandLine"], source.toCommandLine(Source::Default|Source::IncludeCompiler|Source::IncludeSourceFile)); - - if (unit) { - UserData userData; - userData.ast = ast.get(); - visitor(clang_getTranslationUnitCursor(unit), clang_getNullCursor(), &userData); - - const Cursor root = userData.parents.front(); - state["root"] = [root]() { return root; }; - state["findByUsr"] = [ast](const std::string &usr) { - return ast->mByUsr.value(usr); - }; - - state["findByOffset"] = [ast](const std::string &str) { - // int offset = atoi(str.c_str()); - // if (offset) { - - // } else - // sscanf - // return mByUsr.value(usr); - }; - const String script = Path(TO_STR(RTAGS_SOURCE_DIR) "/rtags.lua").readAll(); - state(script.constData()); - } - return ast; -} - -List AST::diagnostics() const -{ - return List(); -} - -List AST::skippedRanges() const -{ - return List(); -} - -List AST::evaluate(const String &script) -{ - assert(mReturnValues.isEmpty()); - try { - mState->operator()(script.constData()); - } catch (...) { - error() << "Got exception"; - } - return std::move(mReturnValues); -} diff --git a/rtags/src/AST.h b/rtags/src/AST.h deleted file mode 100644 index faddefe..0000000 --- a/rtags/src/AST.h +++ /dev/null @@ -1,460 +0,0 @@ -#ifndef AST_h -#define AST_h - -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include -#include "Source.h" -#include "Location.h" -#include "RTags.h" -#include "rct/String.h" -#include "rct/List.h" - -namespace sel { -class State; -}; -class AST -{ -public: - template - static std::string toString(T t) - { - String str; - Log(&str) << t; - return str.ref(); - } - static std::string toString(CXString str) - { - return RTags::eatString(str).ref(); - } - struct SourceLocation { - SourceLocation() - : offset(-1) - {} - - bool operator<(const SourceLocation &other) const { return location < other.location; } - - bool isNull() const { return location.isNull(); } - Location location; - int offset; - - int line() const { return location.line(); } - int column() const { return location.column(); } - std::string file() const { return location.path(); } - std::string toString() const - { - return String::format<256>("%s,%d", - location.toString(Location::AbsolutePath|Location::NoColor).constData(), - offset); - } - - }; - - struct SourceRange { - SourceRange(const CXSourceRange &r = clang_getNullRange()) - : range(r) - {} - CXSourceRange range; - - SourceLocation start() const { return AST::createLocation(clang_getRangeStart(range)); } - SourceLocation end() const { return AST::createLocation(clang_getRangeEnd(range)); } - int length() const { return end().offset - start().offset; } - std::string toString() const { return start().toString() + " - " + end().toString(); } - }; - struct CursorType; - struct Cursors; - struct Cursor { - struct Data : public std::enable_shared_from_this { - Data(AST *a, Data *p, const CXCursor &c, const SourceLocation &loc, const std::string &u = std::string()) - : ast(a), parent(p), cursor(c), location(loc), usr(u) - { - } - ~Data() - { - for (Data *child : children) - delete child; - } - - AST *ast; - Data *parent; - List children; - CXCursor cursor; - SourceLocation location; - std::string usr; - }; - - SourceLocation location() const { return data ? data->location : SourceLocation(); } - std::string usr() const { return data ? data->usr : std::string(); } - std::string kind() const { return stringProperty(&clang_getCursorKind); } - std::string linkage() const { return stringProperty(&clang_getCursorLinkage); } - std::string availability() const { return stringProperty(&clang_getCursorAvailability); } - std::string language() const { return stringProperty(&clang_getCursorAvailability); } - std::string spelling() const { return stringProperty(&clang_getCursorSpelling); } - std::string displayName() const { return stringProperty(&clang_getCursorDisplayName); } - std::string rawComment() const { return stringProperty(&clang_Cursor_getRawCommentText); } - std::string briefComment() const { return stringProperty(&clang_Cursor_getBriefCommentText); } - - std::string mangledName() const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 28) - return stringProperty(&clang_Cursor_getMangling); -#else - return std::string(); -#endif - } - std::string templateKind() const { return stringProperty(&clang_getTemplateCursorKind); } - SourceRange range() const { return data ? SourceRange { clang_getCursorExtent(data->cursor) } : SourceRange(); } - unsigned overriddenCount() const - { - unsigned count = 0; - if (data) { - CXCursor *overridden = 0; - clang_getOverriddenCursors(data->cursor, &overridden, &count); - if (overridden) - clang_disposeOverriddenCursors(overridden); - } - return count; - } - Cursors overriddenCursors() const - { - Cursors ret; - if (data) { - CXCursor *overridden = 0; - unsigned count; - clang_getOverriddenCursors(data->cursor, &overridden, &count); - ret.resize(count); - for (unsigned i=0; iast->create(overridden[i]); - clang_disposeOverriddenCursors(overridden); - } - return ret; - } - - unsigned argumentCount() const { return data ? RTags::cursorArguments(data->cursor) : 0; } - inline Cursors arguments() const; - - int fieldBitWidth() const { return intProperty(&clang_getFieldDeclBitWidth); } - CursorType typedefUnderlyingType() const { return cursorTypeProperty(&clang_getTypedefDeclUnderlyingType); } - CursorType enumIntegerType() const { return cursorTypeProperty(&clang_getEnumDeclIntegerType); } - long long enumConstantValue() const { return intProperty(&clang_getEnumConstantDeclValue); } - std::string includedFile() const - { - if (data && clang_getCursorKind(data->cursor) == CXCursor_InclusionDirective) { - CXFile includedFile = clang_getIncludedFile(data->cursor); - if (includedFile) { - CXStringScope fn = clang_getFileName(includedFile); - const char *cstr = clang_getCString(fn); - if (cstr) - return Path::resolved(cstr).ref(); - } - } - return std::string(); - } - - unsigned templateArgumentCount() const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 28) - return data ? clang_Cursor_getNumTemplateArguments(data->cursor) : 0; -#else - return 0; -#endif - } - CursorType templateArgumentType(unsigned idx) const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 28) - return data ? CursorType(data->ast, clang_Cursor_getTemplateArgumentType(data->cursor, idx)) : CursorType(); -#else - (void)idx; - return CursorType(); -#endif - } - long long templateArgumentValue(unsigned idx) const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 28) - return data ? clang_Cursor_getTemplateArgumentValue(data->cursor, idx) : -1; -#else - (void)idx; - return -1; -#endif - } - std::string templateArgumentKind(unsigned idx) const - { - std::string ret; -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 28) - if (data) - ret = toString(clang_Cursor_getTemplateArgumentKind(data->cursor, idx)); -#else - (void)idx; -#endif - return ret; - } - - Cursor referenced() const { return cursorProperty(&clang_getCursorReferenced); } - Cursor canonical() const { return cursorProperty(&clang_getCanonicalCursor); } - Cursor lexicalParent() const { return cursorProperty(&clang_getCursorLexicalParent); } - Cursor semanticParent() const { return cursorProperty(&clang_getCursorSemanticParent); } - Cursor definitionCursor() const { return cursorProperty(& clang_getCursorDefinition); } - Cursor specializedCursorTemplate() const { return cursorProperty(&clang_getSpecializedCursorTemplate); } - int childCount() const { return data ? data->children.size() : 0; } - Cursor child(int idx) const { return data ? Cursor{ data->children.value(idx)->shared_from_this() } : Cursor(); } - Cursors children() const; - enum QueryResult { - None = 0x0, - Add = 0x1, - Recurse = 0x2 - }; - unsigned none() const { return None; }; - unsigned add() const { return Add; }; - unsigned recurse() const { return Recurse; }; - Cursors query(const std::function callback, int depth = INT_MAX) const - { - Cursors ret; - if (data) { - const unsigned result = callback(*this); - if (result & Add) - ret.append(*this); - if (result & Recurse && depth > 0) { - for (Data *childData : data->children) { - const Cursor child = { childData->shared_from_this() }; - ret.append(child.query(callback, depth - 1)); - } - } - } - return ret; - } - - bool isBitField() const { return intProperty(&clang_Cursor_isBitField); } - bool isVirtualBase() const { return intProperty(&clang_isVirtualBase); } - bool isStatic() const { return intProperty(&clang_CXXMethod_isStatic); } - bool isVirtual() const { return intProperty(&clang_CXXMethod_isVirtual); } - bool isPureVirtual() const - { -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20) - return intProperty(&clang_CXXMethod_isPureVirtual); -#else - return false; -#endif - } - bool isConst() const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 20) - return intProperty(&clang_CXXMethod_isConst); -#else - return false; -#endif - } - bool isDefinition() const { return intProperty(&clang_isCursorDefinition); } - bool isDynamicCall() const { return intProperty(&clang_Cursor_isDynamicCall); } - - template std::string stringProperty(Func func) const { return data ? toString(func(data->cursor)) : std::string(); } - template Ret intProperty(Type (*func)(CXCursor), Type defaultValue = Type()) const { return data ? func(data->cursor) : defaultValue; } - template Cursor cursorProperty(Func func) const { return data ? data->ast->create(func(data->cursor)) : Cursor(); } - template CursorType cursorTypeProperty(Func func) const { return data ? CursorType(data->ast, func(data->cursor)) : CursorType(); } - - std::shared_ptr data; - }; - - struct Cursors : public List - { - int size() const { return List::size(); } - Cursor at(int idx) const { return value(idx); } - }; - - struct CursorType { - CursorType(const AST *a, const CXType &t) : ast(a), type(t) {} - CursorType(const AST *a = 0) : ast(a) { memset(&type, 0, sizeof(type)); } - - std::string spelling() const { return toString(clang_getTypeSpelling(type)); } - Cursor declaration() const { return ast ? ast->create(clang_getTypeDeclaration(type)) : Cursor(); } - std::string callingConvention() const { return toString(clang_getFunctionTypeCallingConv(type)); } - std::string referenceType() const - { -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20) - return toString(clang_Type_getCXXRefQualifier(type)); -#else - return std::string(); -#endif - } - unsigned argumentCount() const { return clang_getNumArgTypes(type); } - CursorType argument(unsigned idx) const { return CursorType(ast, clang_getArgType(type, idx)); } - unsigned templateArgumentCount() const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 20) - return clang_Type_getNumTemplateArguments(type); -#else - return 0; -#endif - } - CursorType templateArgument(unsigned idx) const - { -#if CINDEX_VERSION > CINDEX_VERSION_ENCODE(0, 20) - return CursorType(ast, clang_Type_getTemplateArgumentAsType(type, idx)); -#else - (void)idx; - return CursorType(); -#endif - } - CursorType canonicalType() const { return CursorType(ast, clang_getCanonicalType(type)); } - CursorType pointeeType() const { return CursorType(ast, clang_getPointeeType(type)); } - CursorType resultType() const { return CursorType(ast, clang_getResultType(type)); } - CursorType elementType() const { return CursorType(ast, clang_getElementType(type)); } - CursorType arrayElementType() const { return CursorType(ast, clang_getElementType(type)); } - CursorType classType() const - { -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20) - return CursorType(ast, clang_Type_getClassType(type)); -#else - return CursorType(); -#endif - } - - bool isConstQualified() const { return clang_isConstQualifiedType(type); } - bool isEstrictQualified() const { return clang_isRestrictQualifiedType(type); } - bool isVolatileQualified() const { return clang_isVolatileQualifiedType(type); } - bool isVariadic() const { return clang_isFunctionTypeVariadic(type); } - bool isPod() const { return clang_isPODType(type); } - long long numElements() const { return clang_getNumElements(type); } - long long arraySize() const { return clang_getArraySize(type); } - long long alignOf() const { return clang_Type_getAlignOf(type); } - long long sizeOf() const { return clang_Type_getSizeOf(type); } - - const AST *ast; - CXType type; - }; - - struct Diagnostic { - - - }; - - struct SkippedRange { - - - }; - - static std::shared_ptr create(const Source &source, const String &sourceCode, CXTranslationUnit unit); - List evaluate(const String &script); - Cursor *root() const { return mRoot; } - List diagnostics() const; - List skippedRanges() const; - static SourceLocation createLocation(const CXCursor &cursor) { return createLocation(clang_getCursorLocation(cursor)); } - static SourceLocation createLocation(const CXSourceLocation &location) - { - SourceLocation loc; - loc.location = RTags::createLocation(location, &loc.offset); - return loc; - } - - Cursor create(const CXCursor &cursor) const - { - if (clang_isInvalid(clang_getCursorKind(cursor))) - return Cursor(); - - auto match = [&cursor](const Cursors &cursors) -> Cursor { - for (const Cursor &c : cursors) { - assert(c.data); - if (clang_equalCursors(c.data->cursor, cursor)) { - return c; - } - } - // The explicit const cast is here to satisfy travis clang matrix. - // clang 3.4 does not allow to use two different return types - return Cursor(); - }; - - const std::string usr = toString(clang_getCursorUSR(cursor)); - if (!usr.empty()) { - auto it = mByUsr.find(usr); - if (it != mByUsr.end()) { - const Cursor ret = match(it->second); - if (ret.data) - return ret; - } - } - - const SourceLocation loc = createLocation(cursor); - if (!loc.isNull()) { - auto it = mByLocation.find(loc); - if (it != mByLocation.end()) { - const Cursor ret = match(it->second); - if (ret.data) - return ret; - } - } - return construct(cursor, 0, loc, usr); - } -private: - static CXChildVisitResult visitor(CXCursor cursor, CXCursor, CXClientData u); - Cursor construct(const CXCursor &cursor, - Cursor::Data *parent = 0, - SourceLocation loc = SourceLocation(), - std::string usr = std::string()) const - { - Cursor ret; - if (loc.isNull()) - loc = createLocation(cursor); - if (usr.empty()) - usr = toString(clang_getCursorUSR(cursor)); - ret.data.reset(new Cursor::Data(const_cast(this), parent, cursor, loc, usr)); - if (!loc.isNull()) - mByLocation[loc].append(ret); - if (!ret.data->usr.empty()) - mByUsr[usr].append(ret); - if (parent) - parent->children.append(ret.data.get()); - return ret; - } - AST() - : mRoot(0) - {} - mutable Hash mByUsr; - mutable Map mByLocation; - String mSourceCode; - List mReturnValues; - Cursor *mRoot; - std::shared_ptr mState; -}; - - -inline AST::Cursors AST::Cursor::children() const -{ - Cursors ret; - if (data) { - ret.resize(data->children.size()); - int i = 0; - for (Data *child : data->children) { - ret[i++] = Cursor { child->shared_from_this() }; - } - } - return ret; -} - -inline AST::Cursors AST::Cursor::arguments() const -{ - AST::Cursors ret; - if (data) { - List args; - const unsigned size = RTags::cursorArguments(data->cursor, &args); - if (size) { - ret.resize(size); - for (unsigned i=0; iast->create(args[i]); - } - } - } - return ret; -} -#endif diff --git a/rtags/src/CMakeLists.txt b/rtags/src/CMakeLists.txt deleted file mode 100644 index 2ee7f4d..0000000 --- a/rtags/src/CMakeLists.txt +++ /dev/null @@ -1,364 +0,0 @@ -set(CMAKE_SKIP_BUILD_RPATH FALSE) -set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) - -include(ExternalProject) - -if (RTAGS_BUILD_CLANG) - set(LIBCLANG_VERSION_STRING "5.0.0") - if (RTAGS_NO_INSTALL) - set(CLANG_INSTALL_PATH ${CMAKE_CURRENT_BINARY_DIR}/llvmclang-prefix/install) - else () - set(CLANG_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/rtags-llvmclang) - endif () - ExternalProject_Add(llvmclang - DOWNLOAD_COMMAND ${PROJECT_SOURCE_DIR}/scripts/getclang.sh "${LIBCLANG_VERSION_STRING}" - SOURCE_DIR llvmclang-prefix/src/llvm - CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${CLANG_INSTALL_PATH} -DLLVM_BUILD_TOOLS=1 - LOG_DOWNLOAD 1 # Wrap download in script to log output - LOG_UPDATE 1 # Wrap update in script to log output - LOG_CONFIGURE 1 # Wrap configure in script to log output - LOG_BUILD 1 # Wrap build in script to log output - LOG_TEST 1 # Wrap test in script to log output - LOG_INSTALL 1 # Wrap install in script to log output - ) - if (CMAKE_SYSTEM_NAME MATCHES "Darwin") - set(CLANG_LIBRARY_NAME "libclang.dylib") - add_definitions("-DCLANG_INCLUDE=${CLANG_INSTALL_PATH}/include/c++/v1") # add libcxx include - else () - set(CLANG_LIBRARY_NAME "libclang.so") - endif () - set(LIBCLANG_LIBRARIES ${CLANG_INSTALL_PATH}/lib/${CLANG_LIBRARY_NAME}) - set(LIBCLANG_LIBDIR ${CLANG_INSTALL_PATH}/lib) - set(LIBCLANG_CXXFLAGS "-I${CLANG_INSTALL_PATH}/include") -endif () - - -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/RTagsVersion.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/RTagsVersion.h") - -# Treat MSYS as Cygwin -if (MSYS) - set(CYGWIN 1) - set(CMAKE_SYSTEM_NAME "CYGWIN") -endif () - -# Set RPATH when installing to a custom (non-system) directory -list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) -if ("${isSystemDir}" STREQUAL "-1") - list(APPEND CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib) -endif () - -include(${CMAKE_SOURCE_DIR}/cmake/EnsureLibraries.cmake) - -if (NOT DEFINED LIBCLANG_LIBRARIES) - set(LIBCLANG_LIBRARIES $ENV{LIBCLANG_LIBRARIES}) -endif () - -if (NOT DEFINED LIBCLANG_CXXFLAGS) - set(LIBCLANG_CXXFLAGS $ENV{LIBCLANG_CXXFLAGS}) -endif () - -if (NOT DEFINED LIBCLANG_LIBDIR) - set(LIBCLANG_LIBDIR $ENV{LIBCLANG_LIBDIR}) -endif() - -if (NOT DEFINED LIBCLANG_LIBRARIES OR NOT DEFINED LIBCLANG_CXXFLAGS OR NOT DEFINED LIBCLANG_LIBDIR) - find_package(LibClang REQUIRED) -endif () -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS}") - -if (NOT RTAGS_BUILD_CLANG) - set(LIBCLANG_COMPILE_TEST " -#include - -int main() -{ - CXIndex index = clang_createIndex(0, true); - CXTranslationUnit unit = clang_parseTranslationUnit(index, 0, 0, 0, 0, 0, 0); - clang_disposeTranslationUnit(unit); - clang_disposeIndex(index); - return 0; -} -") - include(CheckCXXSourceCompiles) - set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS}) - set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${LIBCLANG_LIBRARIES}) - check_cxx_source_compiles("${LIBCLANG_COMPILE_TEST}" LIBCLANG_COMPILES) - if (NOT LIBCLANG_COMPILES) - message(FATAL_ERROR "Failed to compile small clang test app.\nIt's likely that the include file could not be found!\nMaybe you need to install the clang development package?\nSee CMakeFiles/CMakeError.log for more info.") - endif () - unset(CMAKE_REQUIRED_FLAGS) - unset(CMAKE_REQUIRED_LIBRARIES) - unset(LIBCLANG_COMPILES) -endif () - -set(CXX_11_EXTENDED_REGEX_TEST " -#include - -int main() -{ - try { - std::regex rx(\"^(.*):([0-9]+):([0-9]+):?-:?([0-9]+):([0-9]+):?(@[A-Za-z,]+)?\", std::regex_constants::extended); - } catch (std::regex_error& e) { - return -1; - } - - return 0; -} -") -include(CheckCXXSourceRuns) -set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-std=c++11" ${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS}) -check_cxx_source_runs("${CXX_11_EXTENDED_REGEX_TEST}" CXX_11_EXTENDED_REGEX_SUPPORT) -if (NOT CXX_11_EXTENDED_REGEX_SUPPORT) - message(FATAL_ERROR "Compiler with complete C++11 support required ( >= GCC 4.9 or >= Clang 3.3)") -endif () -unset(CMAKE_REQUIRED_FLAGS) -unset(CMAKE_REQUIRED_LIBRARIES) -unset(CXX_11_EXTENDED_REGEX_SUPPORT) - -if (EXISTS ${CLANG_COMPILATION_INCLUDE}) - add_definitions(-DHAVE_CXCOMPILATIONDATABASE) -endif () - -if (LUA_ENABLED) - ExternalProject_Add(lua - DOWNLOAD_COMMAND "" - SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/lua - INSTALL_COMMAND "" - CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=0 -DCMAKE_GENERATOR=${CMAKE_GENERATOR}) -endif () - -set(RCT_RTTI_ENABLED 1) -set(RCT_NO_INSTALL 1) -set(RCT_NO_LIBRARY 1) -# Everyting which as been set either in rct/rct.cmake or rct/compiler.cmake -# doesn't need to be set in this file again. -include(rct/rct.cmake) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wstrict-aliasing=2 -Wcast-qual -fPIC") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-aliasing=2 -Wcast-qual -fPIC") -if (NOT CYGWIN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-all -Wstack-protector") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all -Wstack-protector") -endif () - -if (CMAKE_BUILD_TYPE MATCHES "Debug") - add_compile_options("-Og") - add_definitions("-DRTAGS_DEBUG") - set(RCT_EVENTLOOP_CALLBACK_TIME_THRESHOLD 2000) -endif () - -add_definitions( - "-DRTAGS_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}" - "-DCLANG_LIBDIR=${LIBCLANG_LIBDIR}" - "-DCLANG_VERSION=${LIBCLANG_VERSION_STRING}" - "-DOS_${CMAKE_SYSTEM_NAME}" - ${RCT_DEFINITIONS}) - -if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - add_definitions(-D__LONG_LONG_SUPPORTED) -endif () - -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) - -set(RTAGS_SOURCES - ClangIndexer.cpp - ClangThread.cpp - ClassHierarchyJob.cpp - CompilerManager.cpp - CompletionThread.cpp - DependenciesJob.cpp - FileManager.cpp - FindFileJob.cpp - FindSymbolsJob.cpp - FollowLocationJob.cpp - IncludeFileJob.cpp - IndexMessage.cpp - IndexParseData.cpp - IndexerJob.cpp - JobScheduler.cpp - ListSymbolsJob.cpp - Location.cpp - Preprocessor.cpp - ProcThread.cpp - Project.cpp - QueryJob.cpp - QueryMessage.cpp - RClient.cpp - RTags.cpp - ReferencesJob.cpp - Sandbox.cpp - ScanThread.cpp - Server.cpp - Source.cpp - StatusJob.cpp - Symbol.cpp - Symbol.cpp - SymbolInfoJob.cpp - Token.cpp - TokensJob.cpp - ${RCT_SOURCES}) - -if (LUA_ENABLED) - list(APPEND RTAGS_SOURCES AST.cpp) -endif () - -add_library(rtags STATIC ${RTAGS_SOURCES}) -if (RTAGS_BUILD_CLANG) - add_dependencies(rtags llvmclang) -endif () -if (LUA_ENABLED) - add_dependencies(rtags lua) -endif () - -if (RTAGS_COTIRE) - include(cotire) - set_target_properties(rtags PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) - cotire(rtags) -endif () - -include_directories( - ${CMAKE_CURRENT_LIST_DIR} - ${RCT_INCLUDE_DIRS} - ${CMAKE_CURRENT_LIST_DIR}/selene/include - ${CMAKE_CURRENT_BINARY_DIR}/lua-prefix/src/lua-build - ${CMAKE_CURRENT_LIST_DIR}/lua/src) - -if (CMAKE_SYSTEM_NAME MATCHES "Darwin") - set(START_GROUP "") - set(END_GROUP "") -else () - set(START_GROUP "-Wl,--start-group") - set(END_GROUP "-Wl,--end-group") -endif () - -set(RTAGS_LIBRARIES rtags ${START_GROUP} ${LIBCLANG_LIBRARIES} ${END_GROUP}) -if (LUA_ENABLED) - list(APPEND RTAGS_LIBRARIES -L${CMAKE_CURRENT_BINARY_DIR}/lua-prefix/src/lua-build/ liblua.a) - add_definitions(-DRTAGS_HAS_LUA) -endif () - -if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set_source_files_properties(AST.cpp PROPERTIES - COMPILE_FLAGS "-Wno-unused-parameter -Wno-unused-variable -ftemplate-depth=2000 -Wno-cast-qual -Wno-shadow") -else () - set_source_files_properties(AST.cpp PROPERTIES - COMPILE_FLAGS "-Wno-unused-but-set-parameter -Wno-unused-parameter -Wno-unused-variable -ftemplate-depth=2000 -Wno-cast-qual -Wno-shadow") -endif() - -# RCT_LIBRARIES and stdc++ library must be at the end -set(RTAGS_LIBRARIES ${RTAGS_LIBRARIES} -lstdc++ ${RCT_LIBRARIES}) -add_executable(rc rc.cpp) -target_link_libraries(rc ${RTAGS_LIBRARIES}) - -add_executable(rdm rdm.cpp) -target_link_libraries(rdm ${RTAGS_LIBRARIES}) - -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) - -add_executable(rp rp.cpp) -target_link_libraries(rp ${RTAGS_LIBRARIES}) - -if (CYGWIN) - EnsureLibraries(rdm rct) -endif () - -if (EMACS) - set(EMACS_EXECUTABLE ${EMACS}) -else () - find_program(EMACS_EXECUTABLE emacs) -endif () - -if (EMACS_EXECUTABLE) - execute_process(COMMAND ${EMACS_EXECUTABLE} --version - RESULT_VARIABLE EMACS_ERROR - OUTPUT_VARIABLE EMACS_VERSION_INFORMATION - ERROR_QUIET) - if (NOT EMACS_ERROR) - string(REGEX MATCH "[0-9]+(\\.[0-9]+)*" EMACS_VERSION ${EMACS_VERSION_INFORMATION}) - if ("${EMACS_VERSION}" LESS "24.3") - message(WARNING "Installed emacs version is to old, elisp files are not going to be installed, minimum required version is >=24.3!") - set(RTAGS_NO_ELISP_FILES TRUE) - else() - message(STATUS "Found emacs version ${EMACS_VERSION}") - endif () - else () - message(STATUS "Could not get emacs version (\"emacs --version\"), elisp files are not going to be installed") - set(RTAGS_NO_ELISP_FILES TRUE) - endif () -else () - set(RTAGS_NO_ELISP_FILES TRUE) - message(STATUS "Emacs was not found, elisp files are not going to be installed!") -endif () - -set(RTAGS_ELISP_FILES - rtags.el - ac-rtags.el - helm-rtags.el - ivy-rtags.el - company-rtags.el - flycheck-rtags.el) - -if (LUA_ENABLED AND NOT RTAGS_NO_LUA_FILES AND LUA_FOUND AND NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rtags.lua - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/rtags.lua ${CMAKE_CURRENT_BINARY_DIR}/rtags.lua - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/rtags.lua - COMMENT "Copying ${CMAKE_CURRENT_SOURCE_DIR}/rtags.lua -> ${CMAKE_CURRENT_BINARY_DIR}/rtags.lua") -endif () - -if (NOT RTAGS_NO_ELISP_FILES) - if (NOT RTAGS_ELISP_INSTALL_LOCATION) - set(RTAGS_ELISP_INSTALL_LOCATION ${CMAKE_INSTALL_PREFIX}/share/emacs/site-lisp/rtags/) - endif () - set(RTAGS_ELISP_SOURCES "") - foreach(el ${RTAGS_ELISP_FILES}) - if (NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${el} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${el} ${CMAKE_CURRENT_BINARY_DIR}/${el} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${el} - COMMENT "Copying ${CMAKE_CURRENT_SOURCE_DIR}/${el} -> ${CMAKE_CURRENT_BINARY_DIR}/${el}") - endif () - list(APPEND RTAGS_ELISP_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${el}) - if (NOT RTAGS_NO_ELISP_BYTECOMPILE) - list(APPEND RTAGS_ELISP_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${el}c) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${el}c - COMMAND ${EMACS_EXECUTABLE} -batch -l ${CMAKE_CURRENT_SOURCE_DIR}/compile-shim.elisp -l ${CMAKE_CURRENT_SOURCE_DIR}/rtags.el -f batch-byte-compile - ${CMAKE_CURRENT_BINARY_DIR}/${el} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${el} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Creating byte-compiled Emacs lisp ${CMAKE_CURRENT_BINARY_DIR}/${el}c") - add_custom_target(emacs_byte_compile_${el} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${el}c) - endif () - endforeach() -endif () - -install(CODE "message(\"Installing rtags...\")") -include(BashCompletion) -if (BASH_COMPLETION_FOUND) - file (MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/completions") - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink rtags rc - COMMAND ${CMAKE_COMMAND} -E create_symlink rtags rdm - WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/completions") - install(FILES rtags-bash-completion.bash DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR} - PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ - RENAME rtags) - install(FILES "${PROJECT_BINARY_DIR}/completions/rc" "${PROJECT_BINARY_DIR}/completions/rdm" - DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR}) -endif () -install(TARGETS rdm rc rp RUNTIME DESTINATION bin COMPONENT rtags) -install(FILES ../bin/gcc-rtags-wrapper.sh DESTINATION bin - PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) -install(FILES ../man/man7/rc.7 ../man/man7/rdm.7 DESTINATION share/man/man7/) - -if (UNIX AND NOT ${SKIP_CTEST}) - install(CODE "execute_process(COMMAND ctest)") -endif () - -if (NOT RTAGS_NO_ELISP_FILES) - install(FILES ${RTAGS_ELISP_SOURCES} DESTINATION ${RTAGS_ELISP_INSTALL_LOCATION}) -endif () - -if (CLANGTEST_ENABLED) - add_executable(clangtest clangtest.cpp) - target_link_libraries(clangtest ${LIBCLANG_LIBRARIES}) -endif () diff --git a/rtags/src/ClangIndexer.cpp b/rtags/src/ClangIndexer.cpp deleted file mode 100644 index 7cbab3d..0000000 --- a/rtags/src/ClangIndexer.cpp +++ /dev/null @@ -1,2413 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#define RTAGS_SINGLE_THREAD -#include "ClangIndexer.h" - -#include -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 25) -#include -#endif - -#include "Diagnostic.h" -#include "FileMap.h" -#include "QueryMessage.h" -#include "RClient.h" -#include "rct/Connection.h" -#include "rct/EventLoop.h" -#include "rct/SHA256.h" -#include "RTags.h" -#include "RTagsVersion.h" -#include "VisitFileMessage.h" -#include "VisitFileResponseMessage.h" -#include "Location.h" - -static inline String usr(const CXCursor &cursor) -{ - return RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(cursor))); -} - -static inline void setType(Symbol &symbol, const CXType &type) -{ - symbol.type = type.kind; - symbol.typeName = RTags::eatString(clang_getTypeSpelling(type)); - const CXType canonical = clang_getCanonicalType(type); - if (!clang_equalTypes(type, canonical) -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 32) - && (symbol.typeName == "auto" || type.kind != CXType_Auto) -#endif - ) { - symbol.typeName += " => " + RTags::eatString(clang_getTypeSpelling(canonical)); - } -} - -static inline void setRange(Symbol &symbol, const CXSourceRange &range, uint16_t *length = 0) -{ - CXSourceLocation rangeStart = clang_getRangeStart(range); - CXSourceLocation rangeEnd = clang_getRangeEnd(range); - unsigned int startLine, startColumn, endLine, endColumn, startOffset, endOffset; - clang_getSpellingLocation(rangeStart, 0, &startLine, &startColumn, &startOffset); - clang_getSpellingLocation(rangeEnd, 0, &endLine, &endColumn, &endOffset); - symbol.startLine = startLine; - symbol.endLine = endLine; - symbol.startColumn = startColumn; - symbol.endColumn = endColumn; - if (length) - *length = static_cast(endOffset - startOffset); -} - -struct VerboseVisitorUserData { - int indent; - String out; - ClangIndexer *indexer; -}; - -Flags ClangIndexer::sServerOpts; -Path ClangIndexer::sServerSandboxRoot; -ClangIndexer::ClangIndexer() - : mCurrentTranslationUnit(String::npos), mLastCursor(clang_getNullCursor()), - mLastCallExprSymbol(0), mVisitFileResponseMessageFileId(0), - mVisitFileResponseMessageVisit(0), mParseDuration(0), mVisitDuration(0), mBlocked(0), - mAllowed(0), mIndexed(1), mVisitFileTimeout(0), mIndexDataMessageTimeout(0), - mFileIdsQueried(0), mFileIdsQueriedTime(0), mCursorsVisited(0), mLogFile(0), - mConnection(Connection::create(RClient::NumOptions)), mUnionRecursion(false), - mInTemplateFunction(0) -{ - mConnection->newMessage().connect(std::bind(&ClangIndexer::onMessage, this, - std::placeholders::_1, std::placeholders::_2)); -} - -ClangIndexer::~ClangIndexer() -{ - if (mLogFile) - fclose(mLogFile); -} - -bool ClangIndexer::exec(const String &data) -{ - Deserializer deserializer(data); - uint16_t protocolVersion; - deserializer >> protocolVersion; - if (protocolVersion != RTags::DatabaseVersion) { - error("Wrong protocol %d vs %d", protocolVersion, RTags::DatabaseVersion); - return false; - } - uint64_t id; - String socketFile; - Flags indexerJobFlags; - uint32_t connectTimeout, connectAttempts; - int32_t niceValue; - Hash blockedFiles; - - deserializer >> sServerSandboxRoot; - deserializer >> id; - deserializer >> socketFile; - deserializer >> mProject; - uint32_t count; - deserializer >> count; - mSources.resize(count); - for (uint32_t i=0; i> mSourceFile; - deserializer >> indexerJobFlags; - deserializer >> mVisitFileTimeout; - deserializer >> mIndexDataMessageTimeout; - deserializer >> connectTimeout; - deserializer >> connectAttempts; - deserializer >> niceValue; - deserializer >> sServerOpts; - deserializer >> mUnsavedFiles; - deserializer >> mDataDir; - deserializer >> mDebugLocations; - deserializer >> blockedFiles; - - if (sServerOpts & Server::NoRealPath) { - Path::setRealPathEnabled(false); - } - -#if 0 - while (true) { - FILE *f = fopen((String("/tmp/stop_") + mSourceFile.fileName()).constData(), "r+"); - if (f) { - fseek(f, 0, SEEK_END); - fprintf(f, "Waiting ... %d\n", getpid()); - fclose(f); - sleep(1); - } else { - break; - } - } -#endif - - const uint64_t parseTime = Rct::currentTimeMs(); - - if (niceValue != INT_MIN) { - errno = 0; - if (nice(niceValue) == -1) { - error() << "Failed to nice rp" << Rct::strerror(); - } - } - - if (mSourceFile.isEmpty()) { - error("No sourcefile"); - return false; - } - - switch (mSources.size()) { - case 0: - error("No sourcefile"); - return false; - case 1: - if (!mSources.front().fileId) { - error("Bad fileId"); - return false; - } - break; - default: - for (size_t i=1; iconnectUnix(socketFile, connectTimeout)) - break; - if (!--connectAttempts) { - error("Failed to connect to rdm on %s (%dms timeout)", socketFile.constData(), connectTimeout); - return false; - } - usleep(500 * 1000); - } - // mLogFile = fopen(String::format("/tmp/%s", mSourceFile.fileName()).constData(), "w"); - mIndexDataMessage.setProject(mProject); - mIndexDataMessage.setIndexerJobFlags(indexerJobFlags); - mIndexDataMessage.setParseTime(parseTime); - mIndexDataMessage.setId(id); - - assert(mConnection->isConnected()); - assert(mSources.front().fileId); - mIndexDataMessage.files()[mSources.front().fileId] |= IndexDataMessage::Visited; - parse() && visit() && diagnose(); - String message = mSourceFile.toTilde(); - String err; - - StopWatch sw; - int writeDuration = -1; - bool hasUnit = false; - for (const auto &u : mTranslationUnits) { - if (u->unit) { - hasUnit = true; - break; - } - } - if (!hasUnit || !writeFiles(RTags::encodeSourceFilePath(mDataDir, mProject, 0), err)) { - message += " error"; - if (!err.isEmpty()) - message += (' ' + err); - } else { - writeDuration = sw.elapsed(); - } - message += String::format<16>(" in %lldms. ", mTimer.elapsed()); - if (mSources.size() > 1) { - message += String::format("(%zu builds) ", mSources.size()); - } - int cursorCount = 0; - int symbolNameCount = 0; - for (const auto &unit : mUnits) { - cursorCount += unit.second->symbols.size(); - symbolNameCount += unit.second->symbolNames.size(); - } - if (hasUnit) { - String queryData; - if (mFileIdsQueried) - queryData = String::format(", %d queried %dms", mFileIdsQueried, mFileIdsQueriedTime); - const char *format = "(%d syms, %d symNames, %d includes, %d of %d files, symbols: %d of %d, %d cursors, %zu bytes written%s%s) (%d/%d/%dms)"; - message += String::format<1024>(format, cursorCount, symbolNameCount, - mIndexDataMessage.includes().size(), mIndexed, - mIndexDataMessage.files().size(), mAllowed, - mAllowed + mBlocked, mCursorsVisited, - mIndexDataMessage.bytesWritten(), - queryData.constData(), mIndexDataMessage.flags() & IndexDataMessage::UsedPCH ? ", pch" : "", - mParseDuration, mVisitDuration, writeDuration); - } - if (mIndexDataMessage.indexerJobFlags() & IndexerJob::Dirty) { - message += " (dirty)"; - } else if (mIndexDataMessage.indexerJobFlags() & IndexerJob::Reindex) { - message += " (reindex)"; - } - - - mIndexDataMessage.setMessage(message); - sw.restart(); - if (!mConnection->send(mIndexDataMessage)) { - error() << "Couldn't send IndexDataMessage" << mSourceFile; - return false; - } - mConnection->finished().connect(std::bind(&EventLoop::quit, EventLoop::eventLoop())); - if (EventLoop::eventLoop()->exec(mIndexDataMessageTimeout) == EventLoop::Timeout) { - error() << "Timed out sending IndexDataMessage" << mSourceFile; - return false; - } - if (getenv("RDM_DEBUG_INDEXERMESSAGE")) - error() << "Send took" << sw.elapsed() << "for" << mSourceFile; - - if (mSerializeTU) { - Path path = mDataDir + "tucache/"; - Path::mkdir(path, Path::Recursive); - path << mSources.front().fileId; - Path tmp = path; - tmp << ".tmp"; - StopWatch sw2; - clang_saveTranslationUnit(mSerializeTU->unit, tmp.constData(), clang_defaultSaveOptions(mSerializeTU->unit)); - rename(tmp.constData(), path.constData()); - error() << "SAVED CACHED FILE FOR" << mSourceFile << path << sw2.elapsed(); - } - return true; -} - -void ClangIndexer::onMessage(const std::shared_ptr &msg, const std::shared_ptr &/*conn*/) -{ - assert(msg->messageId() == VisitFileResponseMessage::MessageId); - const std::shared_ptr vm = std::static_pointer_cast(msg); - mVisitFileResponseMessageVisit = vm->visit(); - mVisitFileResponseMessageFileId = vm->fileId(); - assert(EventLoop::eventLoop()); - EventLoop::eventLoop()->quit(); -} - -Location ClangIndexer::createLocation(const Path &sourceFile, unsigned int line, unsigned int col, bool *blockedPtr) -{ - uint32_t id = Location::fileId(sourceFile); - Path resolved; - if (!id) { - bool ok; - for (int i=0; i<4; ++i) { - resolved = sourceFile.resolved(Path::RealPath, Path(), &ok); - // if ok is false it means the file is gone, in case this happens - // during a git pull or something we'll give it a couple of chances. - if (ok) - break; - usleep(50000); - } - if (!ok) - return Location(); - id = Location::fileId(resolved); - if (id) - Location::set(sourceFile, id); - } - assert(!resolved.contains("/../")); - - if (id) { - if (blockedPtr) { - Hash >::iterator it = mIndexDataMessage.files().find(id); - if (it == mIndexDataMessage.files().end()) { - // the only reason we already have an id for a file that isn't - // in the mIndexDataMessage.mFiles is that it's blocked from the outset. - // The assumption is that we never will go and fetch a file id - // for a location without passing blockedPtr since any reference - // to a symbol in another file should have been preceded by that - // header in which case we would have to make a decision on - // whether or not to index it. This is a little hairy but we - // have to try to optimize this process. -#ifndef NDEBUG - if (resolved.isEmpty()) - resolved = sourceFile.resolved(); -#endif - assert(id); - mIndexDataMessage.files()[id] = IndexDataMessage::NoFileFlag; - *blockedPtr = true; - } else if (!it->second) { - *blockedPtr = true; - } - } - return Location(id, line, col); - } - - ++mFileIdsQueried; - VisitFileMessage msg(resolved, mProject, mSources.front().fileId); - - mVisitFileResponseMessageFileId = UINT_MAX; - mVisitFileResponseMessageVisit = false; - mConnection->send(msg); - StopWatch sw; - EventLoop::eventLoop()->exec(mVisitFileTimeout); - const int elapsed = sw.elapsed(); - mFileIdsQueriedTime += elapsed; - switch (mVisitFileResponseMessageFileId) { - case 0: - return Location(); - case UINT_MAX: - // timed out. - if (mVisitFileResponseMessageFileId == UINT_MAX) { - error() << "Error getting fileId for" << resolved << mLastCursor - << elapsed << mVisitFileTimeout; - } - exit(1); - default: - id = mVisitFileResponseMessageFileId; - break; - } - assert(id); - Flags &flags = mIndexDataMessage.files()[id]; - if (mVisitFileResponseMessageVisit) { - flags |= IndexDataMessage::Visited; - ++mIndexed; - } - // fprintf(mLogFile, "%s %s\n", file.second ? "WON" : "LOST", resolved.constData()); - - Location::set(resolved, id); - if (resolved != sourceFile) - Location::set(sourceFile, id); - - if (blockedPtr) - *blockedPtr = !mVisitFileResponseMessageVisit; - return Location(id, line, col); -} - -CXTranslationUnit ClangIndexer::unit(size_t u) const -{ - return mTranslationUnits[u]->unit; -} - -static inline void tokenize(const char *buf, int start, - int *templateStart, int *templateEnd, - int *sectionCount, int sections[1024]) -{ - int templateCount = 0; - *templateStart = *templateEnd = -1; - *sectionCount = 1; - sections[0] = start; - int functionStart = -1; - int functionEnd = -1; - - int idx = start; - while (true) { - switch (buf[++idx]) { - case '<': - if (buf[idx + 1] == '<') { - ++idx; - } else if (functionStart == -1 && (idx - 8 < 0 || strncmp("operator", buf + idx - 8, 8) != 0)) { - if (!templateCount++) - *templateStart = idx; - } - break; - case '>': - if (buf[idx + 1] == '>') { - ++idx; - } else if (functionStart == -1 && (idx - 8 < 0 || strncmp("operator", buf + idx - 8, 8) != 0)) { - if (!--templateCount) - *templateEnd = idx; - } - break; - case '(': - if (!templateCount) - functionStart = idx; - break; - case ')': - if (!templateCount) - functionEnd = idx; - break; - case ':': - if (!templateCount && (functionStart == -1 || functionEnd != -1) && buf[idx + 1] == ':' && (*sectionCount) < 1024) { - sections[(*sectionCount)++] = idx + 2; - ++idx; - } - break; - case '\0': - if (templateCount) { - *templateStart = *templateEnd = -1; - } - return; - } - } -} - -String ClangIndexer::addNamePermutations(const CXCursor &cursor, Location location, RTags::CursorType cursorType) -{ - CXCursorKind kind = clang_getCursorKind(cursor); - const CXCursorKind originalKind = kind; - char buf[1024 * 512]; - int pos = sizeof(buf) - 1; - buf[pos] = '\0'; - int cutoff = -1; - - CXCursor c = cursor; - do { - CXStringScope displayName(clang_getCursorDisplayName(c)); - const char *name = displayName.data(); - if (!name) - break; - const int len = strlen(name); - if (!len) - break; - - if (pos != sizeof(buf) - 1) { - pos -= 2; - if (pos >= 0) - memset(buf + pos, ':', 2); - } - pos -= len; - if (pos < 0) { - error("SymbolName too long. Giving up"); - return String(); - } - memcpy(buf + pos, name, len); - - c = clang_getCursorSemanticParent(c); - kind = clang_getCursorKind(c); - if (cutoff == -1) { - switch (kind) { - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: - case CXCursor_StructDecl: - break; - case CXCursor_Namespace: - // namespaces can include all namespaces in their symbolname - if (originalKind == CXCursor_Namespace) - break; - RCT_FALL_THROUGH; - default: - cutoff = pos; - break; - } - } - } while (RTags::needsQualifiers(kind)); - - if (static_cast(pos) == sizeof(buf) - 1) { - return String(); - } - String type; - String trailer; - switch (originalKind) { - case CXCursor_StructDecl: - type = "struct "; - break; - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: - type = "class "; - break; - case CXCursor_Namespace: - type = "namespace "; - break; - case CXCursor_Destructor: - case CXCursor_Constructor: - break; - default: { - type = RTags::eatString(clang_getTypeSpelling(clang_getCanonicalType(clang_getCursorType(cursor)))); - if (originalKind == CXCursor_FunctionDecl || originalKind == CXCursor_CXXMethod || originalKind == CXCursor_FunctionTemplate) { - const size_t idx = type.indexOf(" -> "); - if (idx != String::npos) - trailer = type.mid(idx); - } - const size_t paren = type.indexOf('('); - if (paren != String::npos) { - type.resize(paren); - } else if (!type.isEmpty() && !type.endsWith('*') && !type.endsWith('&')) { - type.append(' '); - } - break; } - } - - if (cutoff == -1) - cutoff = pos; - - String ret; - if (!type.isEmpty()) { - ret = type; - ret.append(buf + cutoff, std::max(0, sizeof(buf) - cutoff - 1)); - if (!trailer.isEmpty()) - ret += trailer; - if (cursorType != RTags::Type_Reference) { - unit(location.fileId())->symbolNames[ret].insert(location); - } - } else { - ret.assign(buf + cutoff, std::max(0, sizeof(buf) - cutoff - 1)); - } - if (cursorType == RTags::Type_Reference) { - return ret; - } - - int templateStart, templateEnd, colonColonCount; - int colonColons[1024]; - ::tokenize(buf, pos, - &templateStart, &templateEnd, - &colonColonCount, colonColons); - assert((templateStart != -1) == (templateEnd != -1)); - - // i == 0 --> with templates, - // i == 1 without templates or without EnumConstantDecl part - for (int i=0; i<2; ++i) { - for (int j=0; j(0, sizeof(buf) - (ch - buf) - 1)); - if (name.isEmpty()) - continue; - unit(location.fileId())->symbolNames[name].insert(location); - if (originalKind == CXCursor_ObjCClassMethodDecl) { - const size_t idx = name.indexOf(':'); - if (idx != String::npos && idx > 0) { - name.resize(idx); - unit(location.fileId())->symbolNames[name].insert(location); - } - } - if (!type.isEmpty() && (originalKind != CXCursor_ParmDecl || !strchr(ch, '('))) { - // We only want to add the type to the final declaration for ParmDecls - // e.g. - // void foo(int)::bar - // and - // int bar - // - // not - // int void foo(int)::bar - // or - // void foo(int)::int bar - - unit(location.fileId())->symbolNames[type + name].insert(location); - } - } - - if (i == 1 || (templateStart == -1 && originalKind != CXCursor_EnumConstantDecl)) { - // nothing more to do - break; - } - - if (originalKind == CXCursor_EnumConstantDecl) { // remove CXCursor_EnumDecl - // struct A { enum B { C } }; - // Will by default generate a A::B::C symbolname. - // This code removes the B:: part from it - if (colonColonCount > 2) { - const char *last = buf + colonColons[colonColonCount - 1]; - const char *secondLast = buf + colonColons[colonColonCount - 2]; - const int len = (last - secondLast); - memmove(buf + pos + len, buf + pos, secondLast - (buf + pos)); - pos += len; - } - } else { // remove templates - assert(templateStart != -1); - assert(templateEnd != -1); - const int templateSize = (templateEnd - templateStart) + 1; - memmove(buf + pos + templateSize, buf + pos, (buf + templateStart) - (buf + pos)); - pos += templateSize; - } - // ### We could/should just move the colon colon values but this - // should be pretty quick and I don't want to write the code to - // do it. - ::tokenize(buf, pos, - &templateStart, &templateEnd, - &colonColonCount, colonColons); - } - - return ret; -} - -static inline CXCursor findDestructorForDelete(const CXCursor &deleteStatement) -{ - const CXCursor child = RTags::findFirstChild(deleteStatement); - CXCursorKind kind = clang_getCursorKind(child); - switch (kind) { - case CXCursor_UnexposedExpr: - case CXCursor_CallExpr: - break; - default: - return clang_getNullCursor(); - } - - const CXCursor var = clang_getCursorReferenced(child); - kind = clang_getCursorKind(var); - switch (kind) { - case CXCursor_ObjCIvarDecl: - case CXCursor_VarDecl: - case CXCursor_FieldDecl: - case CXCursor_ParmDecl: - case CXCursor_CXXMethod: - case CXCursor_FunctionDecl: - case CXCursor_ConversionFunction: - break; - default: - if (!clang_isInvalid(kind)) { - error() << "Got unexpected cursor" << deleteStatement << var; - // assert(0); - } - return clang_getNullCursor(); - } - - CXCursor ref = RTags::findChild(var, CXCursor_TypeRef); - if (ref != CXCursor_TypeRef) - ref = RTags::findChild(var, CXCursor_TemplateRef); - kind = clang_getCursorKind(ref); - switch (kind) { - case CXCursor_TypeRef: - case CXCursor_TemplateRef: - break; - default: - return clang_getNullCursor(); - } - - const CXCursor referenced = clang_getCursorReferenced(ref); - kind = clang_getCursorKind(referenced); - switch (kind) { - case CXCursor_StructDecl: - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: - break; - default: - return clang_getNullCursor(); - } - const CXCursor destructor = RTags::findChild(referenced, CXCursor_Destructor); - return destructor; -} - -CXChildVisitResult ClangIndexer::visitorHelper(CXCursor cursor, CXCursor, CXClientData data) -{ - ClangIndexer *indexer = static_cast(data); - const CXChildVisitResult res = indexer->indexVisitor(cursor); - if (res == CXChildVisit_Recurse) - indexer->visit(cursor); - return CXChildVisit_Continue; -} - -CXChildVisitResult ClangIndexer::indexVisitor(CXCursor cursor) -{ - ++mCursorsVisited; - // error() << "indexVisitor" << cursor; - // FILE *f = fopen("/tmp/clangindex.log", "a"); - // String str; - // Log(&str) << cursor; - // fwrite(str.constData(), 1, str.size(), f); - // fwrite("\n", 1, 1, f); - // fclose(f); - - const CXCursorKind kind = clang_getCursorKind(cursor); - const RTags::CursorType type = RTags::cursorType(kind); - if (type == RTags::Type_Other) { - return CXChildVisit_Recurse; - } - - struct UpdateLastCursor { - ~UpdateLastCursor() { func(); } - std::function func; - } call = { [this, cursor]() { mLastCursor = cursor; } }; - - bool blocked = false; - - Location loc = createLocation(cursor, kind, &blocked); - if (blocked) { - ++mBlocked; - return CXChildVisit_Continue; - } else if (loc.isNull()) { - // error() << "Got null" << cursor; - return CXChildVisit_Recurse; - } - for (const String &debug : mDebugLocations) { - if (debug == "all" || debug == loc) { - Log log(LogLevel::Error); - log << cursor; - CXCursor ref = clang_getCursorReferenced(cursor); - if (!clang_isInvalid(clang_getCursorKind(ref)) && ref != cursor) { - log << "refs" << ref; - } - break; - } - } - ++mAllowed; - if (mLogFile) { - String out; - Log(&out) << cursor; - fwrite(out.constData(), 1, out.size(), mLogFile); - fwrite("\n", 1, 1, mLogFile); - } - - if (testLog(LogLevel::VerboseDebug)) { - Log log(LogLevel::VerboseDebug); - log << cursor; - CXCursor ref = clang_getCursorReferenced(cursor); - if (!clang_isInvalid(clang_getCursorKind(ref)) && ref != cursor) { - log << "refs" << ref; - } - } - - if (Symbol::isClass(kind)) { - mLastClass = loc; - } else { - if (kind == CXCursor_CXXBaseSpecifier) { - handleBaseClassSpecifier(cursor); - return CXChildVisit_Recurse; - } - } - - CXChildVisitResult visitResult = CXChildVisit_Recurse; - switch (type) { - case RTags::Type_Cursor: - visitResult = handleCursor(cursor, kind, loc); - break; - case RTags::Type_Include: - handleInclude(cursor, kind, loc); - break; - case RTags::Type_Literal: - handleLiteral(cursor, kind, loc); - break; - case RTags::Type_Statement: - visitResult = handleStatement(cursor, kind, loc); - break; - case RTags::Type_Reference: - switch (kind) { - case CXCursor_OverloadedDeclRef: { - const int count = clang_getNumOverloadedDecls(cursor); - for (int i=0; i arguments; - extractArguments(&arguments, cursor); - Symbol *old = 0; - Location oldLoc; - std::swap(mLastCallExprSymbol, old); - const CXCursor ref = clang_getCursorReferenced(cursor); - bool handled = false; - const CXCursorKind refKind = clang_getCursorKind(ref); - if (refKind == CXCursor_Constructor - && (clang_getCursorKind(mLastCursor) == CXCursor_TypeRef || clang_getCursorKind(mLastCursor) == CXCursor_TemplateRef)) { - handled = true; - for (int pos = mParents.size() - 1; pos >= 0; --pos) { - const CXCursor &parent = mParents[pos]; - const CXCursorKind k = clang_getCursorKind(parent); - if (k == CXCursor_VarDecl) { - handled = false; - break; - } else if (k == CXCursor_CallExpr) { - if (!clang_isInvalid(clang_getCursorKind(clang_getCursorReferenced(parent)))) { - handled = false; - break; - } - } else if (k != CXCursor_UnexposedExpr) { - break; - } - } - if (handled) { - loc = createLocation(mLastCursor); - handleReference(mLastCursor, kind, loc, ref); - } - } else if (refKind == CXCursor_FieldDecl) { - handled = true; - } - if (!handled) { - handleReference(cursor, kind, loc, ref); - } - List destArguments; - extractArguments(&destArguments, ref); - visit(cursor); - if (mLastCallExprSymbol && !arguments.isEmpty()) { - const Location invokedLocation = createLocation(ref, refKind); - auto u = unit(loc); - size_t idx = 0; - for (const auto &arg : arguments) { - const auto destArg = destArguments.value(idx); - if (destArg.location.isNull()) - break; - const Location start = arg.location; - Location end; - if (idx + 1 == arguments.size()) { - end = Location(start.fileId(), start.line(), start.column() + arg.length); // this falls apart with multi-line args - } else { - end = arguments.value(idx + 1).location; - } - auto it = u->symbols.lower_bound(start); - while (it != u->symbols.end() && it->first < end) { - auto &sym = it->second; - sym.argumentUsage.index = idx; - sym.argumentUsage.invokedFunction = invokedLocation; - sym.argumentUsage.argument = destArg; - sym.argumentUsage.invocation = mLastCallExprSymbol->location; - ++it; - } - ++idx; - } - - mLastCallExprSymbol->arguments = std::move(arguments); - } - std::swap(old, mLastCallExprSymbol); - visitResult = CXChildVisit_Continue; - break; } - default: - handleReference(cursor, kind, loc, clang_getCursorReferenced(cursor)); - break; - } - break; - case RTags::Type_Other: - assert(0); - break; - } - return visitResult; -} - -static inline bool isImplicit(const CXCursor &cursor) -{ - return clang_equalLocations(clang_getCursorLocation(cursor), - clang_getCursorLocation(clang_getCursorSemanticParent(cursor))); -} - -bool ClangIndexer::superclassTemplateMemberFunctionUgleHack(const CXCursor &cursor, CXCursorKind kind, - Location location, const CXCursor &/*ref*/, - Symbol **cursorPtr) -{ - // This is for references to superclass template functions. Awful awful - // shit. See https://github.com/Andersbakken/rtags/issues/62 and commit - // for details. I really should report this as a bug. - if (cursorPtr) - *cursorPtr = 0; - if (kind != CXCursor_MemberRefExpr && clang_getCursorKind(mParents.last()) != CXCursor_CallExpr) - return false; - - const CXCursor templateRef = RTags::findChild(cursor, CXCursor_TemplateRef); - if (templateRef != CXCursor_TemplateRef) - return false; - - const CXCursor classTemplate = clang_getCursorReferenced(templateRef); - if (classTemplate != CXCursor_ClassTemplate) - return false; - FILE *f = fopen(location.path().constData(), "r"); - if (!f) - return false; - - const CXSourceRange range = clang_getCursorExtent(cursor); - const CXSourceLocation end = clang_getRangeEnd(range); - unsigned int offset; - clang_getSpellingLocation(end, 0, 0, 0, &offset); - - String name; - while (offset > 0) { - fseek(f, --offset, SEEK_SET); - char ch = static_cast(fgetc(f)); - if (isalnum(ch) || ch == '_' || ch == '~') { - name.prepend(ch); - } else { - break; - } - } - fclose(f); - if (!name.isEmpty()) { - RTags::Filter out; - out.kinds.insert(CXCursor_MemberRefExpr); - const int argCount = RTags::children(mParents.last(), RTags::Filter(), out).size(); - RTags::Filter in(RTags::Filter::And); - in.names.insert(name); - in.argumentCount = argCount; - const List alternatives = RTags::children(classTemplate, in); - switch (alternatives.size()) { - case 1: - // ### not sure this is correct with line/col - return handleReference(cursor, kind, - Location(location.fileId(), location.line(), location.column() + 1), - alternatives.first(), cursorPtr); - break; - case 0: - break; - default: - warning() << "Can't decide which of these symbols are right for me" - << cursor << alternatives - << "Need to parse types"; - break; - } - } - return false; -} - -bool ClangIndexer::handleReference(const CXCursor &cursor, CXCursorKind kind, Location location, CXCursor ref, Symbol **cursorPtr) -{ - if (cursorPtr) - *cursorPtr = 0; - // error() << "handleReference" << cursor << kind << location << ref; - const CXCursorKind refKind = clang_getCursorKind(ref); - if (clang_isInvalid(refKind)) { - return superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, cursorPtr); - } - - const CXCursor originalRef = ref; - bool isOperator = false; - if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod - || refKind == CXCursor_FunctionDecl - || refKind == CXCursor_FunctionTemplate)) { - // These are bullshit. for this construct: - // foo.bar(); - // the position of the cursor is at the foo, not the bar. - // They are not interesting for followLocation, renameSymbol or find - // references so we toss them. - // For functions it can be the position of the namespace. - // E.g. Foo::bar(); cursor is on Foo - // For constructors they happen to be the only thing we have that - // actually refs the constructor and not the class so we have to keep - // them for that. - return false; - } - - Location refLoc = createLocation(ref, refKind); - if (!refLoc.isValid()) { - // ### THIS IS NOT SOLVED - // if (kind == CXCursor_ObjCMessageExpr) { - // mIndexDataMessage.mPendingReferenceMap[RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(ref)))].insert(location); - // // insert it, we'll hook up the target and references later - // return handleCursor(cursor, kind, location, cursorPtr); - // } - return false; - } - - switch (refKind) { - case CXCursor_Constructor: - case CXCursor_CXXMethod: - case CXCursor_FunctionDecl: - case CXCursor_Destructor: - case CXCursor_FunctionTemplate: { - bool visitReference = false; - ref = resolveTemplate(ref, refLoc, &visitReference); - if (visitReference && (kind == CXCursor_DeclRefExpr || kind == CXCursor_MemberRefExpr)) { - mTemplateSpecializations.insert(originalRef); - } - - if (refKind == CXCursor_FunctionDecl) - break; - if (refKind == CXCursor_Constructor || refKind == CXCursor_Destructor) { - if (isImplicit(ref)) { - return false; - } - } else { - CXStringScope scope = clang_getCursorDisplayName(ref); - const char *data = scope.data(); - if (data) { - const int len = strlen(data); - if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { - if (isImplicit(ref)) { - return false; // eat implicit operator calls - } - isOperator = true; - } - } - } - break; } - default: - break; - } - - const String refUsr = usr(ref); - if (refUsr.isEmpty()) { - return false; - } - - FindResult result; - auto reffedCursor = findSymbol(refLoc, &result); - Map &targets = unit(location)->targets[location]; - if (result == NotFound && !mUnionRecursion) { - CXCursor parent = clang_getCursorSemanticParent(ref); - CXCursor best = clang_getNullCursor(); - while (true) { - if (clang_getCursorKind(parent) != CXCursor_UnionDecl) - break; - best = parent; - parent = clang_getCursorSemanticParent(parent); - } - if (best == CXCursor_UnionDecl) { - mUnionRecursion = true; - // for anonymous unions we don't get to their fields with normal - // recursing of the AST. In these cases we visit the union decl - visit(best); - mUnionRecursion = false; - reffedCursor = findSymbol(refLoc, &result); - } - } - int16_t refTargetValue; - if (result == Found) { - refTargetValue = reffedCursor.targetsValue(); - } else { - refTargetValue = RTags::createTargetsValue(refKind, clang_isCursorDefinition(ref)); - } - - Symbol *c = &unit(location)->symbols[location]; - assert(c); - bool setTarget = true; - if (c->kind == CXCursor_MacroExpansion) { - for (const auto &t : targets) { - if (RTags::targetsValueKind(t.second) == CXCursor_MacroDefinition) { - for (const auto &u : mUnits) { // ### should only search the ones we depend on - const auto it = u.second->usrs.find(t.first); - if (it != u.second->usrs.end()) { - auto mit = mMacroTokens.find(*it->second.begin()); - if (mit != mMacroTokens.end()) { - const String id = RTags::eatString(clang_getCursorSpelling(cursor)); - auto idit = mit->second.data.find(id); - if (idit != mit->second.data.end()) { - List &locs = idit->second.locations; - assert(!locs.isEmpty()); - location = locs.front(); - if (locs.size() == 1) { - if (mit->second.data.size() == 1) { - mMacroTokens.erase(mit); - } else { - mit->second.data.erase(idit); - } - } else { - locs.remove(0, 1); - } - std::shared_ptr uu = unit(location); - c = &uu->symbols[location]; - Map &tt = uu->targets[location]; - tt[refUsr] = refTargetValue; - setTarget = false; - } - } - break; - } - } - break; - } - } - } - - assert(!refUsr.isEmpty()); - targets[refUsr] = refTargetValue; - - if (mInTemplateFunction) - c->flags |= Symbol::TemplateReference; - - if (cursorPtr) - *cursorPtr = c; - - // We need the new cursor to replace the symbolLength. This is important - // in the following case: - // struct R { R(const &r); ... } - // R foo(); - // ... - // R r = foo(); - - // The first cursor on foo() will be a reference to the copy constructor and - // this cursor will have a symbolLength of 1. Thus you won't be able to jump - // to foo from the o. This is fixed by making sure the newer target, if - // better, gets to decide on the symbolLength - - // The !isCursor is var decls and field decls where we set up a target even - // if they're not considered references - - if (setTarget && !c->isNull()) { - if (RTags::isCursor(c->kind)) - return true; - auto best = targets.end(); - int bestRank = RTags::targetRank(RTags::targetsValueKind(refTargetValue)); - for (auto it = targets.begin(); it != targets.end(); ++it) { - const int r = RTags::targetRank(RTags::targetsValueKind(it->second)); - if (r > bestRank || (r == bestRank && RTags::targetsValueIsDefinition(it->second))) { - bestRank = r; - best = it; - } - } - if (best != targets.end() && best->first != refUsr) { // another target is better - return true; - } - } - -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 35) - if (result == Found) { - c->size = reffedCursor.size; - c->alignment = reffedCursor.alignment; - } else { - const CXType type = clang_getCursorType(ref); - if (type.kind != CXType_LValueReference - && type.kind != CXType_RValueReference - && type.kind != CXType_Auto - && type.kind != CXType_Unexposed) { - c->size = std::max(0, clang_Type_getSizeOf(type)); - c->alignment = std::max(-1, clang_Type_getAlignOf(type)); - } - } -#endif - - CXSourceRange range = clang_getCursorExtent(cursor); - uint16_t symLength; - setRange(*c, range, &symLength); - c->kind = kind; - c->location = location; - - c->symbolName = RTags::eatString(clang_getCursorSpelling(cursor)); - if (c->symbolName.isEmpty()) - c->symbolName = (result == Found ? reffedCursor.symbolName : addNamePermutations(ref, refLoc, RTags::Type_Reference)); - if (isOperator) { - c->symbolLength = symLength; - } else { - c->symbolLength = result == Found ? reffedCursor.symbolLength : symbolLength(refKind, ref); - } - if (!c->symbolLength) { - unit(location)->symbols.remove(location); - if (cursorPtr) - *cursorPtr = 0; - return false; - } - setType(*c, clang_getCursorType(kind == CXCursor_MemberRefExpr ? ref : cursor)); - if (RTags::isFunction(refKind)) { - mLastCallExprSymbol = c; - } - - if (mInTemplateFunction && !mParents.isEmpty()) { - if ((kind == CXCursor_DeclRefExpr && mParents.last() == CXCursor_MemberRefExpr) - || (kind == CXCursor_TypeRef && mParents.last() == CXCursor_DeclRefExpr)) { - CXSourceRange parentRange = clang_getCursorExtent(mParents.last()); - CXToken *tokens = 0; - unsigned numTokens = 0; - auto tu = mTranslationUnits.at(mCurrentTranslationUnit)->unit; - clang_tokenize(tu, parentRange, &tokens, &numTokens); - for (size_t i=0; i" || str == "." || str == "::") && ++i < numTokens) { - assert(i < numTokens); - CXSourceRange memberRange = clang_getTokenExtent(tu, tokens[i]); - unsigned line, column; - clang_getSpellingLocation(clang_getRangeStart(memberRange), 0, &line, &column, 0); - const CXStringScope memberSpelling(clang_getTokenSpelling(tu, tokens[i])); - const Location loc(location.fileId(), line, column); - Symbol &sym = unit(loc)->symbols[loc]; - sym.location = loc; - sym.symbolName = memberSpelling.data(); - sym.symbolLength = sym.symbolName.size(); - if (kind == CXCursor_DeclRefExpr) { - sym.kind = CXCursor_MemberRefExpr; - } else { - sym.kind = CXCursor_DeclRefExpr; // yes this is weird - } - sym.flags = Symbol::TemplateReference; - setType(sym, clang_getCursorType(mParents.last())); - setRange(sym, memberRange); - if (kind == CXCursor_DeclRefExpr) // there might be more than one level of :: - break; - } - } - } - - clang_disposeTokens(tu, tokens, numTokens); - } - } - - return true; -} - -std::unordered_set ClangIndexer::addOverriddenCursors(const CXCursor &c, Location location) -{ - // error() << "addOverriddenCursors" << cursor << location; - std::unordered_set ret; - std::function process = [location, &ret, this, &process](const CXCursor &cursor) { - CXCursor *overridden; - unsigned int count; - clang_getOverriddenCursors(cursor, &overridden, &count); - if (overridden) { - ret.insert(cursor); - for (unsigned int i=0; itargets[location][usr] = 0; - process(overridden[i]); - } - clang_disposeOverriddenCursors(overridden); - } - }; - process(c); - return ret; -} - -void ClangIndexer::handleInclude(const CXCursor &cursor, CXCursorKind kind, Location location) -{ - assert(kind == CXCursor_InclusionDirective); - (void)kind; - CXFile includedFile = clang_getIncludedFile(cursor); - if (includedFile) { - const Location refLoc = createLocation(includedFile, 1, 1); - if (!refLoc.isNull()) { - Symbol &c = unit(location)->symbols[location]; - if (!c.isNull()) - return; - - String include = "#include "; - Path path = refLoc.path(); - assert(mSources.front().fileId); - unit(location)->symbolNames[(include + path)].insert(location); - unit(location)->symbolNames[(include + path.fileName())].insert(location); - mIndexDataMessage.includes().push_back(std::make_pair(location.fileId(), refLoc.fileId())); - c.symbolName = "#include " + RTags::eatString(clang_getCursorDisplayName(cursor)); - c.kind = cursor.kind; - c.symbolLength = c.symbolName.size() + 2; - c.location = location; - unit(location)->targets[location][refLoc.toString(Location::NoColor|Location::ConvertToRelative)] = 0; // ### what targets value to create for this? - // this fails for things like: - // # include - return; - } - } - - mIndexDataMessage.files()[location.fileId()] |= IndexDataMessage::IncludeError; - error() << "handleInclude failed" << includedFile << cursor; -} - -void ClangIndexer::handleLiteral(const CXCursor &cursor, CXCursorKind kind, Location location) -{ - auto tu = mTranslationUnits.at(mCurrentTranslationUnit)->unit; - auto u = unit(location); - // error() << location << kind - // << RTags::eatString(clang_getCursorDisplayName(cursor)) - // << RTags::eatString(clang_getCursorSpelling(cursor)) - // << clang_getCursorType(cursor).kind; - - CXType type = clang_getCursorType(cursor); - // error() << location << kind << displayName; - Symbol &s = u->symbols[location]; - if (!s.isNull()) - return; - s.location = location; - s.kind = kind; - setType(s, type); - CXSourceRange range = clang_getCursorExtent(cursor); - setRange(s, range, &s.symbolLength); - - String symbolName; - if (kind != CXCursor_StringLiteral) { - CXToken *tokens = 0; - unsigned numTokens = 0; - clang_tokenize(tu, range, &tokens, &numTokens); - if (numTokens) { - symbolName = RTags::eatString(clang_getTokenSpelling(tu, tokens[0])); - } else { - Log(&symbolName) << type.kind; - } - - clang_disposeTokens(tu, tokens, numTokens); - } else { - symbolName = RTags::eatString(clang_getCursorSpelling(cursor)); - } - s.symbolName = symbolName; - u->symbolNames[symbolName].insert(location); - s.symbolLength = symbolName.size(); -} - -CXChildVisitResult ClangIndexer::handleStatement(const CXCursor &cursor, CXCursorKind kind, Location location) -{ - auto u = unit(location); - // error() << "got dude" << kind << location; - switch (kind) { - case CXCursor_CompoundStmt: { - Symbol &c = u->symbols[location]; - if (!c.isNull()) { - break; - } - setRange(c, clang_getCursorExtent(cursor)); - const Scope scope = { - Scope::Other, 0, - Location(location.fileId(), c.startLine, c.startColumn), - Location(location.fileId(), c.endLine, c.endColumn - 1) - }; - if (mScopeStack.isEmpty() || mScopeStack.back().end != scope.end) { - c.location = location; - c.kind = kind; - c.symbolName = "{}"; - c.symbolLength = 1; - // should it have a symbolLength? - mScopeStack.append(scope); - visit(cursor); - mScopeStack.removeLast(); - } else { - // this is the function body, no need for this CompoundStmt - u->symbols.remove(location); - visit(cursor); - } - return CXChildVisit_Continue; } - case CXCursor_ReturnStmt: { - Symbol &c = u->symbols[location]; - if (!c.isNull()) - break; - - for (int i=mScopeStack.size() - 1; i>=0; --i) { - const auto &scope = mScopeStack.at(i); - if (scope.type == Scope::FunctionDefinition) { - c.kind = kind; - c.symbolName = "return"; - u->symbolNames[c.symbolName].insert(location); - c.kind = kind; - c.symbolLength = 6; - c.location = location; - setRange(c, clang_getCursorExtent(cursor)); - u->targets[location][scope.start.toString(Location::NoColor|Location::ConvertToRelative)] = 0; - break; - } - } - if (!c.symbolLength) - u->symbols.remove(location); - break; } - case CXCursor_ForStmt: - case CXCursor_WhileStmt: - case CXCursor_DoStmt: - case CXCursor_IfStmt: - case CXCursor_SwitchStmt: { - Symbol &c = u->symbols[location]; - if (!c.isNull()) - break; - setRange(c, clang_getCursorExtent(cursor)); - c.kind = kind; - switch (kind) { - case CXCursor_SwitchStmt: c.symbolName = "switch"; break; - case CXCursor_IfStmt: c.symbolName = "if"; break; - case CXCursor_ForStmt: c.symbolName = "for"; break; - case CXCursor_WhileStmt: c.symbolName = "while"; break; - case CXCursor_DoStmt: c.symbolName = "do"; break; - default: assert(0); break; - } - u->symbolNames[c.symbolName].insert(location); - c.symbolLength = c.symbolName.size(); - c.location = location; - if (kind != CXCursor_IfStmt) { - const Loop loop = { - kind, - Location(location.fileId(), c.startLine, c.startColumn), - Location(location.fileId(), c.endLine, c.endColumn) - }; - - mLoopStack.append(loop); - visit(cursor); - mLoopStack.removeLast(); - return CXChildVisit_Continue; - } - break; } - case CXCursor_ContinueStmt: - case CXCursor_BreakStmt: { - Symbol &c = u->symbols[location]; - if (!c.isNull()) - break; - Location target; - for (int i = mLoopStack.size() - 1; i>=0; --i) { - const auto &loop = mLoopStack.at(i); - if (kind == CXCursor_BreakStmt) { - target = loop.end; - break; - } else if (loop.kind != CXCursor_SwitchStmt) { - target = loop.start; - break; - } - } - if (target.isNull()) { - u->symbols.remove(location); - break; - } - setRange(c, clang_getCursorExtent(cursor)); - c.symbolName = kind == CXCursor_BreakStmt ? "break" : "continue"; - u->symbolNames[c.symbolName].insert(location); - c.kind = kind; - c.symbolLength = c.symbolName.size(); - c.location = location; - u->targets[location][target.toString(Location::NoColor|Location::ConvertToRelative)] = 0; - break; } - default: - break; - } - return CXChildVisit_Recurse; -} - -void ClangIndexer::handleBaseClassSpecifier(const CXCursor &cursor) -{ - auto &lastClass = unit(mLastClass)->symbols[mLastClass]; - if (!lastClass.isClass()) { - // this happens with some weird macros in /usr/include/dispatch/io.h:161:1 and others on Mac - // error() << "Couldn't find class for" << cursor << mLastClass; - return; - } - CXCursor ref = clang_getCursorReferenced(cursor); - if (clang_isInvalid(clang_getCursorKind(ref))) { // this happens when the base class is a template parameter - return; - } - - while (true) { - CXCursor tmp = resolveTypedef(resolveTemplate(ref)); - if (tmp == ref) { - break; - } else { - ref = std::move(tmp); - } - } - const String usr = ::usr(ref); - if (usr.isEmpty()) { - warning() << "Couldn't find usr for" << clang_getCursorReferenced(cursor) << cursor << mLastClass; - return; - } - assert(!usr.isEmpty()); - lastClass.baseClasses << usr; -} - -void ClangIndexer::extractArguments(List *arguments, const CXCursor &cursor) -{ - assert(arguments); - List args; - const int count = std::max(0, RTags::cursorArguments(cursor, &args)); - arguments->resize(count); - for (int i=0; iunit; - const String usr = ::usr(cursor); - // error() << "Got a cursor" << cursor; - Symbol &c = unit(location)->symbols[location]; - if (cursorPtr) - *cursorPtr = &c; - if (!c.isNull()) { - if (c.kind == CXCursor_MacroExpansion) { - addNamePermutations(cursor, location, RTags::Type_Cursor); - unit(location)->usrs[usr].insert(location); - } - return CXChildVisit_Recurse; - } - - // if (mLogFile) { - // String out; - // Log(&out) << cursor << a; - // fwrite(out.constData(), 1, out.size(), mLogFile); - // fwrite("\n", 1, 1, mLogFile); - // } - CXStringScope name = clang_getCursorSpelling(cursor); - const char *cstr = name.data(); - c.symbolLength = cstr ? strlen(cstr) : 0; - const CXType type = clang_getCursorType(cursor); - setType(c, type); - c.location = location; - c.usr = usr; - if (!c.symbolLength) { - // this is for these constructs: - // typedef struct { - // int a; - // } foobar; - // - // We end up not getting a spelling for the cursor - - switch (kind) { - case CXCursor_ClassDecl: - c.symbolLength = 5; - c.symbolName = "class"; - break; - case CXCursor_UnionDecl: - c.symbolLength = 5; - c.symbolName = "union"; - break; - case CXCursor_StructDecl: - c.symbolLength = 6; - c.symbolName = "struct"; - break; - case CXCursor_LambdaExpr: - c.symbolLength = 2; - c.symbolName = c.typeName; - break; - default: - unit(location)->symbols.remove(location); - if (cursorPtr) - *cursorPtr = 0; - return CXChildVisit_Recurse; - } - } else { - if (kind == CXCursor_VarDecl || kind == CXCursor_ParmDecl) { - RTags::Auto resolvedAuto; - if (RTags::resolveAuto(cursor, &resolvedAuto)) { - c.flags |= Symbol::Auto; - if (resolvedAuto.type.kind != CXType_Invalid) { - setType(c, resolvedAuto.type); - } else { - warning() << "Couldn't resolve auto for" << cursor; - } - } - } - - c.symbolName = addNamePermutations(cursor, location, RTags::Type_Cursor); - } - - if (clang_isCursorDefinition(cursor)) - c.flags |= Symbol::Definition; - - const CXSourceRange range = clang_getCursorExtent(cursor); - setRange(c, range); - - switch (kind) { - case CXCursor_ParmDecl: - case CXCursor_VarDecl: { - if (type.kind != CXType_Record || mScopeStack.isEmpty() || mScopeStack.back().type == Scope::FunctionDeclaration) - break; - - CXCursor ref = RTags::findChild(cursor, CXCursor_TypeRef); - if (ref != CXCursor_TypeRef) - ref = RTags::findChild(cursor, CXCursor_TemplateRef); - switch (clang_getCursorKind(ref)) { - case CXCursor_TypeRef: - case CXCursor_TemplateRef: { - const CXCursor referenced = clang_getCursorReferenced(ref); - switch (clang_getCursorKind(referenced)) { - case CXCursor_StructDecl: - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: { - const CXCursor destructor = RTags::findChild(referenced, CXCursor_Destructor); - if (RTags::isValid(destructor)) { - const String destructorUsr = ::usr(destructor); - assert(!destructorUsr.isEmpty()); - const Location scopeEndLocation = mScopeStack.back().end; - auto u = unit(scopeEndLocation); - Map &t = u->targets[scopeEndLocation]; - t[destructorUsr] = 0; - Symbol &scopeEnd = u->symbols[scopeEndLocation]; - scopeEnd.symbolName = "}"; - scopeEnd.location = scopeEndLocation; - scopeEnd.symbolLength = 1; - scopeEnd.flags = Symbol::ImplicitDestruction; - scopeEnd.kind = CXCursor_CallExpr; - // error() << "Found destructor" << destructor << "for" << cursor << "in scope that ends on" << mScopeStack.back(); - } - break; } - default: - break; - } - break; } - default: - break; - } - break; } - case CXCursor_EnumConstantDecl: -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 2) - c.enumValue = clang_getEnumConstantDeclValue(cursor); -#endif - break; - case CXCursor_MacroDefinition: { - CXToken *tokens = 0; - unsigned numTokens = 0; - clang_tokenize(tu, range, &tokens, &numTokens); - MacroData ¯oData = mMacroTokens[location]; - enum { - Unset, - GettingArgs, - ArgsDone - } macroState = Unset; - MacroLocationData *last = 0; - bool lastWasHashHash = false; - for (size_t i=1; iunit, tokens[i])); - if (macroState == Unset) { - if (k == CXToken_Punctuation) { - const CXStringScope scope(clang_getTokenSpelling(tu, tokens[i])); - if (!strcmp(scope.data(), "(")) - macroState = GettingArgs; - } - if (macroState == Unset) - macroState = ArgsDone; - } - // error() << i << clang_getTokenKind(tokens[i]) - // << RTags::eatString(clang_getTokenSpelling(tu, tokens[i])); - bool isHashHash = false; - if (k == CXToken_Identifier) { - const String spelling = RTags::eatString(clang_getTokenSpelling(tu, tokens[i])); - if (macroState == GettingArgs) { - macroData.arguments.append(spelling); - } else { - if (!lastWasHashHash) { - last = ¯oData.data[spelling]; - - List &locs = last->locations; - locs.append(createLocation(clang_getTokenLocation(tu, tokens[i]))); - } - if (last) { - const size_t idx = macroData.arguments.indexOf(spelling); - if (idx != String::npos) { - last->arguments.insert(idx); - } - } - } - } else if (macroState == GettingArgs && k == CXToken_Punctuation) { - const CXStringScope scope(clang_getTokenSpelling(tu, tokens[i])); - if (!strcmp(scope.data(), ")")) - macroState = ArgsDone; - } else if (k == CXToken_Punctuation) { - const CXStringScope scope(clang_getTokenSpelling(tu, tokens[i])); - if (!strcmp(scope.data(), "##")) { - isHashHash = true; - } else { - last = 0; - } - } else { - last = 0; - } - lastWasHashHash = isHashHash; - } - // error() << macroData.arguments; - // for (const auto &d : macroData.data) { - // error() << d.first << d.second.locations << d.second.arguments; - // } - - clang_disposeTokens(tu, tokens, numTokens); - break; } - case CXCursor_FieldDecl: -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 30) - c.fieldOffset = std::max(-1, clang_Cursor_getOffsetOfField(cursor)); -#endif - // fall through - default: - break; - } - -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 35) - if (!(c.flags & Symbol::Auto) - && c.type != CXType_LValueReference - && c.type != CXType_RValueReference - && c.type != CXType_Auto - && c.type != CXType_Unexposed) { - c.size = std::max(0, clang_Type_getSizeOf(type)); - c.alignment = std::max(-1, clang_Type_getAlignOf(type)); - if (c.size > 0 && (kind == CXCursor_VarDecl || kind == CXCursor_ParmDecl)) { - for (int i=mScopeStack.size() - 1; i>=0; --i) { - auto &scope = mScopeStack.at(i); - if (scope.type == Scope::FunctionDefinition) { - assert(scope.symbol); - scope.symbol->stackCost += c.size; - break; - } else if (scope.type == Scope::FunctionDeclaration) { - break; - } - } - } - } -#endif - - c.kind = kind; - c.linkage = clang_getCursorLinkage(cursor); - // apparently some function decls will give a different usr for - // their definition and their declaration. Using the canonical - // cursor's usr allows us to join them. Check JSClassRelease in - // JavaScriptCore for an example. - unit(location)->usrs[c.usr].insert(location); - if (c.linkage == CXLinkage_External && !c.isDefinition()) { - switch (c.kind) { - case CXCursor_FunctionDecl: - case CXCursor_VarDecl: { - const auto k = clang_getCursorKind(clang_getCursorSemanticParent(cursor)); - switch (k) { - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: - case CXCursor_StructDecl: - break; - default: - unit(location)->targets[location][usr] = RTags::createTargetsValue(k, true); - break; - } - break; } - default: - break; - } - } - - std::unordered_set cursors; - switch (c.kind) { - case CXCursor_CXXMethod: -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20) - if (clang_CXXMethod_isPureVirtual(cursor)) - c.flags |= Symbol::PureVirtualMethod; - else -#endif - if (clang_CXXMethod_isVirtual(cursor)) - c.flags |= Symbol::VirtualMethod; - - if (clang_CXXMethod_isStatic(cursor)) - c.flags |= Symbol::StaticMethod; -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 27) - if (clang_CXXMethod_isConst(cursor)) - c.flags |= Symbol::ConstMethod; -#endif - - cursors = addOverriddenCursors(cursor, location); - switch (clang_getCursorKind(clang_getCursorSemanticParent(cursor))) { - case CXCursor_ClassTemplate: - case CXCursor_ClassTemplatePartialSpecialization: - c.flags |= Symbol::TemplateFunction; - break; - default: - break; - } - - // fall through - case CXCursor_FunctionDecl: - case CXCursor_FunctionTemplate: - if (c.kind == CXCursor_FunctionTemplate) - c.flags |= Symbol::TemplateFunction; -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 19) - if (clang_Cursor_isVariadic(cursor)) - c.flags |= Symbol::Variadic; -#endif -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 33) - if (clang_Cursor_isFunctionInlined(cursor)) - c.flags |= Symbol::InlineFunction; -#endif - - extractArguments(&c.arguments, cursor); - break; - case CXCursor_LambdaExpr: - extractArguments(&c.arguments, cursor); - break; - case CXCursor_Constructor: - extractArguments(&c.arguments, cursor); - // fall through - case CXCursor_Destructor: { - CXCursor parent = clang_getCursorSemanticParent(cursor); - - switch (clang_getCursorKind(parent)) { - case CXCursor_ClassTemplate: - case CXCursor_ClassTemplatePartialSpecialization: - c.flags |= Symbol::TemplateFunction; - break; - default: - break; - } - - // these are for joining constructors/destructor with their classes (for renaming symbols) - assert(!::usr(parent).isEmpty()); - unit(location)->targets[location][::usr(parent)] = 0; - break; } - case CXCursor_ClassTemplate: - case CXCursor_StructDecl: - case CXCursor_ClassDecl: { - const CXCursor specialization = clang_getSpecializedCursorTemplate(cursor); - if (RTags::isValid(specialization)) { - unit(location)->targets[location][::usr(specialization)] = 0; - c.flags |= Symbol::TemplateSpecialization; - } - break; } - default: - break; - } - - if (!(ClangIndexer::serverOpts() & Server::NoComments)) { - CXComment comment = clang_Cursor_getParsedComment(cursor); - if (clang_Comment_getKind(comment) != CXComment_Null) { - c.briefComment = RTags::eatString(clang_Cursor_getBriefCommentText(cursor)); - c.xmlComment = RTags::eatString(clang_FullComment_getAsXML(comment)); - } - - for (auto it = cursors.begin(); it != cursors.end() && (c.briefComment.isEmpty() || c.xmlComment.isEmpty()); ++it) { - comment = clang_Cursor_getParsedComment(*it); - if (clang_Comment_getKind(comment) != CXComment_Null) { - if (c.briefComment.isEmpty()) { - c.briefComment = RTags::eatString(clang_Cursor_getBriefCommentText(*it)); - } - if (c.xmlComment.isEmpty()) - c.xmlComment = RTags::eatString(clang_FullComment_getAsXML(comment)); - } - } - } - - if (RTags::isFunction(c.kind)) { - const bool definition = c.flags & Symbol::Definition; - mScopeStack.append({definition ? Scope::FunctionDefinition : Scope::FunctionDeclaration, definition ? &c : 0, - Location(location.fileId(), c.startLine, c.startColumn), - Location(location.fileId(), c.endLine, c.endColumn - 1)}); - bool isTemplateFunction = c.kind == CXCursor_FunctionTemplate; - if (!isTemplateFunction && (c.kind == CXCursor_CXXMethod - || c.kind == CXCursor_Constructor - || c.kind == CXCursor_Destructor) - && clang_getCursorSemanticParent(cursor) == CXCursor_ClassTemplate) { - isTemplateFunction = true; - } - if (isTemplateFunction) - ++mInTemplateFunction; - visit(cursor); - if (isTemplateFunction) - --mInTemplateFunction; - mScopeStack.removeLast(); - return CXChildVisit_Continue; - } - - return CXChildVisit_Recurse; -} - -bool ClangIndexer::parse() -{ - StopWatch sw; - assert(mTranslationUnits.isEmpty()); - Flags commandLineFlags = Source::Default; - if (ClangIndexer::serverOpts() & Server::PCHEnabled) - commandLineFlags |= Source::PCHEnabled; - - Flags flags = CXTranslationUnit_DetailedPreprocessingRecord; - if (mIndexDataMessage.indexerJobFlags() & IndexerJob::Active) { - flags |= CXTranslationUnit_PrecompiledPreamble; - flags |= CXTranslationUnit_ForSerialization; -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 32) - flags |= CXTranslationUnit_CreatePreambleOnFirstParse; -#endif - } else { -#if CINDEX_VERSION_MINOR > 33 - flags |= CXTranslationUnit_KeepGoing; -#endif - } - bool pch; - switch (mSources.front().language) { - case Source::CPlusPlus11Header: - case Source::CPlusPlusHeader: - case Source::CHeader: - flags |= CXTranslationUnit_Incomplete; - pch = true; - break; - default: - pch = false; - break; - } - - List unsavedFiles(mUnsavedFiles.size() + 1); - int unsavedIndex = 0; - for (const auto &it : mUnsavedFiles) { - unsavedFiles[unsavedIndex++] = { - it.first.constData(), - it.second.constData(), - static_cast(it.second.size()) - }; - } - - bool ok = false; - for (const Source &source : mSources) { - if (testLog(LogLevel::Debug)) - debug() << "CI::parse: " << source.toCommandLine(commandLineFlags) << "\n"; - - // for (const auto it : source.toCommandLine(commandLineFlags)) { - // error("[%s]", it.constData()); - // } - bool usedPch = false; - const List args = source.toCommandLine(commandLineFlags, &usedPch); - if (usedPch) - mIndexDataMessage.setFlag(IndexDataMessage::UsedPCH); - - std::shared_ptr unit; - if (mIndexDataMessage.indexerJobFlags() & IndexerJob::Active && serverOpts() & Server::TranslationUnitCache) { - Path path = mDataDir + "tucache/"; - Path::mkdir(path, Path::Recursive); - path << mSources.front().fileId; - StopWatch sw2; - unit = RTags::TranslationUnit::load(path); - if (unit) { - error() << "loaded cached unit in" << sw2.restart(); - if (!unit->reparse(&unsavedFiles[0], unsavedIndex)) { - error() << "Failed to reparse"; - unit.reset(); - } else { - error() << "reparsed cached unit in" << sw2.restart(); - } - } - } - - if (!unit) - unit = RTags::TranslationUnit::create(mSourceFile, args, &unsavedFiles[0], unsavedIndex, flags, false); - mTranslationUnits.push_back(unit); - - warning() << "CI::parse loading unit:" << unit->clangLine << " " << (unit->unit != 0); - if (unit->unit) { - if (pch && ClangIndexer::serverOpts() & Server::PCHEnabled) { - Path path = RTags::encodeSourceFilePath(mDataDir, mProject, source.fileId); - Path::mkdir(path, Path::Recursive); - path << "pch.h.gch"; - Path tmp = path; - tmp << ".tmp"; - clang_saveTranslationUnit(unit->unit, tmp.constData(), clang_defaultSaveOptions(unit->unit)); - rename(tmp.constData(), path.constData()); - warning() << "SAVED PCH" << path; - } else if (!mSerializeTU && mIndexDataMessage.indexerJobFlags() & IndexerJob::Active && serverOpts() & Server::TranslationUnitCache) { - mSerializeTU = unit; - } - - ok = true; - mParseDuration = sw.elapsed(); - } else { - error() << "Failed to parse" << unit->clangLine; - mIndexDataMessage.setFlag(IndexDataMessage::ParseFailure); - } - } - return ok; -} - -static inline Map > convertTargets(const Map > &in, bool hasRoot) -{ - Map > ret; - if (hasRoot) { - for (const auto &v : in) { - for (const auto &u : v.second) { - ret[Sandbox::encoded(u.first)].insert(v.first); - } - } - } else { - for (const auto &v : in) { - for (const auto &u : v.second) { - ret[u.first].insert(v.first); - } - } - } - return ret; -} - -static inline void encodeSymbols(Map &symbols) -{ - assert(Sandbox::hasRoot()); - for (auto &sym : symbols) { - Sandbox::encode(sym.second.symbolName); - Sandbox::encode(sym.second.usr); - Sandbox::encode(sym.second.typeName); - Sandbox::encode(sym.second.briefComment); - Sandbox::encode(sym.second.xmlComment); - } -} - -bool ClangIndexer::writeFiles(const Path &root, String &error) -{ - size_t bytesWritten = 0; - const Path p = Sandbox::encoded(mSourceFile); - const bool hasRoot = Sandbox::hasRoot(); - const uint32_t fileId = mSources.front().fileId; - - auto process = [&](Hash >::const_iterator unit) { - assert(mIndexDataMessage.files().value(unit->first) & IndexDataMessage::Visited); - String unitRoot = root; - unitRoot << unit->first; - Path::mkdir(unitRoot, Path::Recursive); - const Path path = Location::path(unit->first); - if (unit->first != fileId) { - FILE *f = fopen((unitRoot + "/info").constData(), "w"); - if (!f) - return false; - Path rpath = path; - Sandbox::encode(rpath); - bytesWritten += fprintf(f, "%s\nIndexed by %s at %llu\n", - rpath.constData(), - p.constData(), static_cast(mIndexDataMessage.parseTime())); - fclose(f); - } - - auto uit = mUnsavedFiles.find(path); - if (uit == mUnsavedFiles.end()) { - Path::rm(unitRoot + "/unsaved"); - } else { - FILE *f = fopen((unitRoot + "/unsaved").constData(), "w"); - if (!f) - return false; - bool ok = fwrite(uit->second.constData(), uit->second.size(), 1, f); - fclose(f); - if (!ok) - return false; - bytesWritten += uit->second.size(); - } - - //::error() << "Writing file" << Location::path(unit->first) << unitRoot << unit->second->symbols.size() - // << unit->second->targets.size() - // << unit->second->usrs.size() - // << unit->second->symbolNames.size(); - uint32_t fileMapOpts = 0; - if (ClangIndexer::serverOpts() & Server::NoFileLock) - fileMapOpts |= FileMap::NoLock; - - if (hasRoot) { - encodeSymbols(unit->second->symbols); - Sandbox::encode(unit->second->usrs); - Sandbox::encode(unit->second->symbolNames); - } - - size_t w; - // for (const char *name : { "/symbols", "/targets", "/usrs", "/symnames", "/tokens" }) { - // if (Path::exists(unitRoot + "/symbols")) - // ::error() << (unitRoot + name) << "already exists"; - // } - if (!(w = FileMap::write(unitRoot + "/symbols", unit->second->symbols, fileMapOpts))) { - error = "Failed to write symbols"; - return false; - } - bytesWritten += w; - - if (!(w = FileMap >::write(unitRoot + "/targets", convertTargets(unit->second->targets, hasRoot), fileMapOpts))) { - error = "Failed to write targets"; - return false; - } - bytesWritten += w; - - if (!(w += FileMap >::write(unitRoot + "/usrs", unit->second->usrs, fileMapOpts))) { - error = "Failed to write usrs"; - return false; - } - bytesWritten += w; - - if (!(w += FileMap >::write(unitRoot + "/symnames", unit->second->symbolNames, fileMapOpts))) { - error = "Failed to write symbolNames"; - return false; - } - bytesWritten += w; - - if (!(w += FileMap::write(unitRoot + "/tokens", unit->second->tokens, fileMapOpts))) { - error = "Failed to write symbolNames"; - return false; - } - bytesWritten += w; - return true; - }; - - List > templateSpecializationTargets; - auto self = mUnits.end(); - for (auto it = mUnits.begin(); it != mUnits.end(); ++it) { - if (!(mIndexDataMessage.files().value(it->first) & IndexDataMessage::Visited)) { - ::error() << "Wanting to write something for" - << it->first << Location::path(it->first) - << "but we didn't visit it" << mSourceFile - << "targets" << it->second->targets.size() - << "usrs" << it->second->usrs.size() - << "symbolNames" << it->second->symbolNames.size() - << "symbols" << it->second->symbols.size() - << "tokens" << it->second->tokens.size(); - continue; - } - if (it->first == fileId) { - self = it; - } else if (!process(it)) { - return false; - } - } - - if (self != mUnits.end()) { - for (const std::shared_ptr &t : templateSpecializationTargets) { - self->second->targets.unite(t->targets); - } - if (!process(self)) { - return false; - } - } - String sourceRoot = root; - sourceRoot << fileId; - Path::mkdir(sourceRoot, Path::Recursive); - sourceRoot << "/info"; - FILE *f = fopen(sourceRoot.constData(), "w"); - if (!f) { - return false; - } - - for (const Source &source : mSources) { - const String args = Sandbox::encoded(String::join(source.toCommandLine(Source::Default|Source::IncludeCompiler|Source::IncludeSourceFile), ' ')); - - bytesWritten += fprintf(f, "%s\n%s\n", p.constData(), args.constData()); - } - bytesWritten += fprintf(f, "Indexed at %llu\n", static_cast(mIndexDataMessage.parseTime())); - - fclose(f); - mIndexDataMessage.setBytesWritten(bytesWritten); - return true; -} - -bool ClangIndexer::diagnose() -{ - DiagnosticsProvider::diagnose(); - for (size_t i=0; iunit; - if (!tu) { - continue; - } - for (const auto &it : mIndexDataMessage.files()) { - if (it.second & IndexDataMessage::Visited) { - const Location loc(it.first, 0, 0); - const Path path = loc.path(); - CXFile file = clang_getFile(tu, path.constData()); - if (file) { - tokenize(file, it.first, path); - } - } - } - } - - return true; -} - -void ClangIndexer::tokenize(CXFile file, uint32_t fileId, const Path &path) -{ - const auto &tu = mTranslationUnits.at(mCurrentTranslationUnit)->unit; - StopWatch sw; - const CXSourceLocation startLoc = clang_getLocationForOffset(tu, file, 0); - const CXSourceLocation endLoc = clang_getLocationForOffset(tu, file, path.fileSize()); - - CXSourceRange range = clang_getRange(startLoc, endLoc); - CXToken *tokens = 0; - unsigned numTokens = 0; - auto &map = unit(fileId)->tokens; - clang_tokenize(tu, range, &tokens, &numTokens); - for (unsigned i=0; iunit) { - continue; - } - - visit(clang_getTranslationUnitCursor(unit->unit)); - - if (testLog(LogLevel::VerboseDebug)) { - VerboseVisitorUserData u = { 0, "clangLine + ">\n", this }; - clang_visitChildren(clang_getTranslationUnitCursor(unit->unit), - ClangIndexer::verboseVisitor, &u); - u.out += "clangLine + ">"; - if (getenv("RTAGS_INDEXERJOB_DUMP_TO_FILE")) { - char buf[1024]; - snprintf(buf, sizeof(buf), "/tmp/%s.log", mSourceFile.fileName()); - FILE *f = fopen(buf, "w"); - assert(f); - fwrite(u.out.constData(), 1, u.out.size(), f); - fclose(f); - } else { - logDirect(LogLevel::VerboseDebug, u.out); - } - } - } - - for (const auto &it : mIndexDataMessage.files()) { - if (it.second & IndexDataMessage::Visited) - addFileSymbol(it.first); - } - - std::unordered_set seen; - for (const CXCursor &spec : mTemplateSpecializations) { - std::function visitor = [&visitor, &seen, this](CXCursor cursor) { - if (!seen.insert(cursor).second) { - return CXChildVisit_Continue; - } - const CXCursorKind kind = clang_getCursorKind(cursor); - const CXCursor ref = clang_getCursorReferenced(cursor); - if (!ref) - return CXChildVisit_Recurse; - const CXCursorKind refKind = clang_getCursorKind(ref); - if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod - || refKind == CXCursor_FunctionDecl - || refKind == CXCursor_FunctionTemplate)) { - return CXChildVisit_Recurse; - } - - // error() << "considering" << cursor << "for" << ref; - bool ignored; - const Location loc = createLocation(cursor, kind, &ignored); - if (!loc.isNull()) { - const String refUsr = usr(resolveTemplate(ref)); - if (!refUsr.isEmpty()) { - assert(!refUsr.isEmpty()); - const uint32_t fileId = mSources.front().fileId; - unit(fileId)->targets[loc][refUsr] = RTags::createTargetsValue(refKind, clang_isCursorDefinition(ref)); - } - if (RTags::isFunction(refKind) && mTemplateSpecializations.find(ref) == mTemplateSpecializations.end()) { - RTags::TranslationUnit::visit(ref, visitor); - } - // error() << "inserting" << loc << refUsr; - } - return CXChildVisit_Recurse; - }; - RTags::TranslationUnit::visit(spec, visitor); - } - - mVisitDuration = watch.elapsed(); - - return true; -} - -CXChildVisitResult ClangIndexer::verboseVisitor(CXCursor cursor, CXCursor, CXClientData userData) -{ - VerboseVisitorUserData *u = reinterpret_cast(userData); - Location loc = u->indexer->createLocation(cursor); - if (loc.fileId()) { - CXCursor ref = clang_getCursorReferenced(cursor); - - if (u->indent >= 0) - u->out += String(u->indent, ' '); - u->out += RTags::cursorToString(cursor); - if (ref == cursor) { - u->out += " refs self"; - } else if (RTags::isValid(ref)) { - u->out += " refs " + RTags::cursorToString(ref); - } - - if (loc.fileId() && u->indexer->mIndexDataMessage.files().value(loc.fileId()) & IndexDataMessage::Visited) { - if (u->indexer->unit(loc)->symbols.contains(loc)) { - u->out += " used as cursor\n"; - } else { - u->out += " not used\n"; - } - } else { - u->out += " not indexed\n"; - } - } - if (u->indent >= 0) { - u->indent += 2; - clang_visitChildren(cursor, ClangIndexer::verboseVisitor, userData); - u->indent -= 2; - return CXChildVisit_Continue; - } else { - return CXChildVisit_Recurse; - } -} - -void ClangIndexer::addFileSymbol(uint32_t file) -{ - const Location loc(file, 1, 1); - const Path path = Location::path(file); - auto ref = unit(loc); - ref->symbolNames[path].insert(loc); - const char *fn = path.fileName(); - ref->symbolNames[fn].insert(loc); - Symbol &sym = ref->symbols[loc]; - if (sym.isNull()) - sym.flags |= Symbol::FileSymbol; - sym.location = loc; -} - -int ClangIndexer::symbolLength(CXCursorKind kind, const CXCursor &cursor) -{ - if (kind == CXCursor_VarDecl && RTags::resolveAuto(cursor)) { - return 4; - } - - CXStringScope name = clang_getCursorSpelling(cursor); - const char *cstr = name.data(); - if (cstr) - return strlen(cstr); - - // this is for these constructs: - // || - // \/ - // typedef struct { - // int a; - // } foobar; - // - // We end up not getting a spelling for the cursor - - switch (kind) { - case CXCursor_EnumDecl: - return 4; - case CXCursor_ClassDecl: - case CXCursor_UnionDecl: - return 5; - case CXCursor_StructDecl: - return 6; - default: - break; - } - return 0; -} - -Symbol ClangIndexer::findSymbol(Location location, FindResult *result) const -{ - auto it = mUnits.find(location.fileId()); - if (it != mUnits.end()) { - bool ok; - Symbol ret = it->second->symbols.value(location, Symbol(), &ok); - if (ok) { - *result = Found; - return ret; - } - } - - if (mIndexDataMessage.files().value(location.fileId()) & IndexDataMessage::Visited) { - *result = NotFound; - } else { - *result = NotIndexed; - } - return Symbol(); -} - -CXCursor ClangIndexer::resolveTemplate(CXCursor cursor, Location location, bool *specialized) -{ - if (specialized) - *specialized = false; - while (true) { - const CXCursor general = clang_getSpecializedCursorTemplate(cursor); - if (clang_Cursor_isNull(general)) - break; - if (specialized) - *specialized = true; - if (location.isNull()) - location = createLocation(cursor); - if (createLocation(general) == location) { - cursor = general; - } else { - break; - } - } - return cursor; -} - -CXCursor ClangIndexer::resolveTypedef(CXCursor cursor) -{ - while (clang_getCursorKind(cursor) == CXCursor_TypedefDecl) { - CXCursor typedeffed = clang_getTypeDeclaration(clang_getTypedefDeclUnderlyingType(cursor)); - if (RTags::isValid(typedeffed)) { - cursor = typedeffed; - } else { - break; - } - } - return cursor; -} diff --git a/rtags/src/ClangIndexer.h b/rtags/src/ClangIndexer.h deleted file mode 100644 index ce40b72..0000000 --- a/rtags/src/ClangIndexer.h +++ /dev/null @@ -1,196 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef ClangIndexer_h -#define ClangIndexer_h - -#include -#include "Token.h" - -#include "IndexDataMessage.h" -#include "rct/Hash.h" -#include "rct/Path.h" -#include "rct/StopWatch.h" -#include "RTags.h" -#include "Server.h" -#include "Symbol.h" -#include - -struct Unit; -class ClangIndexer : public RTags::DiagnosticsProvider -{ -public: - ClangIndexer(); - ~ClangIndexer(); - - bool exec(const String &data); - static Flags serverOpts() { return sServerOpts; } - static const Path &serverSandboxRoot() { return sServerSandboxRoot; } -private: - bool diagnose(); - bool visit(); - bool parse(); - void tokenize(CXFile file, uint32_t fileId, const Path &path); - bool writeFiles(const Path &root, String &error); - - void addFileSymbol(uint32_t file); - int symbolLength(CXCursorKind kind, const CXCursor &cursor); - void extractArguments(List *arguments, const CXCursor &cursor); - CXCursor resolveTemplate(CXCursor cursor, Location location = Location(), bool *specialized = 0); - static CXCursor resolveTypedef(CXCursor cursor); - - // DiagnosticsProvider - using RTags::DiagnosticsProvider::createLocation; - virtual Location createLocation(const Path &file, unsigned int line, unsigned int col, bool *blocked = 0) override; - virtual CXTranslationUnit unit(size_t u) const override; - virtual size_t unitCount() const override - { - return mTranslationUnits.size(); - } - virtual size_t diagnosticCount(size_t unit) const override - { - if (CXTranslationUnit u = mTranslationUnits[unit]->unit) { - return clang_getNumDiagnostics(u); - } - return 0; - } - virtual CXDiagnostic diagnostic(size_t unit, size_t idx) const override - { - assert(mTranslationUnits[unit]->unit); - return clang_getDiagnostic(mTranslationUnits[unit]->unit, idx); - } - - virtual uint32_t sourceFileId() const override { return mSources.front().fileId; } - virtual IndexDataMessage &indexDataMessage() override { return mIndexDataMessage; } - - String addNamePermutations(const CXCursor &cursor, - Location location, - RTags::CursorType cursorType); - - CXChildVisitResult handleCursor(const CXCursor &cursor, CXCursorKind kind, - Location location, Symbol **cursorPtr = 0); - bool handleReference(const CXCursor &cursor, CXCursorKind kind, - Location loc, CXCursor reference, - Symbol **cursorPtr = 0); - void handleBaseClassSpecifier(const CXCursor &cursor); - void handleInclude(const CXCursor &cursor, CXCursorKind kind, Location location); - void handleLiteral(const CXCursor &cursor, CXCursorKind kind, Location location); - CXChildVisitResult handleStatement(const CXCursor &cursor, CXCursorKind kind, Location location); - Location findByUSR(const CXCursor &cursor, CXCursorKind kind, Location loc) const; - std::unordered_set addOverriddenCursors(const CXCursor &cursor, Location location); - bool superclassTemplateMemberFunctionUgleHack(const CXCursor &cursor, CXCursorKind kind, - Location location, const CXCursor &ref, - Symbol **cursorPtr = 0); - void visit(CXCursor cursor) - { - mParents.append(cursor); - clang_visitChildren(cursor, visitorHelper, this); - mParents.removeLast(); - } - CXChildVisitResult indexVisitor(CXCursor cursor); - static CXChildVisitResult visitorHelper(CXCursor cursor, CXCursor, CXClientData userData); - static CXChildVisitResult verboseVisitor(CXCursor cursor, CXCursor, CXClientData userData); - static CXChildVisitResult resolveAutoTypeRefVisitor(CXCursor cursor, CXCursor, CXClientData data); - - void onMessage(const std::shared_ptr &msg, const std::shared_ptr &conn); - - struct Unit { - Map symbols; - Map > targets; - Map > usrs; - Map > symbolNames; - Map tokens; - }; - - std::shared_ptr &unit(uint32_t fileId) - { - std::shared_ptr &unit = mUnits[fileId]; - if (!unit) { - unit.reset(new Unit); - } - return unit; - } - std::shared_ptr unit(Location loc) { return unit(loc.fileId()); } - - enum FindResult { - Found, - NotIndexed, - NotFound - }; - Symbol findSymbol(Location location, FindResult *result) const; - - struct MacroLocationData { - Set arguments; - List locations; - }; - struct MacroData { - List arguments; - Map data; - }; - Map mMacroTokens; - - Hash > mUnits; - - Path mProject; - SourceList mSources; - Path mSourceFile; - IndexDataMessage mIndexDataMessage; - List > mTranslationUnits; - size_t mCurrentTranslationUnit; - CXCursor mLastCursor; - Symbol *mLastCallExprSymbol; - Location mLastClass; - uint32_t mVisitFileResponseMessageFileId; - bool mVisitFileResponseMessageVisit; - Path mSocketFile; - StopWatch mTimer; - int mParseDuration, mVisitDuration, mBlocked, mAllowed, - mIndexed, mVisitFileTimeout, mIndexDataMessageTimeout, - mFileIdsQueried, mFileIdsQueriedTime, mCursorsVisited; - UnsavedFiles mUnsavedFiles; - List mDebugLocations; - FILE *mLogFile; - std::shared_ptr mConnection; - Path mDataDir; - bool mUnionRecursion; - - struct Scope { - enum ScopeType { - FunctionDefinition, - FunctionDeclaration, - Other - }; - ScopeType type; - Symbol *symbol; - Location start, end; - }; - List mScopeStack; - - struct Loop { // or switch - CXCursorKind kind; - Location start, end; - }; - List mLoopStack; - - std::shared_ptr mSerializeTU; - List mParents; - std::unordered_set mTemplateSpecializations; - size_t mInTemplateFunction; - - static Flags sServerOpts; - static Path sServerSandboxRoot; -}; - -#endif diff --git a/rtags/src/ClangThread.cpp b/rtags/src/ClangThread.cpp deleted file mode 100644 index 0e09bce..0000000 --- a/rtags/src/ClangThread.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "ClangThread.h" -#include "rct/Connection.h" -#include "RTags.h" -#include "Server.h" -#ifdef RTAGS_HAS_LUA -#include "AST.h" -#endif - -struct Dep : public DependencyNode -{ - Dep(uint32_t f) - : DependencyNode(f) - {} - Hash > references; -}; - -ClangThread::ClangThread(const std::shared_ptr &queryMessage, - const Source &source, const std::shared_ptr &conn) - : Thread(), mQueryMessage(queryMessage), mSource(source), - mConnection(conn), mIndentLevel(0), mAborted(false) -{ - setAutoDelete(true); -} - -ClangThread::~ClangThread() -{ -} - -CXChildVisitResult ClangThread::visitor(CXCursor cursor, CXCursor, CXClientData userData) -{ - ClangThread *that = reinterpret_cast(userData); - assert(that); - return that->visit(cursor); -} - -CXChildVisitResult ClangThread::visit(const CXCursor &cursor) -{ - if (isAborted()) - return CXChildVisit_Break; - const Location location = RTags::createLocation(cursor); - if (!location.isNull()) { - if (mQueryMessage->flags() & QueryMessage::DumpCheckIncludes) { - checkIncludes(location, cursor); - } else { - Flags locationFlags; - if (mQueryMessage->flags() & QueryMessage::NoColor) - locationFlags |= Location::NoColor; - - CXSourceRange range = clang_getCursorExtent(cursor); - CXSourceLocation rangeEnd = clang_getRangeEnd(range); - unsigned int endLine, endColumn; - clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); - if (!(mQueryMessage->flags() & QueryMessage::DumpIncludeHeaders) && location.fileId() != mSource.fileId) { - return CXChildVisit_Continue; - } - - String message; - message.reserve(256); - - if (!(mQueryMessage->flags() & QueryMessage::NoContext)) { - message = location.context(locationFlags, &mContextCache); - } - - if (endLine == location.line()) { - message += String::format<32>(" // %d-%d, %d: ", location.column(), endColumn, mIndentLevel); - } else { - message += String::format<32>(" // %d-%d:%d, %d: ", location.column(), endLine, endColumn, mIndentLevel); - } - message += RTags::cursorToString(cursor, RTags::AllCursorToStringFlags); - message.append(" " + RTags::typeName(cursor));; - if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { - RTags::Auto autoResolved; - if (RTags::resolveAuto(cursor, &autoResolved) && RTags::isValid(autoResolved.cursor)) { - message += "auto resolves to " + RTags::cursorToString(autoResolved.cursor, RTags::AllCursorToStringFlags); - } - } - auto printCursor = [&message](const CXCursor &c, bool *spec = 0) { - CXCursor canonical = clang_getCanonicalCursor(c); - if (canonical != c && RTags::isValid(canonical)) { - message.append(" canonical "); - message.append(RTags::cursorToString(canonical, RTags::AllCursorToStringFlags)); - } - - CXCursor specialized = clang_getSpecializedCursorTemplate(c); - if (specialized != c && RTags::isValid(specialized)) { - message.append(" specialized "); - message.append(RTags::cursorToString(specialized, RTags::AllCursorToStringFlags)); - if (spec) - *spec = true; - } else if (spec) { - *spec = false; - } - }; - - CXCursor ref = clang_getCursorReferenced(cursor); - bool refSpecialized = false; - if (RTags::isValid(ref) && ref != cursor) { - message.append("refs "); - message.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags)); - printCursor(ref, &refSpecialized); - if (refSpecialized && cursor != CXCursor_DeclRefExpr && cursor != CXCursor_MemberRefExpr) - refSpecialized = false; - } - - printCursor(cursor); - - writeToConnetion(message); - if (refSpecialized && false) { - visit(ref); - } - } - } - ++mIndentLevel; - clang_visitChildren(cursor, ClangThread::visitor, this); - if (isAborted()) - return CXChildVisit_Break; - --mIndentLevel; - return CXChildVisit_Continue; -} - -void ClangThread::run() -{ - StopWatch sw; - const auto key = mConnection->disconnected().connect([this](const std::shared_ptr &) { abort(); }); - - String sourceCode = mSource.sourceFile().readAll(); - CXUnsavedFile unsaved = { - mSource.sourceFile().constData(), - sourceCode.constData(), - static_cast(sourceCode.size()) - }; - - - std::shared_ptr translationUnit = RTags::TranslationUnit::create(mSource.sourceFile(), - mSource.toCommandLine(Source::Default), - &unsaved, 1, CXTranslationUnit_DetailedPreprocessingRecord, - false); - - const unsigned long long parseTime = sw.restart(); - warning() << "parseTime" << parseTime; -#ifdef RTAGS_HAS_LUA - if (mQueryMessage->type() == QueryMessage::VisitAST) { - std::shared_ptr ast = AST::create(mSource, sourceCode, translationUnit->unit); - if (ast) { - for (const String script : mQueryMessage->visitASTScripts()) { - warning() << "evaluating script:\n" << script; - for (const String &str : ast->evaluate(script)) { - if (!str.isEmpty()) { - writeToConnetion(str); - } - } - } - } - } else -#endif - { - if (mQueryMessage->type() == QueryMessage::DumpFile && mQueryMessage->flags() & QueryMessage::DumpCheckIncludes) - writeToConnetion(String::format<128>("Indexed: %s => %s", translationUnit->clangLine.constData(), translationUnit ? "success" : "failure")); - - if (translationUnit) { - clang_visitChildren(clang_getTranslationUnitCursor(translationUnit->unit), ClangThread::visitor, this); - if (mQueryMessage->flags() & QueryMessage::DumpCheckIncludes) - checkIncludes(); - } - } - - - mConnection->disconnected().disconnect(key); - std::weak_ptr conn = mConnection; - EventLoop::mainEventLoop()->callLater([conn]() { - if (auto c = conn.lock()) - c->finish(); - }); -} - -void ClangThread::writeToConnetion(const String &message) -{ - std::weak_ptr conn = mConnection; - EventLoop::mainEventLoop()->callLater([conn, message]() { - if (auto c = conn.lock()) { - c->write(message); - } - }); -} - -void ClangThread::handleInclude(Location loc, const CXCursor &cursor) -{ - CXFile includedFile = clang_getIncludedFile(cursor); - if (includedFile) { - CXStringScope fn = clang_getFileName(includedFile); - const char *cstr = clang_getCString(fn); - if (!cstr) { - clang_disposeString(fn); - return; - } - const Path p = Path::resolved(cstr); - clang_disposeString(fn); - const uint32_t fileId = Location::insertFile(p); - Dep *&source = mDependencies[loc.fileId()]; - if (!source) - source = new Dep(loc.fileId()); - Dep *&include = mDependencies[fileId]; - if (!include) - include = new Dep(fileId); - source->include(include); - } -} - -void ClangThread::handleReference(Location loc, const CXCursor &ref) -{ - if (clang_getCursorKind(ref) == CXCursor_Namespace) - return; - const Location refLoc = RTags::createLocation(ref); - if (refLoc.isNull() || refLoc.fileId() == loc.fileId()) - return; - - Dep *dep = mDependencies[loc.fileId()]; - assert(dep); - Dep *refDep = mDependencies[refLoc.fileId()]; - assert(refDep); - auto &refs = dep->references[refDep->fileId]; - refs[loc] = refLoc; -} - -void ClangThread::checkIncludes(Location location, const CXCursor &cursor) -{ - if (clang_getCursorKind(cursor) == CXCursor_InclusionDirective) { - handleInclude(location, cursor); - } else { - const CXCursor ref = clang_getCursorReferenced(cursor); - if (RTags::isValid(cursor) && cursor != ref) { - handleReference(location, ref); - } - } -} - -static bool validateHasInclude(uint32_t ref, const Dep *cur, Set &seen) -{ - assert(ref); - assert(cur); - if (cur->includes.contains(ref)) - return true; - if (!seen.insert(ref)) - return false; - for (const auto &pair : cur->includes) { - if (validateHasInclude(ref, static_cast(pair.second), seen)) - return true; - } - return false; -} - -static bool validateNeedsInclude(const Dep *source, const Dep *header, Set &seen) -{ - if (!seen.insert(header->fileId)) { - // error() << "already seen" << Location::path(source->fileId); - return false; - } - if (source->references.contains(header->fileId)) { - // error() << "Got ref" << Location::path(header->fileId); - return true; - } - for (const auto &child : header->includes) { - // error() << "Checking child" << Location::path(child.second->fileId); - if (validateNeedsInclude(source, static_cast(child.second), seen)) { - return true; - } - } - - // error() << "Checking" << Location::path(source->fileId) << "doesn't seem to need" << Location::path(header->fileId) << depth; - return false; -} - -void ClangThread::checkIncludes() -{ - for (const auto &it : mDependencies) { - const Path path = Location::path(it.first); - if (path.isSystem()) - continue; - - for (const auto &dep : it.second->includes) { - Set seen; - if (!validateNeedsInclude(it.second, static_cast(dep.second), seen)) { - writeToConnetion(String::format<128>("%s includes %s for no reason", - path.constData(), - Location::path(dep.second->fileId).constData())); - } - } - - continue; // the rest of this doeesn't really work that well. - - for (const auto &ref : it.second->references) { - const Path refPath = Location::path(ref.first); - if (refPath.startsWith("/usr/include/sys/_types/_") || refPath.startsWith("/usr/include/_types/_")) - continue; - Set seen; - if (!validateHasInclude(ref.first, it.second, seen)) { - List reasons; - for (const auto &r : ref.second) { - String reason; - Log log(&reason); - log << r.first << "=>" << r.second; - reasons << reason; - } - writeToConnetion(String::format<128>("%s should include %s (%s)", - Location::path(it.first).constData(), - Location::path(ref.first).constData(), - String::join(reasons, " ").constData())); - // for (const auto &incs : mDependencies[ref.first]->dependents) { - // writeToConnetion(String::format<128>("GOT INCLUDER %s:%d", Location::path(incs.first).constData(), - // incs.first)); - // } - } - } - } - - for (auto it : mDependencies) { - delete it.second; - } -} diff --git a/rtags/src/ClangThread.h b/rtags/src/ClangThread.h deleted file mode 100644 index f349129..0000000 --- a/rtags/src/ClangThread.h +++ /dev/null @@ -1,59 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef ClangThread_h -#define ClangThread_h - -#include - -#include "Project.h" -#include "QueryMessage.h" -#include "rct/Thread.h" -#include "rct/Value.h" -#include "Source.h" - -class Connection; -struct Dep; -class ClangThread : public Thread -{ -public: - ClangThread(const std::shared_ptr &queryMessage, - const Source &source, - const std::shared_ptr &conn); - ~ClangThread() override; - virtual void run() override; - void abort() { std::unique_lock lock(mMutex); mAborted = false; } - bool isAborted() const { std::unique_lock lock(mMutex); return mAborted; } -private: - static CXChildVisitResult visitor(CXCursor cursor, CXCursor, CXClientData userData); - CXChildVisitResult visit(const CXCursor &cursor); - void checkIncludes(Location location, const CXCursor &cursor); - - void writeToConnetion(const String &message); - void handleInclude(Location loc, const CXCursor &cursor); - void handleReference(Location loc, const CXCursor &ref); - void checkIncludes(); - - const std::shared_ptr mQueryMessage; - const Source mSource; - std::shared_ptr mConnection; - int mIndentLevel; - mutable std::mutex mMutex; - Hash mDependencies; - Hash mContextCache; - bool mAborted; -}; - -#endif diff --git a/rtags/src/ClassHierarchyJob.cpp b/rtags/src/ClassHierarchyJob.cpp deleted file mode 100644 index 8e77333..0000000 --- a/rtags/src/ClassHierarchyJob.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "ClassHierarchyJob.h" - -#include "Project.h" -#include "RTags.h" -#include "Server.h" - -ClassHierarchyJob::ClassHierarchyJob(Location loc, - const std::shared_ptr &query, - const std::shared_ptr &project) - : QueryJob(query, project), location(loc) -{ -} - -int ClassHierarchyJob::execute() -{ - Symbol symbol = project()->findSymbol(location); - if (symbol.isNull()) - return 1; - if (!symbol.isClass() || !symbol.isDefinition()) - symbol = project()->findTarget(symbol.location); - if (!symbol.isClass()) - return 1; - - typedef std::function(const Symbol &)> FindFunc; - std::function recurse = [&](const Symbol &sym, - const char *title, - int indent, - FindFunc find) - { - auto classes = find(sym); - if (!indent) { - if (classes.isEmpty()) { - return; - } - write(title); - indent = 2; - write<256>(" %s\t%s", - sym.symbolName.constData(), - sym.location.toString(locationToStringFlags()).constData()); - } else { - write<256>("%s%s\t%s", - String(indent, ' ').constData(), - sym.symbolName.constData(), - sym.location.toString(locationToStringFlags()).constData()); - } - for (const Symbol &c : classes) { - recurse(c, title, indent + 2, find); - } - }; - - recurse(symbol, "Superclasses:", 0, [this](const Symbol &sym) { - Set ret; - for (const String &usr : sym.baseClasses) { - for (const auto &s : project()->findByUsr(usr, sym.location.fileId(), Project::ArgDependsOn)) { - if (s.isDefinition()) { - ret.insert(s); - break; - } - } - } - return ret; - }); - recurse(symbol, "Subclasses:", 0, [this](const Symbol &sym) { return project()->findSubclasses(sym); }); - return 0; -} diff --git a/rtags/src/ClassHierarchyJob.h b/rtags/src/ClassHierarchyJob.h deleted file mode 100644 index 079abc9..0000000 --- a/rtags/src/ClassHierarchyJob.h +++ /dev/null @@ -1,32 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef ClassHierarchyJob_h -#define ClassHierarchyJob_h - -#include "Location.h" -#include "QueryJob.h" - -class ClassHierarchyJob : public QueryJob -{ -public: - ClassHierarchyJob(Location loc, const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - const Location location; -}; - -#endif diff --git a/rtags/src/CommandLineParser.h b/rtags/src/CommandLineParser.h deleted file mode 100644 index 8a0e72a..0000000 --- a/rtags/src/CommandLineParser.h +++ /dev/null @@ -1,316 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef CommandLineParser_h -#define CommandLineParser_h - -namespace CommandLineParser { -enum ValueType { - Required, - Optional, - NoValue -}; -template -struct Option { - const T option; - const String longOpt; - const char shortOpt; - ValueType valueType; - const String description; -}; -enum Status { - Parse_Exec, - Parse_Ok, - Parse_Error -}; - -struct ParseStatus { - String error; - Status status; -}; -enum Flag { - NoFlag = 0x0, - IgnoreUnknown = 0x1 -}; - -enum ConfigOptionType { - ConfigNone = 0, - Config, - NoRc -}; - -RCT_FLAGS(Flag); -template -ParseStatus parse(int argc, char **argv, - std::initializer_list > optsList, - Flags flags, - const std::function &args)> &handler, - const String &app = String(), - std::initializer_list > configOpts = std::initializer_list >(), - String *cmdLine = 0) -{ - Hash *> longOpts; - Hash *> shortOpts; - for (const auto &opt : optsList) { - if (!opt.longOpt.isEmpty()) - longOpts[opt.longOpt] = &opt; - if (opt.shortOpt) - shortOpts[opt.shortOpt] = &opt; - } - if (getenv("RTAGS_DUMP_UNUSED")) { - String unused; - for (int i=0; i<26; ++i) { - if (!shortOpts.contains('a' + i)) - unused.append('a' + i); - if (!shortOpts.contains('A' + i)) - unused.append('A' + i); - } - printf("Unused: %s\n", unused.constData()); - for (const auto &opt : optsList) { - if (!opt.longOpt.isEmpty()) { - if (!opt.shortOpt) { - printf("No shortoption for %s\n", opt.longOpt.constData()); - } else if (opt.longOpt[0] != opt.shortOpt) { - printf("Not ideal option for %s|%c\n", opt.longOpt.constData(), opt.shortOpt); - } - } - } - return { String(), Parse_Ok }; - } - - List args; - if (configOpts.size() && !app.isEmpty()) { - bool norc = false; - Path rcfile = Path::home() + "." + app + "rc"; - if (!rcfile.exists()) { - const char * configPath = getenv("XDG_CONFIG_DIR"); - rcfile = configPath ? configPath : Path::home() + ".config"; - rcfile += "/rtags/"; - rcfile.mkdir(Path::Recursive); - rcfile += app + "rc"; - } - parse(argc, argv, configOpts, - IgnoreUnknown, [&norc, &rcfile](ConfigOptionType type, String &&value, size_t &, const List &) -> ParseStatus { - switch (type) { - case ConfigNone: { - assert(0); - break; } - case Config: { - rcfile = std::move(value); - break; } - case NoRc: { - norc = true; - break; } - } - return { String(), Parse_Exec }; - }); - if (!norc) { - args.push_back(argv[0]); - String rc = Path("/etc/rcrc").readAll(); - if (!rc.isEmpty()) { - for (const String &s : rc.split('\n')) { - if (!s.isEmpty() && !s.startsWith('#')) - args += s.split(' '); - } - } - if (!rcfile.isEmpty()) { - rc = rcfile.readAll(); - if (!rc.isEmpty()) { - for (const String& s : rc.split('\n')) { - if (!s.isEmpty() && !s.startsWith('#')) - args += s.split(' '); - } - } - } - for (int i=1; iappend(' '); - } - const bool space = arg.contains(' '); - if (space) - cmdLine->append('"'); - cmdLine->append(arg); - if (space) - cmdLine->append('"'); - } - } - - ParseStatus status = { String(), Parse_Exec }; - for (size_t i=1; i *> opts; - String value; - auto addArg = [&arg, &opts, &status, flags](const Option *opt) -> bool { - if (opt) { - opts.append(opt); - return true; - } - if (flags & IgnoreUnknown) - return true; - - status = { String::format<1024>("Couldn't parse argument %s", arg.constData()), Parse_Error }; - return false; - }; - if (arg == "--") { - addArg(longOpts.value("--")); - } else if (arg.startsWith("--")) { - const size_t eq = arg.indexOf('='); - String a; - if (eq == String::npos) { - a = arg.mid(2); - } else { - a = arg.mid(2, eq - 2); - value = arg.mid(eq + 1); - } - addArg(longOpts.value(a)); - } else if (arg.startsWith("-")) { - for (size_t j=1; j 1 && !opts.isEmpty() && opts.back()->valueType != NoValue) { - if (arg.at(j) == '=') - ++j; - value = arg.mid(j); - break; - } - - addArg(shortOpts.value(arg.at(j))); - } - } else { - addArg(0); - } - - for (const Option *opt : opts) { - switch (opt->valueType) { - case Required: - if (value.isEmpty() && i + 1 < args.size()) - value = args.at(++i); - status = handler(opt->option, std::move(value), i, args); - break; - case Optional: - if (value.isEmpty() && i + 1 < args.size() && (!args.at(i + 1).startsWith('-') || args.at(i + 1).size() == 1)) - value = args.at(++i); - status = handler(opt->option, std::move(value), i, args); - break; - case NoValue: - status = handler(opt->option, String(), i, args); - break; - } - if (status.status != Parse_Exec) - break; - } - if (status.status != Parse_Exec) - break; - } - return status; -} - -template -static void help(FILE *f, const char *app, std::initializer_list > optsList) -{ - List out; - size_t longest = 0; - for (const auto &opt : optsList) { - if (opt.longOpt.isEmpty() && !opt.shortOpt) { - out.append(String()); - } else { - out.append(String::format<64>(" %s%s%s%s", - (opt.longOpt.isEmpty() ? String() : ("--" + opt.longOpt)).constData(), - !opt.longOpt.isEmpty() && opt.shortOpt ? "|" : "", - opt.shortOpt ? String::format<2>("-%c", opt.shortOpt).constData() : "", - opt.valueType == Required ? " [arg] " - : opt.valueType == Optional ? " [optional] " : "")); - longest = std::max(out.back().size(), longest); - } - } - fprintf(f, "%s options...\n", app); - const Option *opts = optsList.begin(); - const size_t c = out.size(); - for (size_t i=0; i -static void man(std::initializer_list > optsList) -{ - const Option *opts = optsList.begin(); - String out = ("\n" - "\n" - "\n" - "\n" - "\n" - "\n" - " rc file.1.xml > file.1\n" - "\n" - "\n" - "\n" - "\n" - "

rc is a command line client used to control RTags.

\n" - "\n" - "
\n"); - for (size_t i=0; i\n"); - out.append(String::format<128>("
\n", opts[i].description.constData())); - } else { - out.append(String::format<64>(" \n", - (opts[i].longOpt.isEmpty() ? String() : ("--" + opts[i].longOpt)).constData(), - !opts[i].longOpt.isEmpty() && opts[i].shortOpt ? "|" : "", - opts[i].shortOpt ? String::format<2>("-%c", opts[i].shortOpt).constData() : "", - opts[i].valueType == Required ? " [arg] " : opts[i].valueType == Optional ? " [optional] " : "", - opts[i].description.constData())); - } - } - } - out.append("
\n" - "
\n" - "

RTags was written by Jan Erik Hanssen <jhanssen@gmail.com> and Anders Bakken <abakken@gmail.com>

\n" - "
\n" - "
\n" - "

\n" - "
\n" - "
\n" - "

This man page was written using .

\n" - "
\n" - "
\n"); - printf("%s", out.constData()); -} -} - -#endif diff --git a/rtags/src/CompilerManager.cpp b/rtags/src/CompilerManager.cpp deleted file mode 100644 index 7ecf791..0000000 --- a/rtags/src/CompilerManager.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "CompilerManager.h" - -#include "rct/Log.h" -#include "rct/Process.h" -#include "Source.h" - -static std::mutex sMutex; -struct Compiler { - Compiler() - : inited(false) - {} - bool inited; - - // There are three include-path-limiting options: - // 1. -nostdinc -- disables all default system include paths - // Example: (stuff under /usr/include, etc.) - // 2. -nostdinc++ -- disables C++ standard include path - // Example: (stuff under /usr/lib/c++/v1) - // 3. -nobuiltininc -- (clang only?) disables compiler-provided includes - // Example: limits.h, float.h - - Set defines; - List includePaths; - List stdincxxPaths; - List builtinPaths; -}; -static Hash sCompilers; - -namespace CompilerManager { - -List compilers() -{ - std::lock_guard lock(sMutex); - return sCompilers.keys(); -} - -void applyToSource(Source &source, Flags flags) -{ - std::lock_guard lock(sMutex); - Path cpath = source.compiler(); - Compiler &compiler = sCompilers[cpath]; - if (!compiler.inited) { - compiler.inited = true; - - List overrides; - List out, err; - List args; - List environ({"RTAGS_DISABLED=1"}); - args << "-x" << "c++" << "-v" << "-E" << "-dM" << "-"; - - for (int i=0; i<4; /* see below */) { - Process proc; - proc.exec(cpath, args, environ); - assert(proc.isFinished()); - if (!proc.returnCode()) { - out << proc.readAllStdOut().split('\n'); - err << proc.readAllStdErr().split('\n'); - - // proc success. What's next? - switch (i) { - case 0: - // C++ ok .. see which path is controlled by -nostdinc++ - args.prepend("-nostdinc++"); - err << "@@@@\n"; // magic separator - i = 2; - break; - - case 1: - // "-x c++" not ok. Goto -nobuiltininc. - err << "@@@@\n"; // magic separator - args.prepend("-nobuiltininc"); - i = 3; - break; - - case 2: - args.removeFirst(); // clear -nostdinc++ - err << "@@@@\n"; // magic separator - args.prepend("-nobuiltininc"); - i = 3; - break; - - default: - err << "@@@@\n"; // magic separator - i = 4; - break; - } - } else if (i == 0) { - // Strip -x c++ and try again - args.removeFirst(); - args.removeFirst(); - i = 1; - } else if (i == 3) { - // GCC does not support -nobuiltininc flag. - // Remove and retry - args.removeFirst(); - } else { - error() << "CompilerManager: Cannot extract standard include paths.\n"; - return; - } - } - for (size_t i=0; i copy; - for (size_t i=0; i. */ - -#ifndef CompilerManager_h -#define CompilerManager_h - -#include "rct/List.h" -#include "rct/Path.h" -#include "rct/Serializer.h" -#include "rct/Flags.h" - -struct Source; - -namespace CompilerManager -{ -List compilers(); -enum Flag { - None = 0x0, - IncludeDefines = 0x1, - IncludeIncludePaths = 0x2 -}; -RCT_FLAGS(Flag); -void applyToSource(Source &source, Flags flags); -} - -#endif diff --git a/rtags/src/CompletionThread.cpp b/rtags/src/CompletionThread.cpp deleted file mode 100644 index 13629d8..0000000 --- a/rtags/src/CompletionThread.cpp +++ /dev/null @@ -1,748 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "CompletionThread.h" -#include "IndexDataMessage.h" -#include "Project.h" - -#include "rct/StopWatch.h" -#include "RTags.h" -#include "RTagsLogOutput.h" -#include "Server.h" - -#include -#include -#include "rct/StringTokenizer.h" -#ifdef HAS_JSON_H -#include "rct/json/json.hpp" -using namespace nlohmann; -#endif - -static uint64_t start = 0; -#define LOG() \ - if (Server::instance()->options().options & Server::CompletionLogs) \ - error() << "CODE COMPLETION" << String::format<16>("%gs", static_cast(Rct::monoMs() - ::start) / 1000.0) - - -CompletionThread::CompletionThread(int cacheSize) - : mShutdown(false), mCacheSize(cacheSize), mDump(0) -{ -} - -CompletionThread::~CompletionThread() -{ - mCacheList.deleteAll(); -} - -void CompletionThread::run() -{ - while (true) { - Request *request = 0; - Dump *dump = 0; - { - std::unique_lock lock(mMutex); - while (!mShutdown && mPending.isEmpty() && !mDump) { - mCondition.wait(lock); - } - if (mShutdown) { - for (auto it = mPending.begin(); it != mPending.end(); ++it) { - delete *it; - } - mPending.clear(); - if (mDump) { - std::unique_lock dumpLock(mDump->mutex); - mDump->done = true; - mDump->cond.notify_one(); - mDump = 0; - } - break; - } else if (mDump) { - std::swap(dump, mDump); - } else { - assert(!mPending.isEmpty()); - request = mPending.takeFirst(); - } - } - if (dump) { - std::unique_lock lock(dump->mutex); - Log out(&dump->string); - for (SourceFile *cache = mCacheList.first(); cache; cache = cache->next) { - out << cache->source - << "\nparseTime:" << cache->parseTime - << "\nreparseTime:" << cache->reparseTime - << "\ncompletions:" << cache->completions - << "\ncompletionTime:" << cache->codeCompleteTime - << (cache->completions - ? String::format<32>("(avg: %.2f)", - (static_cast(cache->codeCompleteTime) / cache->completions)) - : String()) - << "\ntranslationUnit:" << cache->translationUnit << "\n"; - } - dump->done = true; - dump->cond.notify_one(); - } else { - assert(request); - process(request); - delete request; - } - } -} - -void CompletionThread::completeAt(Source &&source, Location location, - Flags flags, String &&unsaved, - const String &prefix, - const std::shared_ptr &conn) -{ - if (Server::instance()->options().options & Server::CompletionLogs) - error() << "CODE COMPLETION completeAt" << location << flags; - Request *request = new Request({ std::forward(source), location, flags, std::forward(unsaved), prefix, conn}); - std::unique_lock lock(mMutex); - auto it = mPending.begin(); - while (it != mPending.end()) { - if ((*it)->source == source) { - delete *it; - mPending.erase(it); - break; - } - ++it; - } - mPending.push_front(request); - mCondition.notify_one(); -} - -void CompletionThread::prepare(Source &&source, String &&unsaved) -{ - if (Server::instance()->options().options & Server::CompletionLogs) - error() << "CODE COMPLETION prepare" << source.sourceFile() << unsaved.size(); - std::unique_lock lock(mMutex); - for (auto req : mPending) { - if (req->source == source) { - req->unsaved = std::move(unsaved); - return; - } - } - Request *request = new Request({ std::forward(source), Location(), WarmUp, std::forward(unsaved), String(), std::shared_ptr() }); - mPending.push_back(request); - mCondition.notify_one(); -} - -String CompletionThread::dump() -{ - Dump dump; - dump.done = false; - { - std::unique_lock lock(mMutex); - if (mDump) - return String(); // dump in progress - - mDump = &dump; - mCondition.notify_one(); - } - std::unique_lock lock(dump.mutex); - while (!dump.done) { - dump.cond.wait(lock); - } - return std::move(dump.string); -} - -void CompletionThread::stop() -{ - std::unique_lock lock(mMutex); - mShutdown = true; - mCondition.notify_one(); -} - -bool CompletionThread::compareCompletionCandidates(const Completions::Candidate *l, - const Completions::Candidate *r) -{ - if (l->priority != r->priority) - return l->priority < r->priority; -#ifdef RTAGS_COMPLETION_TOKENS_ENABLED - if ((l->distance != -1) != (r->distance != -1)) - return l->distance != -1; - if (l->distance != r->distance) - return l->distance > r->distance; -#endif - return l->completion < r->completion; -} - -void CompletionThread::process(Request *request) -{ - ::start = Rct::monoMs(); - LOG() << "processing" << request->toString(); - StopWatch sw; - int parseTime = 0; - int reparseTime = 0; - int completeTime = 0; - int processTime = 0; - mMutex.lock(); - SourceFile *&cache = mCacheMap[request->source.fileId]; - - if (cache && cache->source != request->source) { - LOG() << "cached sourcefile doesn't match source, discarding" << request->source.sourceFile(); - delete cache; - cache = 0; - } - if (!cache) { - cache = new SourceFile; - LOG() << "creating source file for" << request->source.sourceFile(); - mCacheList.append(cache); - while (mCacheMap.size() > mCacheSize) { - SourceFile *c = mCacheList.removeFirst(); - LOG() << "over cache limit. discarding" << c->source.sourceFile(); - mCacheMap.remove(c->source.fileId); - delete c; - } - } else { - mCacheList.moveToEnd(cache); - } - mMutex.unlock(); - - assert(!cache->translationUnit || cache->source == request->source); - if (!cache->translationUnit) { - cache->source = request->source; - } - - const Path sourceFile = request->source.sourceFile(); - CXUnsavedFile unsaved = { - sourceFile.constData(), - request->unsaved.constData(), - static_cast(request->unsaved.size()) - }; - - const auto &options = Server::instance()->options(); - bool reparse = false; - if (!cache->translationUnit) { - if (request->conn && request->flags & NoWait) { - request->flags |= WarmUp; - if (request->flags & Elisp) { - request->conn->finish("(list (cons 'pending t))"); - } else if (request->flags & XML) { - request->conn->finish(""); - } else if (request->flags & JSON) { - request->conn->finish("{\"pending\":true}"); - } else { - request->conn->finish("pending"); - } - request->conn.reset(); - } - LOG() << "No translationUnit for" << request->source.sourceFile() << "recreating"; - sw.restart(); - Flags flags = static_cast(clang_defaultEditingTranslationUnitOptions()); - flags |= CXTranslationUnit_CacheCompletionResults; - flags |= CXTranslationUnit_DetailedPreprocessingRecord; - flags |= CXTranslationUnit_Incomplete; - flags |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - flags |= CXTranslationUnit_PrecompiledPreamble; -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 32) - flags |= CXTranslationUnit_CreatePreambleOnFirstParse; -#endif - for (const auto &inc : options.includePaths) { - request->source.includePaths << inc; - } - request->source.defines << options.defines; - - cache->translationUnit = RTags::TranslationUnit::create(sourceFile, - request->source.toCommandLine(Source::Default|Source::ExcludeDefaultArguments), - &unsaved, request->unsaved.size() ? 1 : 0, flags, true); - // error() << "PARSING" << clangLine; - parseTime = cache->parseTime = sw.elapsed(); - // with clang 3.8 it definitely seems like we have to reparse once to - // generate the preamble. Even with CXTranslationUnit_CreatePreambleOnFirstParse - if (!cache->translationUnit) { - LOG() << "Failed to parse translation unit" << request->source.sourceFile(); - return; - } - reparse = true; - } else if (!request->unsaved.isEmpty()) { - reparse = request->unsaved != cache->unsaved; - cache->lastModified = 0; - } else { - const uint64_t lastModified = request->source.sourceFile().lastModifiedMs(); - if (lastModified != cache->lastModified) { - cache->lastModified = lastModified; - cache->unsaved.clear(); - reparse = true; - } else { - assert(cache->unsaved.isEmpty()); - } - } - - LOG() << "line: " << request->location.line() << "column: " - << request->location.column() << ", prefix: " - << request->prefix; - - if (reparse) { - sw.restart(); - assert(cache->translationUnit); - LOG() << "reparsing translation unit" << request->source.sourceFile(); - cache->translationUnit->reparse(&unsaved, request->unsaved.size() ? 1 : 0); - reparseTime = cache->reparseTime = sw.elapsed(); - cache->unsaved = std::move(request->unsaved); - } - - - if (request->flags & WarmUp) { - LOG() << "Warmed up unit" << request->source.sourceFile(); - return; - } - - sw.restart(); - unsigned int completionFlags = (CXCodeComplete_IncludeCodePatterns|CXCodeComplete_IncludeBriefComments); - if (request->flags & IncludeMacros) - completionFlags |= CXCodeComplete_IncludeMacros; - - CXCodeCompleteResults *results = clang_codeCompleteAt(cache->translationUnit->unit, sourceFile.constData(), - request->location.line(), request->location.column(), - &unsaved, unsaved.Length ? 1 : 0, completionFlags); - completeTime = cache->codeCompleteTime = sw.restart(); - LOG() << "Generated" << (results ? results->NumResults : 0) << "completions for" << request->location << (results ? "successfully" : "unsuccessfully") << "in" << completeTime << "ms"; - - ++cache->completions; - if (results) { - List candidates; - candidates.reserve(results->NumResults); - - int nodeCount = 0; -#ifdef RTAGS_COMPLETION_TOKENS_ENABLED - Map tokens; - if (!request->unsaved.isEmpty()) { - tokens = Token::tokenize(request->unsaved.constData(), request->unsaved.size()); - // for (Map::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { - // error() << String(it->first.data, it->first.length) << it->second; - // } - } -#endif - for (unsigned int i = 0; i < results->NumResults; ++i) { - const CXCursorKind kind = results->Results[i].CursorKind; - const CXCompletionString &string = results->Results[i].CompletionString; - - const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); - if (!(options.options & Server::CompletionsNoFilter)) { - switch (availabilityKind) { - case CXAvailability_Available: - break; - case CXAvailability_Deprecated: - break; - case CXAvailability_NotAccessible: - break; - case CXAvailability_NotAvailable: // protected members are erroneously flagged as NotAvailable in clang 3.6 - continue; - } - } - - const int priority = clang_getCompletionPriority(string); - - CompletionCandidate *candidate = new CompletionCandidate; - candidate->kind = RTags::eatString(clang_getCursorKindSpelling(kind)); - candidate->priority = priority; - candidate->parent = RTags::eatString(clang_getCompletionParent(string, 0)); - candidate->brief_comment = RTags::eatString(clang_getCompletionBriefComment(string)); - - candidates.push_back(candidate); - - bool ok = true; - const int chunkCount = clang_getNumCompletionChunks(string); - for (int j=0; jname = text; - if (candidate->name.isEmpty()) { - ok = false; - break; - } - candidate->signature += candidate->name; - } else { - candidate->signature += text; - if (chunkKind == CXCompletionChunk_ResultType) - candidate->signature += ' '; - } - } - - if (ok) { - const unsigned int annotations = clang_getCompletionNumAnnotations(string); - for (unsigned j=0; jannotation.isEmpty()) - candidate->annotation += ' '; - candidate->annotation + cstr; - } - } - } - } - - List > matches = StringTokenizer::find_and_sort_matches(candidates, request->prefix); - - if (!matches.isEmpty()) { - printCompletions(matches, request); - processTime = sw.elapsed(); - LOG() << "Sent" << matches.size() << "completions for" << request->location; - warning("Processed %s, parse %d/%d, complete %d, process %d => %d completions (unsaved %zu)", - request->location.toString().constData(), - parseTime, reparseTime, completeTime, processTime, nodeCount, request->unsaved.size()); - - } else { - LOG() << "No completions available for" << request->location; - printCompletions(List >(), request); - error() << "No completion results available" << request->location; - } - - processDiagnostics(request, results, cache->translationUnit->unit); - clang_disposeCodeCompleteResults(results); - } -} - -Value CompletionThread::Completions::Candidate::toValue(unsigned int f) const -{ - Value ret; - if (!completion.isEmpty()) - ret["completion"] = completion; - if (!signature.isEmpty()) - ret["signature"] = signature; - if (!annotation.isEmpty()) - ret["annotation"] = annotation; - if (!parent.isEmpty()) - ret["parent"] = parent; - if (!briefComment.isEmpty()) - ret["briefComment"] = briefComment; - ret["priority"] = priority; -#ifdef RTAGS_COMPLETION_TOKENS_ENABLED - ret["distance"] = distance; -#endif - String str; - str << cursorKind; - ret["kind"] = str; - if (f & IncludeChunks && !chunks.isEmpty()) { - Value cc; - cc.arrayReserve(chunks.size()); - for (const auto &chunk : chunks) { - Value c; - c["text"] = chunk.text; - String kind; - kind << chunk.kind; - c["kind"] = kind; - cc.push_back(c); - } - ret["chunks"] = cc; - } - return ret; -} - -struct Output -{ - void send(const String &string) - { - if (connection) { - connection->write(string); - connection->finish(); - } else { - output->log(string.constData()); - } - } - std::shared_ptr output; - std::shared_ptr connection; - Flags flags; -}; - -void CompletionThread::printCompletions(const List > &results, Request *request) -{ - static List cursorKindNames; - // error() << request->flags << testLog(RTags::DiagnosticsLevel) << completions.size() << request->conn; - List > outputs; - bool xml = false; - bool elisp = false; - bool raw = false; -#ifdef HAS_JSON_H - bool send_json = false; - json j = {{"completions", json::array()}}; -#endif - if (request->conn) { - auto output = std::make_shared(); - output->connection = request->conn; - output->flags = request->flags; - outputs.append(output); - if (request->flags & Elisp) { - elisp = true; - } else if (request->flags & XML) { - xml = true; -#ifdef HAS_JSON_H - } else if (request->flags & JSON) { - send_json = true; -#endif - } else { - raw = true; - } - request->conn.reset(); - } else { - log([&](const std::shared_ptr &output) { - // error() << "Got a dude" << output->testLog(RTags::DiagnosticsLevel); - if (output->testLog(RTags::DiagnosticsLevel)) { - auto out = std::make_shared(); - out->output = output; - if (output->flags() & RTagsLogOutput::Elisp) { - out->flags |= CompletionThread::Elisp; - elisp = true; - } else if (output->flags() & RTagsLogOutput::XML) { - out->flags |= CompletionThread::XML; - xml = true; -#ifdef HAS_JSON_H - } else if (output->flags() & RTagsLogOutput::JSON) { - out->flags |= CompletionThread::JSON; - send_json = true; -#endif - } else { - raw = true; - } - outputs.append(out); - } - }); - } - - if (!outputs.isEmpty()) { - String rawOut, xmlOut, elispOut; -#ifdef HAS_JSON_H - String jsonOut; -#endif - if (raw) - rawOut.reserve(16384); - if (xml) { - xmlOut.reserve(16384); - xmlOut += String::format<128>("location.toString(Location::AbsolutePath).constData()); - } - if (elisp) { - elispOut.reserve(16384); - elispOut << String::format<256>("(list 'completions (list \"%s\" (list", - RTags::elispEscape(request->location.toString(Location::AbsolutePath)).constData()); - } - for (const std::unique_ptr &result : results) { - CompletionCandidate *c = result->candidate; - const String str = String::format<128>(" %s %s %s %s %s %s\n", - c->name.c_str(), - c->signature.c_str(), - c->kind.c_str(), - c->annotation.c_str(), - c->parent.c_str(), - c->brief_comment.c_str()); - - - if (xml || raw) - if (raw) - rawOut += str; - if (xml) - xmlOut += str; -#ifdef HAS_JSON_H - if (send_json) { - j["completions"] += { - {"completion", c->name}, - {"signature", c->signature}, - {"kind", c->kind}, - {"parent", c->parent}, - {"brief_comment", c->brief_comment}, - {"annotation", c->annotation}, - {"priority", c->priority} - }; - } -#endif - if (elisp) { - elispOut += String::format<128>(" (list \"%s\" \"%s\" \"%s\" \"%s\")", - RTags::elispEscape(c->name).constData(), - RTags::elispEscape(c->signature).constData(), - c->kind.c_str(), - RTags::elispEscape(c->brief_comment).constData()); - //, - // RTags::elispEscape(val->annotation).constData(), - // val->parent.constData(), - // val->briefComment.constData()); - } - } - if (elisp) - elispOut += ")))"; - if (xml) - xmlOut += "]]>\n"; -#ifdef HAS_JSON_H - if (send_json) - jsonOut = j.dump(4); -#endif - - EventLoop::mainEventLoop()->callLater([outputs, xmlOut, elispOut, rawOut -#ifdef HAS_JSON_H - , jsonOut -#endif - ]() { - for (auto &it : outputs) { - if (it->flags & Elisp) { - it->send(elispOut); - } else if (it->flags & XML) { - it->send(xmlOut); -#ifdef HAS_JSON_H - } else if (it->flags & JSON) { - it->send(jsonOut); -#endif - } else { - it->send(rawOut); - } - } - }); - } -} - -bool CompletionThread::isCached(uint32_t fileId, const std::shared_ptr &project) const -{ - std::unique_lock lock(mMutex); - for (SourceFile *file : mCacheList) { - if (file->source.fileId == fileId || project->dependsOn(file->source.fileId, fileId)) - return true; - } - return false; -} - - -String CompletionThread::Request::toString() const -{ - String ret = location.toString(Location::NoColor); - if (!unsaved.isEmpty()) { - ret += String::format<64>(" - Unsaved: %zu", unsaved.size()); - } - - struct { - const char *name; - const Flag flag; - } const f[] = { - { "Elisp", Elisp }, - { "XML", XML }, - { "JSON", JSON }, - { "IncludeMacros", IncludeMacros }, - { "WarmUp", WarmUp }, - }; - - for (const auto &flag : f) { - if (flags & flag.flag) { - ret += String::format<64>(" - %s", flag.name); - } - } - - if (!unsaved.isEmpty() && !location.isNull()) { - int line = location.line(); - int pos = 0; - while (line > 1) { - int p = unsaved.indexOf('\n', pos); - if (p == -1) { - pos = -1; - break; - } - pos = p + 1; - --line; - } - if (pos != -1) { - int end = unsaved.indexOf('\n', pos); - if (end == -1) - end = unsaved.size(); - ret += String::format<1024>(" - Completing at %s:%d:%d line: [%s]", - location.path().constData(), - location.line(), - location.column(), - unsaved.mid(pos, end - pos).constData()); - } - } - - return ret; -} - -Source CompletionThread::findSource(const Set &deps) const -{ - std::unique_lock lock(mMutex); - for (SourceFile *sourceFile = mCacheList.first(); sourceFile; sourceFile = sourceFile->next) { - if (deps.contains(sourceFile->source.fileId)) { - return sourceFile->source; - } - } - return Source(); -} - -class CompletionDiagnostics : public RTags::DiagnosticsProvider -{ -public: - CompletionDiagnostics(uint32_t sourceFileId, uint32_t completionFileId, CXCodeCompleteResults *results, CXTranslationUnit unit) - : mSourceFileId(sourceFileId), mResults(results), mUnit(unit) - { - mIndexDataMessage.files()[completionFileId] = IndexDataMessage::Visited; - } - - virtual size_t unitCount() const override - { - return 1; - } - - virtual size_t diagnosticCount(size_t) const override - { - return clang_codeCompleteGetNumDiagnostics(mResults); - } - - virtual CXDiagnostic diagnostic(size_t, size_t idx) const override - { - return clang_codeCompleteGetDiagnostic(mResults, idx); - } - - virtual Location createLocation(const Path &file, unsigned int line, unsigned int col, bool *blocked = 0) override - { - if (blocked) - *blocked = false; - return Location(Location::insertFile(file), line, col); - } - - virtual uint32_t sourceFileId() const override - { - return mSourceFileId; - } - - virtual IndexDataMessage &indexDataMessage() override - { - return mIndexDataMessage; - } - - virtual CXTranslationUnit unit(size_t) const override - { - return mUnit; - } - - const uint32_t mSourceFileId; - CXCodeCompleteResults *const mResults; - CXTranslationUnit const mUnit; - IndexDataMessage mIndexDataMessage; -}; - -void CompletionThread::processDiagnostics(const Request *request, CXCodeCompleteResults *results, CXTranslationUnit unit) -{ - assert(request); - std::shared_ptr project = Server::instance()->currentProject(); - if (!project) { - return; - } - const uint32_t sourceFileId = request->source.fileId; - if (!project->hasSource(sourceFileId)) { - return; - } - LOG() << "processing diagnostics" << clang_codeCompleteGetNumDiagnostics(results) - << clang_getNumDiagnostics(unit) << request->location << Location::path(request->source.fileId); - CompletionDiagnostics diag(sourceFileId, request->location.fileId(), results, unit); - diag.diagnose(); - // error() << "got diagnostics" << diag.indexDataMessage().diagnostics().size(); - Project::FileMapScopeScope scope(project); - project->updateDiagnostics(sourceFileId, diag.indexDataMessage().diagnostics()); -} diff --git a/rtags/src/CompletionThread.h b/rtags/src/CompletionThread.h deleted file mode 100644 index d00d56d..0000000 --- a/rtags/src/CompletionThread.h +++ /dev/null @@ -1,207 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef CompletionThread_h -#define CompletionThread_h - -#include -#include -#include -#include - -#include "Location.h" -#include "rct/Connection.h" -#include "rct/EmbeddedLinkedList.h" -#include "rct/Flags.h" -#include "rct/LinkedList.h" -#include "rct/Map.h" -#include "rct/Thread.h" -#include "Source.h" -#include "RTags.h" - -struct MatchResult; -class CompletionThread : public Thread -{ -public: - CompletionThread(int cacheSize); - ~CompletionThread(); - - virtual void run() override; - enum Flag { - None = 0x00, - Elisp = 0x01, - XML = 0x02, - JSON = 0x04, - IncludeMacros = 0x08, - WarmUp = 0x10, - NoWait = 0x20 - }; - bool isCached(uint32_t fileId, const std::shared_ptr &project) const; - void completeAt(Source &&source, Location location, Flags flags, - String &&unsaved, const String &prefix, - const std::shared_ptr &conn); - void prepare(Source &&source, String &&unsaved); - Source findSource(const Set &deps) const; - void stop(); - String dump(); -private: - struct Request; - void processDiagnostics(const Request *request, CXCodeCompleteResults *results, CXTranslationUnit unit); - void process(Request *request); - - Set mWatched; - bool mShutdown; - const size_t mCacheSize; - struct Request { - ~Request() - { - if (conn) - conn->finish(); - } - String toString() const; - Source source; - Location location; - Flags flags; - String unsaved, prefix; - std::shared_ptr conn; - }; - LinkedList mPending; - struct Dump { - bool done; - std::mutex mutex; - std::condition_variable cond; - String string; - } *mDump; - - struct Completions { - Completions(Location loc) : location(loc), next(0), prev(0) {} - struct Candidate { - String completion, signature, annotation, parent, briefComment; - int priority = 0; -#ifdef RTAGS_COMPLETION_TOKENS_ENABLED - int distance = 0; -#endif - CXCursorKind cursorKind; - struct Chunk { - Chunk() - : kind(CXCompletionChunk_Optional) - {} - Chunk(String &&t, CXCompletionChunkKind k) - : text(std::forward(t)), kind(k) - {} - String text; - CXCompletionChunkKind kind; - }; - List chunks; - - enum Flag { - None = 0x0, - IncludeChunks = 0x1 - }; - Value toValue(unsigned int flags) const; - }; - - List candidates; - const Location location; - Flags flags; - Completions *next, *prev; - }; - - void printCompletions(const List > &results, Request *request); - static bool compareCompletionCandidates(const Completions::Candidate *l, - const Completions::Candidate *r); - - struct SourceFile { - SourceFile() - : lastModified(0), parseTime(0), reparseTime(0), codeCompleteTime(0), completions(0), next(0), prev(0) - {} - std::shared_ptr translationUnit; - String unsaved; - uint64_t lastModified; - uint64_t parseTime, reparseTime, codeCompleteTime; // ms - size_t completions; - Source source; - SourceFile *next, *prev; - }; - -#ifdef RTAGS_COMPLETION_TOKENS_ENABLED - struct Token - { - Token(const char *bytes = 0, int size = 0) - : data(bytes), length(size) - {} - - inline bool operator==(const Token &other) const - { - return length == other.length && !strncmp(data, other.data, length); - } - inline bool operator<(const Token &other) const - { - if (!data) - return !other.data ? 0 : -1; - if (!other.data) - return 1; - const int minLength = std::min(length, other.length); - int ret = memcmp(data, other.data, minLength); - if (!ret) { - if (length < other.length) { - ret = -1; - } else if (other.length < length) { - ret = 1; - } - } - return ret; - } - - const char *data; - int length; - - static inline Map tokenize(const char *data, int size) - { - Map tokens; - int tokenEnd = -1; - for (int i=size - 1; i>=0; --i) { - if (RTags::isSymbol(data[i])) { - if (tokenEnd == -1) - tokenEnd = i; - } else if (tokenEnd != -1) { - addToken(data, i + 1, tokenEnd - i, tokens); - tokenEnd = -1; - } - } - if (tokenEnd != -1) - addToken(data, 0, tokenEnd + 1, tokens); - return tokens; - } - private: - static inline void addToken(const char *data, int pos, int len, Map &tokens) - { - int &val = tokens[Token(data + pos, len)]; - if (!val) - val = pos; - } - }; -#endif - - Hash mCacheMap; - EmbeddedLinkedList mCacheList; - - mutable std::mutex mMutex; - std::condition_variable mCondition; -}; - -RCT_FLAGS(CompletionThread::Flag); - -#endif diff --git a/rtags/src/DependenciesJob.cpp b/rtags/src/DependenciesJob.cpp deleted file mode 100644 index f533813..0000000 --- a/rtags/src/DependenciesJob.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "DependenciesJob.h" - -#include "FileManager.h" -#include "Project.h" -#include "QueryMessage.h" -#include "RTags.h" -#include "Server.h" - -DependenciesJob::DependenciesJob(const std::shared_ptr &query, const std::shared_ptr &project) - : QueryJob(query, project, QuietJob) -{ - Deserializer deserializer(query->query()); - Path path; - deserializer >> path >> mArgs; - mFileId = Location::fileId(path); -} - -int DependenciesJob::execute() -{ - std::shared_ptr proj = project(); - if (!proj) - return 2; - write(proj->dumpDependencies(mFileId, mArgs, queryFlags())); - return 0; -} diff --git a/rtags/src/DependenciesJob.h b/rtags/src/DependenciesJob.h deleted file mode 100644 index 9d2465c..0000000 --- a/rtags/src/DependenciesJob.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef DependenciesJob_h -#define DependenciesJob_h - -#include "QueryJob.h" - - -class Project; -class QueryMessage; -class DependenciesJob : public QueryJob -{ -public: - DependenciesJob(const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - uint32_t mFileId; - List mArgs; -}; - -#endif diff --git a/rtags/src/Diagnostic.h b/rtags/src/Diagnostic.h deleted file mode 100644 index 4500adb..0000000 --- a/rtags/src/Diagnostic.h +++ /dev/null @@ -1,99 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef Diagnostic_h -#define Diagnostic_h - -#include "rct/Serializer.h" -#include "rct/String.h" -#include "Location.h" -#include "Sandbox.h" - -struct Diagnostic; -typedef Map Diagnostics; - -struct Diagnostic -{ - enum Flag { - None = 0x00, - Warning = 0x01, - Error = 0x02, - Fixit = 0x04, - Note = 0x08, - Skipped = 0x10, - Type_Mask = Warning|Error|Fixit|Note|Skipped, - TemplateOnly = 0x20, - DisplayCategory = 0x40 - }; - - Diagnostic() - : length(-1), sourceFileId(0) - { - } - - Flag type() const; - - String message; - int length; - uint32_t sourceFileId; - - Map ranges; - Diagnostics children; - Flags flags; - bool isNull() const { return type() == None; } - - bool operator==(const Diagnostic &other) const - { - return (message == other.message - && length == other.length - && sourceFileId == other.sourceFileId - && ranges == other.ranges - && children == other.children - && flags == other.flags); - } - - bool operator!=(const Diagnostic &other) const - { - return !operator==(other); - } -}; - -RCT_FLAGS(Diagnostic::Flag); - -inline Diagnostic::Flag Diagnostic::type() const -{ - return Flags(flags & Type_Mask).cast(); -} - -template <> inline Serializer &operator<<(Serializer &s, const Diagnostic &d) -{ - // SBROOT - String tmessage = Sandbox::encoded(d.message); - s << d.flags.cast() << tmessage << d.length << d.sourceFileId << d.ranges << d.children; - return s; -} - -template <> inline Deserializer &operator>>(Deserializer &s, Diagnostic &d) -{ - uint8_t flags; - String tmessage; - s >> flags >> tmessage >> d.length >> d.sourceFileId >> d.ranges >> d.children; - // SBROOT - d.message = Sandbox::decoded(std::move(tmessage)); - d.flags = static_cast(flags); - return s; -} - -#endif diff --git a/rtags/src/FileManager.cpp b/rtags/src/FileManager.cpp deleted file mode 100644 index a172315..0000000 --- a/rtags/src/FileManager.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "FileManager.h" - -#include "Filter.h" -#include "Project.h" -#include "ScanThread.h" -#include "Server.h" - -FileManager::FileManager(const std::shared_ptr &project) - : mProject(project), mLastReloadTime(0) -{ -} - -void FileManager::load(Mode mode) -{ - if (!Server::instance()->options().tests.isEmpty()) - mode = Synchronous; - - mLastReloadTime = Rct::monoMs(); - std::shared_ptr project = mProject.lock(); - assert(project); - if (mode == Asynchronous) { - startScanThread(); - } else { - const Set paths = ScanThread::paths(project->path()); - onRecurseJobFinished(paths); - } -} - -void FileManager::onRecurseJobFinished(const Set &paths) -{ - std::lock_guard lock(mMutex); // ### is this needed now? - - std::shared_ptr project = mProject.lock(); - if (!project) - return; - Files &map = project->files(); - map.clear(); - clearFileSystemWatcher(); - for (Set::const_iterator it = paths.begin(); it != paths.end(); ++it) { - const Path parent = it->parentDir(); - if (parent.isEmpty()) { - error() << "Got empty parent here" << *it; - continue; - } - assert(!parent.isEmpty()); - Set &dir = map[parent]; - if (dir.isEmpty()) { - watch(parent); - // error() << "Watching parent" << parent; - } - dir.insert(it->fileName()); - } - assert(!map.contains(Path())); -} - -void FileManager::onFileAdded(const Path &path) -{ - debug() << "fm file added" << path; - std::lock_guard lock(mMutex); - if (path.isEmpty()) { - return; - } - const Filter::Result res = Filter::filter(path); - switch (res) { - case Filter::Directory: - watch(path); - load(Asynchronous); - return; - case Filter::Filtered: - return; - default: - break; - } - - std::shared_ptr project = mProject.lock(); - assert(project); - Files &map = project->files(); - const Path parent = path.parentDir(); - if (!parent.isEmpty()) { - Set &dir = map[parent]; - watch(parent); - dir.insert(path.fileName()); - } else { - error() << "Got empty parent here" << path; - load(Asynchronous); - } - assert(!map.contains(Path())); -} - -void FileManager::onFileRemoved(const Path &path) -{ - debug() << "fm file removed" << path; - std::lock_guard lock(mMutex); - std::shared_ptr project = mProject.lock(); - if (!project) - return; - Files &map = project->files(); - if (!map.remove(path)) { - const Path parent = path.parentDir(); - if (map.contains(parent)) { - Set &dir = map[parent]; - dir.remove(String(path.fileName())); - if (dir.isEmpty()) { - project->unwatch(parent, Project::Watch_FileManager); - map.remove(parent); - } - } - } -} - -static inline bool startsWith(const Path &left, const Path &right) -{ - assert(!left.isEmpty()); - return !right.isEmpty() && left.startsWith(right); -} - -bool FileManager::contains(const Path &path) const -{ - std::lock_guard lock(mMutex); - std::shared_ptr proj = mProject.lock(); - if (!proj) - return false; - if (startsWith(path, proj->path())) - return true; - const Path p = Path::resolved(path); - if (p != path && startsWith(path, proj->path())) - return true; - return false; -} - -void FileManager::watch(const Path &path) -{ - if (Server::instance()->options().options & Server::NoFileManagerWatch) - return; - if (path.contains("/.git/") || path.contains("/.svn/") || path.contains("/.cvs/")) { - return; // more source control systems? - } - if (auto proj = mProject.lock()) { - proj->watch(path, Project::Watch_FileManager); - } -} - -void FileManager::startScanThread() -{ - std::shared_ptr project = mProject.lock(); - assert(project); - ScanThread *thread = new ScanThread(project->path()); - thread->setAutoDelete(true); - std::weak_ptr that = shared_from_this(); - thread->finished().connect([that](const Set &paths) { - if (auto strong = that.lock()) - strong->onRecurseJobFinished(paths); - }); - - thread->start(); -} - -void FileManager::clearFileSystemWatcher() -{ - if (auto project = mProject.lock()) - project->clearWatch(Project::Watch_FileManager); -} diff --git a/rtags/src/FileManager.h b/rtags/src/FileManager.h deleted file mode 100644 index 6b53867..0000000 --- a/rtags/src/FileManager.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef FileManager_h -#define FileManager_h - -#include - -#include "rct/Path.h" -#include "rct/Timer.h" - -class Project; -class FileManager : public std::enable_shared_from_this -{ -public: - FileManager(const std::shared_ptr &project); - enum Mode { - Synchronous, - Asynchronous - }; - - void load(Mode mode); - uint64_t lastReloadTime() const { return mLastReloadTime; } - void onFileAdded(const Path &path); - void onFileRemoved(const Path &path); - void onRecurseJobFinished(const Set &mPaths); - bool contains(const Path &path) const; - void clearFileSystemWatcher(); -private: - void startScanThread(); - void watch(const Path &path); - std::weak_ptr mProject; - uint64_t mLastReloadTime; - mutable std::mutex mMutex; -}; - -#endif diff --git a/rtags/src/FileMap.h b/rtags/src/FileMap.h deleted file mode 100644 index b2d0e5b..0000000 --- a/rtags/src/FileMap.h +++ /dev/null @@ -1,314 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef FileMap_h -#define FileMap_h - -#include -#include -#include -#include -#include -#include -#include - -#include "Location.h" -#include "rct/Serializer.h" - -template inline static int compare(const T &l, const T &r) -{ - if (l < r) - return -1; - if (l > r) - return 1; - return 0; -} - -template <> inline int compare(const String &l, const String &r) -{ - return l.compare(r); -} - -template <> inline int compare(const Location &l, const Location &r) -{ - return l.compare(r); -} - -template -class FileMap -{ -public: - FileMap() - : mPointer(0), mSize(0), mCount(0), mValuesOffset(0), mFD(-1), mOptions(0) - {} - - ~FileMap() - { - if (mFD != -1) { - assert(mPointer); - munmap(const_cast(mPointer), mSize); - if (!(mOptions & NoLock)) - lock(mFD, Unlock); - int ret; - eintrwrap(ret, close(mFD)); - } - } - - void init(const char *pointer, uint32_t size) - { - mPointer = pointer; - mSize = size; - memcpy(&mCount, mPointer, sizeof(uint32_t)); - memcpy(&mValuesOffset, mPointer + sizeof(uint32_t), sizeof(uint32_t)); - } - - enum Options { - None = 0x0, - NoLock = 0x1 - }; - bool load(const Path &path, uint32_t options, String *error = 0) - { - eintrwrap(mFD, open(path.constData(), O_RDONLY)); - if (mFD == -1) { - if (error) { - *error = Rct::strerror(); - *error << " " << __LINE__; - } - return false; - } - if (!(options & NoLock) && !lock(mFD, Read)) { - if (error) { - *error = Rct::strerror(); - *error << " " << __LINE__; - } - - close(mFD); - mFD = -1; - return false; - } - - struct stat st; - if (fstat(mFD, &st)) { - if (error) { - *error = Rct::strerror(); - *error << " " << __LINE__; - } - lock(mFD, Unlock); - int ret; - eintrwrap(ret, close(mFD)); - mFD = -1; - return false; - } - - const char *pointer = static_cast(mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, mFD, 0)); - // error() << errno;// << mPointer; - if (pointer == MAP_FAILED) { - if (error) { - *error = Rct::strerror(); - *error << " " << __LINE__; - } - lock(mFD, Unlock); - int ret; - eintrwrap(ret, close(mFD)); - mFD = -1; - return false; - } - - mOptions = options; - init(pointer, st.st_size); - return true; - } - - Value value(const Key &key, bool *matched = 0) const - { - bool match; - const uint32_t idx = lowerBound(key, &match); - // error() << "value" << idx << key << match; - if (matched) - *matched = match; - if (match) - return valueAt(idx); - return Value(); - } - - uint32_t count() const { return mCount; } - - Key keyAt(uint32_t index) const - { - assert(index >= 0 && index < mCount); - return read(keysSegment(), index); - } - - Value valueAt(uint32_t index) const - { - assert(index >= 0 && index < mCount); - return read(valuesSegment(), index); - } - - uint32_t lowerBound(const Key &k, bool *match = 0) const - { - if (!mCount) { - if (match) - *match = false; - return std::numeric_limits::max(); - - } - int lower = 0; - int upper = mCount - 1; - - do { - const int mid = lower + ((upper - lower) / 2); - const int cmp = compare(k, keyAt(mid)); - if (cmp < 0) { - upper = mid - 1; - } else if (cmp > 0) { - lower = mid + 1; - } else { - if (match) - *match = true; - return mid; - } - } while (lower <= upper); - - if (lower == static_cast(mCount)) - lower = std::numeric_limits::max(); - if (match) - *match = false; - return lower; - } - - static String encode(const Map &map) - { - String out; - Serializer serializer(out); - serializer << static_cast(map.size()); - uint32_t valuesOffset; - if (uint32_t size = FixedSize::value) { - valuesOffset = ((static_cast(map.size()) * size) + (sizeof(uint32_t) * 2)); - serializer << valuesOffset; - for (const std::pair &pair : map) { - out.append(reinterpret_cast(&pair.first), size); - } - } else { - serializer << static_cast(0); // values offset - uint32_t offset = sizeof(uint32_t) * 2 + (map.size() * sizeof(uint32_t)); - String keyData; - Serializer keySerializer(keyData); - for (const std::pair &pair : map) { - const uint32_t pos = offset + keyData.size(); - out.append(reinterpret_cast(&pos), sizeof(pos)); - keySerializer << pair.first; - } - out.append(keyData); - valuesOffset = out.size(); - memcpy(out.data() + sizeof(uint32_t), &valuesOffset, sizeof(valuesOffset)); - } - assert(valuesOffset == static_cast(out.size())); - - if (uint32_t size = FixedSize::value) { - for (const std::pair &pair : map) { - out.append(reinterpret_cast(&pair.second), size); - } - } else { - const uint32_t encodedValuesOffset = valuesOffset + (sizeof(uint32_t) * map.size()); - String valueData; - Serializer valueSerializer(valueData); - for (const std::pair &pair : map) { - const uint32_t pos = encodedValuesOffset + valueData.size(); - out.append(reinterpret_cast(&pos), sizeof(pos)); - valueSerializer << pair.second; - } - out.append(valueData); - - } - return out; - } - static size_t write(const Path &path, const Map &map, uint32_t options) - { - int fd = open(path.constData(), O_RDWR|O_CREAT, 0644); - if (fd == -1) { - if (!Path::mkdir(path.parentDir(), Path::Recursive)) - return 0; - fd = open(path.constData(), O_RDWR|O_CREAT, 0644); - if (fd == -1) - return 0; - } - if (!(options & NoLock) && !lock(fd, Write)) { - ::close(fd); - return 0; - } - const String data = encode(map); - bool ok = ::ftruncate(fd, data.size()) != -1; - if (!ok) { - if (!(options & NoLock)) - lock(fd, Unlock); - ::close(fd); - return 0; - } - - ok = ::write(fd, data.constData(), data.size()) == static_cast(data.size()); - if (!(options & NoLock)) - ok = lock(fd, Unlock) && ok; - - ::close(fd); - if (!ok) - unlink(path.constData()); - return ok ? data.size() : 0; - } -private: - enum Mode { - Read = F_RDLCK, - Write = F_WRLCK, - Unlock = F_UNLCK - }; - static bool lock(int fd, Mode mode) - { - struct flock fl; - memset(&fl, 0, sizeof(fl)); - fl.l_type = mode; - fl.l_whence = SEEK_SET; - fl.l_pid = getpid(); - int ret; - eintrwrap(ret, fcntl(fd, F_SETLKW, &fl)); - return ret != -1; - } - const char *valuesSegment() const { return mPointer + mValuesOffset; } - const char *keysSegment() const { return mPointer + (sizeof(uint32_t) * 2); } - - template - inline T read(const char *base, uint32_t index) const - { - if (const uint32_t size = FixedSize::value) { - T t = T(); - memcpy(&t, base + (index * size), FixedSize::value); - return t; - } - uint32_t offset; - memcpy(&offset, base + (sizeof(uint32_t) * index), sizeof(offset)); - Deserializer deserializer(mPointer + offset, INT_MAX); - T t; - deserializer >> t; - return t; - } - - const char *mPointer; - uint32_t mSize; - uint32_t mCount; - uint32_t mValuesOffset; - int mFD; - uint32_t mOptions; -}; - -#endif diff --git a/rtags/src/Filter.h b/rtags/src/Filter.h deleted file mode 100644 index 1d7a492..0000000 --- a/rtags/src/Filter.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef Filter_h -#define Filter_h - -#include - -#include "rct/List.h" -#include "rct/Path.h" -#include "rct/String.h" - -namespace Filter { -enum Result { - Filtered, - File, - Source, - Directory -}; - -static inline Result filter(const Path &path, const List &filters = List()) -{ - const int size = filters.size(); - for (int i=0; i. */ - -#include "FindFileJob.h" - -#include "FileManager.h" -#include "Project.h" -#include "rct/SignalSlot.h" -#include "RTags.h" -#include "Server.h" - -static Flags flags(Flags queryFlags) -{ - Flags flags = QueryJob::QuietJob; - if (queryFlags & QueryMessage::Elisp) - flags |= QueryJob::QuoteOutput; - return flags; -} - -FindFileJob::FindFileJob(const std::shared_ptr &query, const std::shared_ptr &project) - : QueryJob(query, project, ::flags(query->flags())) -{ - const String q = query->query(); - if (!q.isEmpty()) { - if (query->flags() & QueryMessage::MatchRegex) { - mRegex = q.ref(); - } else { - mPattern = q; - } - } -} - -int FindFileJob::execute() -{ - std::shared_ptr proj = project(); - if (!proj) { - return 1; - } - if (!proj->fileManager()) - return 1; - const Path srcRoot = proj->path(); - assert(srcRoot.endsWith('/')); - - enum Mode { - All, - FilePath, - Regex, - Pattern, - } mode = All; - - String::CaseSensitivity cs = String::CaseSensitive; - if (queryFlags() & QueryMessage::MatchRegex) { - mode = Regex; - } else if (!mPattern.isEmpty()) { - mode = mPattern[0] == '/' ? FilePath : Pattern; - } - if (queryFlags() & QueryMessage::MatchCaseInsensitive) - cs = String::CaseInsensitive; - - String out; - out.reserve(PATH_MAX); - const bool absolutePath = queryFlags() & QueryMessage::AbsolutePath; - if (absolutePath) - out.append(srcRoot); - const Files& dirs = proj->files(); - assert(proj->fileManager()); - if (dirs.isEmpty()) - proj->fileManager()->load(FileManager::Synchronous); - Files::const_iterator dirit = dirs.begin(); - bool foundExact = false; - const int patternSize = mPattern.size(); - List matches; - const bool preferExact = queryFlags() & QueryMessage::FindFilePreferExact; - int ret = 1; - bool firstElisp = queryFlags() & QueryMessage::Elisp; - - auto writeFile = [this, &firstElisp](const Path &path) { - if (firstElisp) { - firstElisp = false; - if (!write("(list", DontQuote)) - return false; - } - return write(path); - }; - while (dirit != dirs.end()) { - const Path &dir = dirit->first; - if (dir.size() < srcRoot.size()) { - continue; - } else { - out.append(dir.constData() + srcRoot.size(), dir.size() - srcRoot.size()); - } - - const Set &files = dirit->second; - for (Set::const_iterator it = files.begin(); it != files.end(); ++it) { - const String &key = *it; - out.append(key); - bool ok = false; - switch (mode) { - case All: - ok = true; - break; - case Regex: - ok = Rct::contains(out, mRegex); - break; - case FilePath: - case Pattern: - if (!preferExact) { - ok = out.contains(mPattern, cs); - } else { - const int outSize = out.size(); - const bool exact = (outSize > patternSize && out.endsWith(mPattern) && out.at(outSize - (patternSize + 1)) == '/'); - if (exact) { - ok = true; - if (!foundExact) { - matches.clear(); - foundExact = true; - } - } else { - ok = !foundExact && out.contains(mPattern, cs); - } - } - if (!ok && mode == FilePath) { - Path p(out); - if (!absolutePath) - p.prepend(srcRoot); - p.resolve(); - if (p == mPattern) - ok = true; - } - break; - } - if (ok) { - ret = 0; - - Path matched = out; - if (absolutePath) - matched.resolve(); - if (preferExact && !foundExact) { - matches.append(matched); - } else { - if (!writeFile(matched)) - return 1; - } - } - out.chop(key.size()); - } - out.chop(dir.size() - srcRoot.size()); - ++dirit; - } - for (List::const_iterator it = matches.begin(); it != matches.end(); ++it) { - if (!writeFile(*it)) { - return 1; - } - } - if (queryFlags() & QueryMessage::Elisp && !firstElisp && !write(")", DontQuote)) - return 1; - return ret; -} diff --git a/rtags/src/FindFileJob.h b/rtags/src/FindFileJob.h deleted file mode 100644 index 13805de..0000000 --- a/rtags/src/FindFileJob.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef FindFileJob_h -#define FindFileJob_h - -#include - -#include "QueryJob.h" -#include "rct/String.h" - -class FindFileJob : public QueryJob -{ -public: - FindFileJob(const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - String mPattern; - std::regex mRegex; -}; - -#endif diff --git a/rtags/src/FindSymbolsJob.cpp b/rtags/src/FindSymbolsJob.cpp deleted file mode 100644 index 3f32884..0000000 --- a/rtags/src/FindSymbolsJob.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "FindSymbolsJob.h" - -#include "Project.h" -#include "QueryMessage.h" -#include "rct/Log.h" -#include "RTags.h" -#include "Server.h" - -static inline Flags jobFlags(Flags queryFlags) -{ - return (queryFlags & QueryMessage::Elisp - ? Flags(QueryJob::QuoteOutput|QueryJob::QuietJob) - : Flags(QueryJob::QuietJob)); -} - -FindSymbolsJob::FindSymbolsJob(const std::shared_ptr &query, const std::shared_ptr &proj) - : QueryJob(query, proj, ::jobFlags(query->flags())), string(query->query()) -{ -} - -int FindSymbolsJob::execute() -{ - int ret = 2; - if (std::shared_ptr proj = project()) { - Set symbols; - auto inserter = [proj, this, &symbols](Project::SymbolMatchType type, - const String &symbolName, - const Set &locations) { - if (type == Project::StartsWith) { - const size_t paren = symbolName.indexOf('('); - if (paren == String::npos || paren != string.size() || RTags::isFunctionVariable(symbolName)) - return; - } - for (const auto &it : locations) { - const Symbol sym = proj->findSymbol(it); - if (!sym.isNull() || sym.flags & Symbol::FileSymbol) - symbols.insert(sym); - } - }; - proj->findSymbols(string, inserter, queryFlags(), fileFilter()); - if (!symbols.isEmpty()) { - const List sorted = proj->sort(symbols, queryFlags()); - const Flags writeFlags = fileFilter() ? Unfiltered : NoWriteFlags; - const int count = sorted.size(); - ret = count ? 0 : 1; - for (int i=0; i. */ - -#ifndef FindSymbolsJob_h -#define FindSymbolsJob_h - -#include "QueryJob.h" -#include "rct/String.h" - -class QueryMessage; -class FindSymbolsJob : public QueryJob -{ -public: - FindSymbolsJob(const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - const String string; -}; - -#endif diff --git a/rtags/src/FixIt.h b/rtags/src/FixIt.h deleted file mode 100644 index b7e3383..0000000 --- a/rtags/src/FixIt.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef FixIt_h -#define FixIt_h - -#include - -#include "rct/Serializer.h" -#include "rct/String.h" - -struct FixIt -{ - inline FixIt(uint32_t l = 0, uint32_t c = 0, uint32_t len = 0, const String &t = String()) - : line(l), column(c), length(len), text(t) - { - } - inline bool operator<(const FixIt &other) const - { - if (line < other.line) - return true; - if (line > other.line) - return false; - if (column < other.column) - return true; - if (column > other.column) - return false; - return length < other.length; - } - inline bool operator==(const FixIt &other) const - { - return (line == other.line && column == other.column && length == other.length && text == other.text); - } - - uint32_t line, column, length; - String text; -}; - -template <> inline Serializer &operator<<(Serializer &s, const FixIt &f) -{ - s << f.line << f.column << f.length << f.text; - return s; -} - -template <> inline Deserializer &operator>>(Deserializer &s, FixIt &f) -{ - s >> f.line >> f.column >> f.length >> f.text; - return s; -} - -#endif diff --git a/rtags/src/FollowLocationJob.cpp b/rtags/src/FollowLocationJob.cpp deleted file mode 100644 index 9de5f46..0000000 --- a/rtags/src/FollowLocationJob.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "FollowLocationJob.h" - -#include "Project.h" -#include "rct/SignalSlot.h" -#include "RTags.h" -#include "Server.h" - -FollowLocationJob::FollowLocationJob(Location loc, - const std::shared_ptr &query, - const std::shared_ptr &project) - : QueryJob(query, project), location(loc) -{ -} - -int FollowLocationJob::execute() -{ - int idx = 0; - Symbol symbol = project()->findSymbol(location, &idx); - if (symbol.isNull()) { - return 1; - } - - // if you invoke a destructor explicitly there's a typeref on the class - // name. This finds the destructor instead. - if ((symbol.kind == CXCursor_TypeRef || symbol.kind == CXCursor_TemplateRef) && idx > 0) { - auto symbols = project()->openSymbols(location.fileId()); - if (!symbols || !symbols->count()) - return 1; - const Symbol prev = symbols->valueAt(idx - 1); - if (prev.kind == CXCursor_MemberRefExpr - && prev.location.column() == symbol.location.column() - 1 - && prev.location.line() == symbol.location.line() - && prev.symbolName.contains("~")) { - symbol = prev; - } - } - - if (queryFlags() & QueryMessage::TargetUsrs) { - const Set usrs = project()->findTargetUsrs(location); - for (const String &usr : usrs) { - for (const Symbol &s : project()->findByUsr(usr, location.fileId(), Project::All)) { - write(s.toString()); - } - } - return 0; - } - - auto targets = RTags::sortTargets(project()->findTargets(symbol)); - - int rank = -1; - Set seen; - auto writeTarget = [&rank, this, &seen](const Symbol &target) { - if (seen.insert(target.location)) { - write(target.location); - rank = RTags::targetRank(target.kind); - } - }; - for (const auto &target : targets) { - if (target.location.isNull()) - continue; - - if (symbol.usr == target.usr) { - writeTarget(target); - if (queryFlags() & QueryMessage::AllTargets) - continue; - break; - } - - if (queryFlags() & QueryMessage::DeclarationOnly ? target.isDefinition() : !target.isDefinition()) { - const auto others = RTags::sortTargets(project()->findTargets(target)); - bool found = false; - for (auto other : others) { - if (!other.isNull() && other.usr == target.usr) { - found = true; - writeTarget(other); - if (!(queryFlags() & QueryMessage::AllTargets)) { - break; - } - } - } - - if (found) { - if (queryFlags() & QueryMessage::AllTargets) { - continue; - } else { - break; - } - } - } - writeTarget(target); - if (!(queryFlags() & QueryMessage::AllTargets)) - break; - } - return 0; -} diff --git a/rtags/src/FollowLocationJob.h b/rtags/src/FollowLocationJob.h deleted file mode 100644 index 1e5ae75..0000000 --- a/rtags/src/FollowLocationJob.h +++ /dev/null @@ -1,32 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef FollowLocationJob_h -#define FollowLocationJob_h - -#include "Location.h" -#include "QueryJob.h" - -class FollowLocationJob : public QueryJob -{ -public: - FollowLocationJob(Location loc, const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - const Location location; -}; - -#endif diff --git a/rtags/src/IncludeFileJob.cpp b/rtags/src/IncludeFileJob.cpp deleted file mode 100644 index 88b6758..0000000 --- a/rtags/src/IncludeFileJob.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "IncludeFileJob.h" - -#include "Project.h" -#include "RTags.h" -#include "Server.h" - -IncludeFileJob::IncludeFileJob(const std::shared_ptr &query, const std::shared_ptr &project) - : QueryJob(query, project) -{ - const uint32_t fileId = Location::fileId(query->currentFile()); - mSource = project->sources(fileId).value(query->buildIndex()); - if (mSource.isNull()) { - for (const uint32_t dep : project->dependencies(fileId, Project::DependsOnArg)) { - mSource = project->sources(dep).value(query->buildIndex()); - if (!mSource.isNull()) - break; - } - } - mSymbol = query->query(); -} - -static inline List headersForSymbol(const std::shared_ptr &project, Location loc) -{ - List ret; - const Path &path = loc.path(); - if (path.isHeader()) { - ret.append(path); - if (const DependencyNode *node = project->dependencies().value(loc.fileId())) { - for (const auto &dependent : node->dependents) { - const Path p = Location::path(dependent.first); - if (p.isHeader() && dependent.second->includes.size() == 1) { - ret.append(p); - // allow headers that only include one header if we don't - // find anything for the real header - } - } - } - } - return ret; -} - -int IncludeFileJob::execute() -{ - if (mSource.isNull()) { - return 1; - } - const Path directory = mSource.sourceFile().parentDir(); - Set last; - int matches = 0; - Set all; - auto process = [&directory, this, &all](const Set &locations) { - for (Location loc : locations) { - bool first = true; - for (const Path &path : headersForSymbol(project(), loc)) { - bool found = false; - const Symbol sym = project()->findSymbol(loc); - switch (sym.kind) { - case CXCursor_ClassDecl: - case CXCursor_StructDecl: - case CXCursor_ClassTemplate: - case CXCursor_TypedefDecl: - if (!sym.isDefinition()) - break; - RCT_FALL_THROUGH; - case CXCursor_FunctionDecl: - case CXCursor_FunctionTemplate: { - List alternatives; - if (path.startsWith(directory)) - alternatives << String::format<256>("#include \"%s\"", path.mid(directory.size()).constData()); - for (const Source::Include &inc : mSource.includePaths) { - const Path p = inc.path.ensureTrailingSlash(); - if (path.startsWith(p)) { - const String str = String::format<256>("#include <%s>", path.mid(p.size()).constData()); - alternatives << str; - } - } - const int tail = strlen(path.fileName()) + 1; - List::const_iterator it = alternatives.begin(); - while (it != alternatives.end()) { - bool drop = false; - for (List::const_iterator it2 = it + 1; it2 != alternatives.end(); ++it2) { - if (it2->size() < it->size()) { - if (!strncmp(it2->constData() + 9, it->constData() + 9, it2->size() - tail - 9)) { - drop = true; - break; - } - } - } - if (!drop) { - found = true; - all.insert(*it); - } - ++it; - } - - break; } - default: - break; - } - if (first) { - if (found) - break; - first = false; - } - } - } - }; - project()->findSymbols(mSymbol, [&](Project::SymbolMatchType type, const String &symbolName, const Set &locations) { - ++matches; - bool fuzzy = false; - if (type == Project::StartsWith) { - fuzzy = true; - const size_t paren = symbolName.indexOf('('); - if (paren == mSymbol.size() && !RTags::isFunctionVariable(symbolName)) - fuzzy = false; - } - - if (!fuzzy) { - process(locations); - } else if (matches == 1) { - last = locations; - } - }, queryFlags()); - if (matches == 1 && !last.isEmpty()) { - process(last); - } - List alternatives = all.toList(); - std::sort(alternatives.begin(), alternatives.end(), [](const String &a, const String &b) { - return a.size() < b.size(); - }); - for (const auto &a : alternatives) { - write(a); - } - - return 0; -} diff --git a/rtags/src/IncludeFileJob.h b/rtags/src/IncludeFileJob.h deleted file mode 100644 index 9da692a..0000000 --- a/rtags/src/IncludeFileJob.h +++ /dev/null @@ -1,33 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef IncludeFileJob_h -#define IncludeFileJob_h - -#include "QueryJob.h" -#include "rct/String.h" - -class IncludeFileJob : public QueryJob -{ -public: - IncludeFileJob(const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - String mSymbol; - Source mSource; -}; - -#endif diff --git a/rtags/src/IncludeTypesInternal.h b/rtags/src/IncludeTypesInternal.h deleted file mode 100644 index 5384b14..0000000 --- a/rtags/src/IncludeTypesInternal.h +++ /dev/null @@ -1,14 +0,0 @@ -DECLARE_INCLUDE_TYPE(Type_DirAfter, "-idirafter", " ") -DECLARE_INCLUDE_TYPE(Type_File, "-include", " ") -DECLARE_INCLUDE_TYPE(Type_Framework, "-F", "") -DECLARE_INCLUDE_TYPE(Type_Include, "-I", "") -DECLARE_INCLUDE_TYPE(Type_Macros, "-imacros", " ") -DECLARE_INCLUDE_TYPE(Type_MultiLib, "-imultilib", " ") -DECLARE_INCLUDE_TYPE(Type_PCH, "-include-pch", " ") -DECLARE_INCLUDE_TYPE(Type_Prefix, "-iprefix", " ") -DECLARE_INCLUDE_TYPE(Type_Quote, "-iquote", " ") -DECLARE_INCLUDE_TYPE(Type_Sysroot, "-isysroot", " ") -DECLARE_INCLUDE_TYPE(Type_System, "-isystem", " ") -DECLARE_INCLUDE_TYPE(Type_SystemFramework, "-iframework", " ") -DECLARE_INCLUDE_TYPE(Type_WithPrefix, "-iwithprefix", " ") -DECLARE_INCLUDE_TYPE(Type_WithPrefixBefore, "-iwithprefixbefore", " ") diff --git a/rtags/src/IndexDataMessage.h b/rtags/src/IndexDataMessage.h deleted file mode 100644 index f817015..0000000 --- a/rtags/src/IndexDataMessage.h +++ /dev/null @@ -1,129 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef IndexDataMessage_h -#define IndexDataMessage_h - -#include "Diagnostic.h" -#include "IndexerJob.h" -#include "rct/Flags.h" -#include "rct/Serializer.h" -#include "rct/String.h" -#include "RTagsMessage.h" - -class IndexDataMessage : public RTagsMessage -{ -public: - enum { MessageId = IndexDataMessageId }; - - IndexDataMessage(const std::shared_ptr &job) - : RTagsMessage(MessageId), mParseTime(0), mId(0), mIndexerJobFlags(job->flags), mBytesWritten(0) - {} - - IndexDataMessage() - : RTagsMessage(MessageId), mParseTime(0), mId(0), mBytesWritten(0) - {} - - void encode(Serializer &serializer) const; - void decode(Deserializer &deserializer); - - enum Flag { - None = 0x0, - ParseFailure = 0x1, - InclusionError = 0x2, - UsedPCH = 0x4 - }; - Flags flags() const { return mFlags; } - void setFlags(Flags f) { mFlags = f; } - void setFlag(Flag flag, bool on = true) { mFlags.set(flag, on); } - - Set visitedFiles() const - { - Set ret; - for (const auto &it : mFiles) { - if (it.second & Visited) - ret.insert(it.first); - } - return ret; - } - - Set blockedFiles() const - { - Set ret; - for (const auto &it : mFiles) { - if (!(it.second & Visited)) - ret.insert(it.first); - } - return ret; - } - - const Path &project() const { return mProject; } - void setProject(const Path &p) { mProject = p; } - - uint64_t id() const { return mId; } - void setId(uint64_t i) { mId = i; } - - uint64_t parseTime() const { return mParseTime; } - void setParseTime(uint64_t time) { mParseTime = time; } - - Flags indexerJobFlags() const { return mIndexerJobFlags; } - void setIndexerJobFlags(Flags flags) { mIndexerJobFlags = flags; } - - const String &message() const { return mMessage; } - void setMessage(const String &msg) { mMessage = msg; } - - FixIts &fixIts() { return mFixIts; } - Diagnostics &diagnostics() { return mDiagnostics; } - Includes &includes() { return mIncludes; } - enum FileFlag { - NoFileFlag = 0x0, - Visited = 0x1, - HeaderError = 0x2, - IncludeError = 0x4 - }; - Hash > &files() { return mFiles; } - const Hash > &files() const { return mFiles; } - - size_t bytesWritten() const { return mBytesWritten; } - void setBytesWritten(size_t bytes) { mBytesWritten = bytes; } -private: - Path mProject; - uint64_t mParseTime, mId; - Flags mIndexerJobFlags; // indexerjobflags - String mMessage; // used as output for dump when flags & Dump - FixIts mFixIts; - Diagnostics mDiagnostics; - Includes mIncludes; - Hash > mFiles; - Flags mFlags; - size_t mBytesWritten; -}; - -RCT_FLAGS(IndexDataMessage::Flag); -RCT_FLAGS(IndexDataMessage::FileFlag); - -inline void IndexDataMessage::encode(Serializer &serializer) const -{ - serializer << mProject << mParseTime << mId << mIndexerJobFlags << mMessage - << mFixIts << mIncludes << mDiagnostics << mFiles << mFlags << mBytesWritten; -} - -inline void IndexDataMessage::decode(Deserializer &deserializer) -{ - deserializer >> mProject >> mParseTime >> mId >> mIndexerJobFlags >> mMessage - >> mFixIts >> mIncludes >> mDiagnostics >> mFiles >> mFlags >> mBytesWritten; -} - -#endif diff --git a/rtags/src/IndexMessage.cpp b/rtags/src/IndexMessage.cpp deleted file mode 100644 index 4e49d82..0000000 --- a/rtags/src/IndexMessage.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "IndexMessage.h" - -#include "rct/Serializer.h" - -IndexMessage::IndexMessage() - : RTagsMessage(MessageId), mFlags(None) -{ -} - -void IndexMessage::encode(Serializer &serializer) const -{ - serializer << mCommandLine << mWorkingDirectory << mProjectRoot - << mCompileCommands << mArgs << mFlags << mEnvironment; -} - -void IndexMessage::decode(Deserializer &deserializer) -{ - deserializer >> mCommandLine >> mWorkingDirectory >> mProjectRoot - >> mCompileCommands >> mArgs >> mFlags >> mEnvironment; -} diff --git a/rtags/src/IndexMessage.h b/rtags/src/IndexMessage.h deleted file mode 100644 index d764a4f..0000000 --- a/rtags/src/IndexMessage.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef IndexMessage_h -#define IndexMessage_h - -#include "rct/Flags.h" -#include "rct/List.h" -#include "rct/String.h" -#include "RTagsMessage.h" - -class IndexMessage : public RTagsMessage -{ -public: - enum { MessageId = CompileId }; - - IndexMessage(); - - const Path &projectRoot() const { return mProjectRoot; } - void setProjectRoot(const Path &projectRoot) { mProjectRoot = projectRoot; } - const Path &workingDirectory() const { return mWorkingDirectory; } - void setWorkingDirectory(Path &&wd) { mWorkingDirectory = std::move(wd); } - void setEnvironment(const List &environment) { mEnvironment = environment; } - const List &environment() const { return mEnvironment; } - List &&takeEnvironment() { return std::move(mEnvironment); } - Path compileCommands() const { return mCompileCommands; } - void setCompileCommands(Path &&path) { mCompileCommands = std::move(path); } - const String &arguments() const { return mArgs; } - String &&takeArguments() { return std::move(mArgs); } - void setArguments(String &&args) { mArgs = std::move(args); } - enum Flag { - None = 0x0, - GuessFlags = 0x1 - }; - Flags flags() const { return mFlags; } - void setFlags(Flags f) { mFlags = f; } - void setFlag(Flag flag, bool on = true) { mFlags.set(flag, on); } - virtual void encode(Serializer &serializer) const override; - virtual void decode(Deserializer &deserializer) override; -private: - Path mWorkingDirectory; - String mArgs; - List mEnvironment; - Path mProjectRoot; - Path mCompileCommands; - Flags mFlags; -}; - -RCT_FLAGS(IndexMessage::Flag); - -#endif diff --git a/rtags/src/IndexParseData.cpp b/rtags/src/IndexParseData.cpp deleted file mode 100644 index 908d9fd..0000000 --- a/rtags/src/IndexParseData.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "IndexParseData.h" -#include "Location.h" - -bool IndexParseData::write(const std::function &write, const Match &match) const -{ - auto process = [&write, &match](const String &str, const Sources &sss) { - if (!sss.isEmpty()) { - if (!write(str + ":")) - return false; - - for (const auto &ss : sss) { - const Path file = Location::path(ss.first); - if (match.isEmpty() || match.match(file)) { - write(" " + file + ":"); - for (const auto &s : ss.second) { - if (!write(" " + s.toString())) - return false; - } - } - } - } - return true; - }; - if (!process("Sources", sources)) - return false; - - for (const auto &commands : compileCommands) { - if (!process(Location::path(commands.first), commands.second.sources)) - return false; - } - return true; -} diff --git a/rtags/src/IndexParseData.h b/rtags/src/IndexParseData.h deleted file mode 100644 index eac45e8..0000000 --- a/rtags/src/IndexParseData.h +++ /dev/null @@ -1,117 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef IndexParseData_h -#define IndexParseData_h - -#include "rct/Path.h" -#include "rct/List.h" -#include "rct/Serializer.h" -#include "rct/Log.h" -#include -#include "RTags.h" -#include "rct/Connection.h" -#include "Match.h" -#include - -class IndexParseData -{ -public: - Path project; - struct CompileCommands { - CompileCommands() - : lastModifiedMs(0) - {} - CompileCommands(CompileCommands &&other) - : lastModifiedMs(other.lastModifiedMs), sources(std::move(other.sources)), environment(std::move(other.environment)) - { - other.lastModifiedMs = 0; - } - CompileCommands(const CompileCommands &other) - : lastModifiedMs(other.lastModifiedMs), sources(other.sources), environment(other.environment) - {} - - CompileCommands &operator=(CompileCommands &&other) - { - lastModifiedMs = other.lastModifiedMs; - sources = std::move(other.sources); - environment = std::move(other.environment); - other.lastModifiedMs = 0; - return *this; - } - - CompileCommands &operator=(const CompileCommands &other) - { - lastModifiedMs = other.lastModifiedMs; - sources = other.sources; - environment = other.environment; - return *this; - } - - uint64_t lastModifiedMs; - Sources sources; - List environment; - }; - Hash compileCommands; // fileId for compile_commands.json -> CompileCommands - List environment; - Sources sources; - - bool isEmpty() const { return compileCommands.isEmpty() && environment.isEmpty() && sources.isEmpty(); } - bool write(const std::function &write, const Match &match = Match()) const; -}; - -inline Serializer &operator<<(Serializer &s, const IndexParseData::CompileCommands &commands) -{ - s << commands.lastModifiedMs << commands.sources << Sandbox::encoded(commands.environment); - return s; -} - -inline Deserializer &operator>>(Deserializer &s, IndexParseData::CompileCommands &commands) -{ - s >> commands.lastModifiedMs >> commands.sources >> commands.environment; - Sandbox::decode(commands.environment); - return s; -} - -inline Serializer &operator<<(Serializer &s, const IndexParseData &data) -{ - s << Sandbox::encoded(data.project) << static_cast(data.compileCommands.size()); - for (const auto &pair : data.compileCommands) { - s << Location::path(pair.first) << pair.first << pair.second; - } - s << data.sources << Sandbox::encoded(data.environment); - return s; -} - -inline Deserializer &operator>>(Deserializer &s, IndexParseData &data) -{ - s >> data.project; - data.compileCommands.clear(); - uint32_t size; - s >> size; - while (size-- > 0) { - Path file; - s >> file; - uint32_t fileId; - s >> fileId; - Location::set(file, fileId); - s >> data.compileCommands[fileId]; - } - s >> data.sources >> data.environment; - Sandbox::decode(data.environment); - return s; -} - -#endif diff --git a/rtags/src/IndexerJob.cpp b/rtags/src/IndexerJob.cpp deleted file mode 100644 index 7718bda..0000000 --- a/rtags/src/IndexerJob.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "IndexerJob.h" - -#include "CompilerManager.h" -#include "Project.h" -#include "rct/Process.h" -#include "JobScheduler.h" -#include "RTags.h" -#include "Server.h" -#include "RTagsVersion.h" - -uint64_t IndexerJob::sNextId = 1; -IndexerJob::IndexerJob(const SourceList &s, - Flags f, - const std::shared_ptr &p, - const UnsavedFiles &u) - : id(0), flags(f), - project(p->path()), unsavedFiles(u), crashCount(0), mCachedPriority(INT_MIN) -{ - sources.append(s.front()); - for (size_t i=1; isourceFile(); - acquireId(); - visited.insert(sources.begin()->fileId); -} - -IndexerJob::~IndexerJob() -{ - destroyed(this); -} - -void IndexerJob::acquireId() -{ - id = sNextId++; -} - -int IndexerJob::priority() const -{ - if (mCachedPriority == INT_MIN) { - int ret = 0; - Server *server = Server::instance(); - uint32_t fileId = sources.begin()->fileId; - assert(server); - if (server->jobScheduler()->hasHeaderError(fileId)) { - ret = -1; - } else { - if (flags & Dirty) { - ++ret; - } else if (flags & Reindex) { - ret += 4; - } - std::shared_ptr p = server->project(project); - if (server->isActiveBuffer(fileId)) { - ret += 8; - } else if (p) { - if (DependencyNode *node = p->dependencyNode(fileId)) { - Set seen; - seen.insert(node); - std::function func = [&seen, server, &func](const DependencyNode *n) { - for (const auto &inc : n->includes) { - if (seen.insert(inc.second) - && !Location::path(n->fileId).isSystem() - && (server->isActiveBuffer(n->fileId) || func(inc.second))) { - return true; - } - } - return false; - }; - if (func(node)) - ret += 2; - } - } - - if (p && server->currentProject() == p) - ++ret; - } - mCachedPriority = ret; - } - return mCachedPriority; -} - -String IndexerJob::encode() const -{ - String ret; - { - Serializer serializer(ret); - serializer.write("1234", sizeof(int)); // for size - std::shared_ptr proj = Server::instance()->project(project); - const Server::Options &options = Server::instance()->options(); - serializer << static_cast(RTags::DatabaseVersion) - << options.sandboxRoot - << id - << options.socketFile - << project - << static_cast(sources.size()); - for (Source copy : sources) { - if (!(options.options & Server::AllowWErrorAndWFatalErrors)) { - int idx = copy.arguments.indexOf("-Werror"); - if (idx != -1) - copy.arguments.removeAt(idx); - idx = copy.arguments.indexOf("-Wfatal-errors"); - if (idx != -1) - copy.arguments.removeAt(idx); - } - copy.arguments << options.defaultArguments; - - if (!(options.options & Server::AllowPedantic)) { - const int idx = copy.arguments.indexOf("-Wpedantic"); - if (idx != -1) { - copy.arguments.removeAt(idx); - } - } - - if (options.options & Server::EnableCompilerManager) { - CompilerManager::applyToSource(copy, CompilerManager::IncludeIncludePaths); - } - - Server::instance()->filterBlockedArguments(copy); - - for (const auto &inc : options.includePaths) { - copy.includePaths << inc; - } - if (Server::instance()->options().options & Server::PCHEnabled) - proj->fixPCH(copy); - - copy.defines << options.defines; - if (!(options.options & Server::EnableNDEBUG)) { - copy.defines.remove(Source::Define("NDEBUG")); - } - assert(!sourceFile.isEmpty()); - copy.encode(serializer, Source::IgnoreSandbox); - } - assert(proj); - Flags f = flags; - if (Server::instance()->isActiveBuffer(fileId())) - f |= Active; - serializer << sourceFile - << f - << static_cast(options.rpVisitFileTimeout) - << static_cast(options.rpIndexDataMessageTimeout) - << static_cast(options.rpConnectTimeout) - << static_cast(options.rpConnectAttempts) - << static_cast(options.rpNiceValue) - << options.options - << unsavedFiles - << options.dataDir - << options.debugLocations; - - proj->encodeVisitedFiles(serializer); - } - const uint32_t size = ret.size() - sizeof(int); - memcpy(&ret[0], &size, sizeof(size)); - return ret; -} - -String IndexerJob::dumpFlags(Flags flags) -{ - List ret; - if (flags & Dirty) { - ret += "Dirty"; - } - if (flags & Reindex) { - ret += "Reindex"; - } - if (flags & Compile) { - ret += "Compile"; - } - if (flags & Running) { - ret += "Running"; - } - if (flags & Crashed) { - ret += "Crashed"; - } - if (flags & Aborted) { - ret += "Aborted"; - } - if (flags & Complete) { - ret += "Complete"; - } - - return String::join(ret, ", "); -} - -void IndexerJob::recalculatePriority() -{ - mCachedPriority = INT_MIN; - priority(); -} diff --git a/rtags/src/IndexerJob.h b/rtags/src/IndexerJob.h deleted file mode 100644 index ab229d8..0000000 --- a/rtags/src/IndexerJob.h +++ /dev/null @@ -1,74 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef IndexerJob_h -#define IndexerJob_h - -#include "rct/Flags.h" -#include "rct/SignalSlot.h" -#include "RTags.h" -#include "Source.h" - -class IndexerJob -{ -public: - enum Flag { - None = 0x000, - Dirty = 0x001, - Reindex = 0x002, - Compile = 0x004, - Running = 0x010, - Crashed = 0x020, - Aborted = 0x040, - Complete = 0x080, - NoAbort = 0x100, - Active = 0x200, - Type_Mask = Dirty|Compile|Reindex - }; - - static String dumpFlags(Flags flags); - - IndexerJob(const SourceList &sources, - Flags flags, - const std::shared_ptr &project, - const UnsavedFiles &unsavedFiles = UnsavedFiles()); - ~IndexerJob(); - - void acquireId(); - String encode() const; - - uint32_t fileId() const { assert(!sources.isEmpty()); return sources.begin()->fileId; } - - int priority() const; - void recalculatePriority(); - - uint64_t id; - SourceList sources; - Path sourceFile; - Flags flags; - Path project; - UnsavedFiles unsavedFiles; - Set visited; - int crashCount; - Signal > destroyed; - -private: - mutable int mCachedPriority; - static uint64_t sNextId; -}; - -RCT_FLAGS(IndexerJob::Flag); - -#endif diff --git a/rtags/src/JobScheduler.cpp b/rtags/src/JobScheduler.cpp deleted file mode 100644 index fb4ce27..0000000 --- a/rtags/src/JobScheduler.cpp +++ /dev/null @@ -1,322 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "JobScheduler.h" - -#include "IndexDataMessage.h" -#include "IndexerJob.h" -#include "Project.h" -#include "rct/Connection.h" -#include "rct/Process.h" -#include "Server.h" - -enum { MaxPriority = 10 }; -// we set the priority to be this when a job has been requested and we couldn't load it -JobScheduler::JobScheduler() - : mProcrastination(0) -{} - -JobScheduler::~JobScheduler() -{ - mPendingJobs.deleteAll(); - if (!mActiveByProcess.isEmpty()) { - for (const auto &job : mActiveByProcess) { - job.first->kill(); - delete job.first; - } - } -} - -void JobScheduler::add(const std::shared_ptr &job) -{ - assert(!(job->flags & ~IndexerJob::Type_Mask)); - std::shared_ptr node(new Node({ 0, job, 0, 0, 0, String() })); - node->job = job; - // error() << job->priority << job->sourceFile << mProcrastination; - if (mPendingJobs.isEmpty() || job->priority() > mPendingJobs.first()->job->priority()) { - mPendingJobs.prepend(node); - } else { - std::shared_ptr after = mPendingJobs.last(); - while (job->priority() > after->job->priority()) { - after = after->prev; - assert(after); - } - mPendingJobs.insert(node, after); - } - assert(!mInactiveById.contains(job->id)); - mInactiveById[job->id] = node; - // error() << "procrash" << mProcrastination << job->sourceFile; - if (!mProcrastination) - startJobs(); -} - -uint32_t JobScheduler::hasHeaderError(DependencyNode *node, Set &seen) const -{ - assert(node); - for (auto dep : node->includes) { - if (!seen.insert(dep.first)) - continue; - - if (mHeaderErrors.contains(dep.first)) { - return dep.first; - } - if (uint32_t fileId = hasHeaderError(dep.second, seen)) { - return fileId; - } - } - return 0; -} - -uint32_t JobScheduler::hasHeaderError(uint32_t file, const std::shared_ptr &project) const -{ - DependencyNode *node = project->dependencies().value(file); - if (!node) - return false; - Set seen; - return hasHeaderError(node, seen); -} - -void JobScheduler::startJobs() -{ - Server *server = Server::instance(); - assert(server); - if (server->suspended()) { - warning() << "Suspended, not starting jobs"; - return; - } - const auto &options = server->options(); - std::shared_ptr jobNode = mPendingJobs.first(); - auto cont = [&jobNode, this]() { - auto tmp = jobNode->next; - mPendingJobs.remove(jobNode); - jobNode = tmp; - }; - - while (mActiveByProcess.size() < options.jobCount && jobNode) { - assert(jobNode); - assert(jobNode->job); - assert(!(jobNode->job->flags & (IndexerJob::Running|IndexerJob::Complete|IndexerJob::Crashed|IndexerJob::Aborted))); - std::shared_ptr project = Server::instance()->project(jobNode->job->project); - if (!project) { - cont(); - debug() << jobNode->job->sourceFile << "doesn't have a project, discarding"; - continue; - } - - const uint64_t jobId = jobNode->job->id; - Process *process = new Process; - debug() << "Starting process for" << jobId << jobNode->job->fileId() << jobNode->job.get(); - List arguments; - arguments << "--priority" << String::number(jobNode->job->priority()); - - for (int i=logLevel().toInt(); i>0; --i) - arguments << "-v"; - - process->readyReadStdOut().connect([this](Process *proc) { - std::shared_ptr n = mActiveByProcess[proc]; - assert(n); - n->stdOut.append(proc->readAllStdOut()); - - std::regex rx("@CRASH@([^@]*)@CRASH@"); - std::smatch match; - while (std::regex_search(n->stdOut.ref(), match, rx)) { - error() << match[1].str(); - n->stdOut.remove(match.position(), match.length()); - } - }); - - if (!process->start(options.rp, arguments)) { - error() << "Couldn't start rp" << options.rp << process->errorString(); - delete process; - jobNode->job->flags |= IndexerJob::Crashed; - debug() << "job crashed (didn't start)" << jobId << jobNode->job->fileId() << jobNode->job.get(); - auto msg = std::make_shared(jobNode->job); - msg->setFlag(IndexDataMessage::ParseFailure); - jobFinished(jobNode->job, msg); - cont(); - continue; - } - process->finished().connect([this, jobId](Process *proc) { - EventLoop::deleteLater(proc); - auto n = mActiveByProcess.take(proc); - assert(!n || n->process == proc); - const String stdErr = proc->readAllStdErr(); - if ((n && !n->stdOut.isEmpty()) || !stdErr.isEmpty()) { - error() << (n ? ("Output from " + n->job->sourceFile + ":") : String("Orphaned process:")) - << '\n' << stdErr << (n ? n->stdOut : String()); - } - - if (n) { - assert(n->process == proc); - n->process = 0; - assert(!(n->job->flags & IndexerJob::Aborted)); - if (!(n->job->flags & IndexerJob::Complete) && proc->returnCode() != 0) { - auto nodeById = mActiveById.take(jobId); - assert(nodeById); - assert(nodeById == n); - // job failed, probably no IndexDataMessage coming - n->job->flags |= IndexerJob::Crashed; - debug() << "job crashed" << jobId << n->job->fileId() << n->job.get(); - auto msg = std::make_shared(n->job); - msg->setFlag(IndexDataMessage::ParseFailure); - jobFinished(n->job, msg); - } - } - startJobs(); - }); - - - jobNode->process = process; - assert(!(jobNode->job->flags & ~IndexerJob::Type_Mask)); - jobNode->job->flags |= IndexerJob::Running; - process->write(jobNode->job->encode()); - jobNode->started = Rct::monoMs(); - mActiveByProcess[process] = jobNode; - // error() << "STARTING JOB" << node->job->sourceFile; - mInactiveById.remove(jobId); - mActiveById[jobId] = jobNode; - cont(); - } -} - -void JobScheduler::handleIndexDataMessage(const std::shared_ptr &message) -{ - auto node = mActiveById.take(message->id()); - if (!node) { - debug() << "Got IndexDataMessage for unknown job"; - return; - } - debug() << "job got index data message" << node->job->id << node->job->fileId() << node->job.get(); - jobFinished(node->job, message); -} - -void JobScheduler::jobFinished(const std::shared_ptr &job, const std::shared_ptr &message) -{ - bool headerErrorChanged = false; - for (const auto &it : message->files()) { - if (it.second & IndexDataMessage::HeaderError) { - if (mHeaderErrors.insert(it.first)) - headerErrorChanged = true; - } else if (mHeaderErrors.remove(it.first)) { - headerErrorChanged = true; - } - } - // mHeaderErrors.unite(message->headerErrors()); - assert(!(job->flags & IndexerJob::Aborted)); - assert(job); - assert(message); - std::shared_ptr project = Server::instance()->project(job->project); - if (!project) - return; - - job->flags &= ~IndexerJob::Running; - if (!(job->flags & IndexerJob::Crashed)) { - job->flags |= IndexerJob::Complete; - } else { - ++job->crashCount; - const auto &options = Server::instance()->options(); - assert(job->crashCount <= options.maxCrashCount); - if (job->crashCount < options.maxCrashCount) { - project->releaseFileIds(job->visited); - EventLoop::eventLoop()->registerTimer([job, this](int) { - if (!(job->flags & IndexerJob::Aborted)) { - job->flags &= ~IndexerJob::Crashed; - job->acquireId(); - add(job); - } - }, 500, Timer::SingleShot); // give it 500 ms before we try again - return; - } - debug() << "job crashed too many times" << job->id << job->fileId() << job.get(); - } - project->onJobFinished(job, message); - if (headerErrorChanged) - sort(); -} - -void JobScheduler::dump(const std::shared_ptr &conn) -{ - if (!mPendingJobs.isEmpty()) { - conn->write("Pending:"); - for (const auto &node : mPendingJobs) { - conn->write<128>("%s: %s %d %s", - node->job->sourceFile.constData(), - node->job->flags.toString().constData(), - node->job->priority(), - IndexerJob::dumpFlags(node->job->flags).constData()); - } - } - if (!mActiveById.isEmpty()) { - conn->write("Active:"); - const unsigned long long now = Rct::monoMs(); - for (const auto &node : mActiveById) { - conn->write<128>("%s: %s priority: %d %s %lldms", - node.second->job->sourceFile.constData(), - node.second->job->flags.toString().constData(), - node.second->job->priority(), - IndexerJob::dumpFlags(node.second->job->flags).constData(), - now - node.second->started); - - } - } -} - -void JobScheduler::abort(const std::shared_ptr &job) -{ - assert(!(job->flags & IndexerJob::Aborted)); - job->flags |= IndexerJob::Aborted; - if (job->flags & IndexerJob::Crashed) { - return; - } - job->flags &= ~IndexerJob::Running; - auto node = mActiveById.take(job->id); - if (!node) { - debug() << "Aborting inactive job" << job->sourceFile << job->fileId() << job->id << job.get(); - node = mInactiveById.take(job->id); - assert(node); - mPendingJobs.remove(node); - } else { - debug() << "Aborting active job" << job->sourceFile << job->fileId() << job->id << job.get(); - } - if (node->process) { - debug() << "Killing process" << node->process; - node->process->kill(); - mActiveByProcess.remove(node->process); - } -} - -void JobScheduler::clearHeaderError(uint32_t file) -{ - if (mHeaderErrors.remove(file)) - warning() << Location::path(file) << "was touched, starting jobs"; -} - -void JobScheduler::sort() -{ - std::vector > nodes(mPendingJobs.size()); - for (size_t i=0; i node = mPendingJobs.removeFirst(); - node->job->recalculatePriority(); - nodes[i] = std::move(node); - } - - std::stable_sort(nodes.begin(), nodes.end(), [](const std::shared_ptr &l, const std::shared_ptr &r) -> bool { - return l->job->priority() > r->job->priority(); - }); - - for (std::shared_ptr &n : nodes) { - mPendingJobs.append(std::move(n)); - } -} diff --git a/rtags/src/JobScheduler.h b/rtags/src/JobScheduler.h deleted file mode 100644 index 12467b9..0000000 --- a/rtags/src/JobScheduler.h +++ /dev/null @@ -1,86 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef JobScheduler_h -#define JobScheduler_h - -#include - -#include "rct/EmbeddedLinkedList.h" -#include "rct/Set.h" -#include "rct/Hash.h" -#include "rct/String.h" - -class Connection; -class IndexDataMessage; -class IndexerJob; -class Process; -class Project; -struct DependencyNode; -class JobScheduler : public std::enable_shared_from_this -{ -public: - JobScheduler(); - ~JobScheduler(); - - struct JobScope { - JobScope(const std::shared_ptr &scheduler) - : mScheduler(scheduler) - { - assert(mScheduler); - ++mScheduler->mProcrastination; - } - - ~JobScope() - { - if (!--mScheduler->mProcrastination) - mScheduler->startJobs(); - } - - private: - const std::shared_ptr mScheduler; - }; - - void add(const std::shared_ptr &job); - void handleIndexDataMessage(const std::shared_ptr &message); - void dump(const std::shared_ptr &conn); - void abort(const std::shared_ptr &job); - void clearHeaderError(uint32_t file); - bool hasHeaderError(uint32_t fileId) const { return mHeaderErrors.contains(fileId); } - Set headerErrors() const { return mHeaderErrors; } - void startJobs(); - size_t pendingJobCount() const { return mPendingJobs.size(); } - size_t activeJobCount() const { return mActiveById.size(); } - void sort(); -private: - void jobFinished(const std::shared_ptr &job, const std::shared_ptr &message); - struct Node { - unsigned long long started; - std::shared_ptr job; - Process *process; - std::shared_ptr next, prev; - String stdOut; - }; - uint32_t hasHeaderError(DependencyNode *node, Set &seen) const; - uint32_t hasHeaderError(uint32_t file, const std::shared_ptr &project) const; - - int mProcrastination; - Set mHeaderErrors; - EmbeddedLinkedList > mPendingJobs; - Hash > mActiveByProcess; - Hash > mActiveById, mInactiveById; -}; - -#endif diff --git a/rtags/src/ListSymbolsJob.cpp b/rtags/src/ListSymbolsJob.cpp deleted file mode 100644 index 1d6c338..0000000 --- a/rtags/src/ListSymbolsJob.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "ListSymbolsJob.h" - -#include "Project.h" -#include "QueryMessage.h" -#include "rct/List.h" -#include "rct/Log.h" -#include "RTags.h" -#include "Server.h" - -const Flags defaultFlags = (QueryJob::WriteUnfiltered | QueryJob::QuietJob); -const Flags elispFlags = (defaultFlags | QueryJob::QuoteOutput); - -ListSymbolsJob::ListSymbolsJob(const std::shared_ptr &query, const std::shared_ptr &proj) - : QueryJob(query, proj, query->flags() & QueryMessage::Elisp ? elispFlags : defaultFlags), - string(query->query()) -{ -} - -int ListSymbolsJob::execute() -{ - Set out; - std::shared_ptr proj = project(); - if (proj) { - if (queryFlags() & QueryMessage::WildcardSymbolNames - && (string.contains('*') || string.contains('?')) && !string.endsWith('*')) { - string += '*'; - } - List filters = pathFilters(); - List paths; - for (const auto &filter : filters) { - if (filter.mode == QueryMessage::PathFilter::Self) { - paths.append(filter.pattern); - if (!paths.last().isFile()) { - paths.clear(); - break; - } - } else { - paths.clear(); - break; - } - } - if (!paths.isEmpty()) { - out = listSymbolsWithPathFilter(proj, paths); - } else { - out = listSymbols(proj); - } - } - - if (queryFlags() & QueryMessage::Elisp) { - write("(list", IgnoreMax | DontQuote); - for (Set::const_iterator it = out.begin(); it != out.end(); ++it) { - write(*it); - } - write(")", IgnoreMax | DontQuote); - } else { - List sorted = out.toList(); - if (queryFlags() & QueryMessage::ReverseSort) { - std::sort(sorted.begin(), sorted.end(), std::greater()); - } else { - std::sort(sorted.begin(), sorted.end()); - } - const int count = sorted.size(); - for (int i = 0; i < count; ++i) { - write(sorted.at(i)); - } - } - return out.isEmpty() ? 1 : 0; -} - -Set ListSymbolsJob::listSymbolsWithPathFilter(const std::shared_ptr &project, const List &paths) const -{ - Set out; - const bool wildcard = queryFlags() & QueryMessage::WildcardSymbolNames && (string.contains('*') || string.contains('?')); - const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses; - const bool caseInsensitive = queryFlags() & QueryMessage::MatchCaseInsensitive; - const String::CaseSensitivity cs = caseInsensitive ? String::CaseInsensitive : String::CaseSensitive; - for (size_t i=0; iopenSymbols(fileId); - if (!symbols) - continue; - const int count = symbols->count(); - for (int j=0; jvalueAt(j); - if (!filterKind(symbol)) { - continue; - } - const String &symbolName = symbol.symbolName; - if (symbolName.isEmpty()) - continue; - if (!string.isEmpty()) { - if (wildcard) { - if (!Project::matchSymbolName(string, symbolName, cs)) { - continue; - } - } else if (!symbolName.contains(string, cs)) { - continue; - } - } - - if (stripParentheses) { - const int paren = symbolName.indexOf('('); - if (paren == -1) { - out.insert(symbolName); - } else { - if (!RTags::isFunctionVariable(symbolName)) - out.insert(symbolName.left(paren)); - } - } else { - out.insert(symbolName); - } - } - } - return out; -} - -Set ListSymbolsJob::listSymbols(const std::shared_ptr &project) const -{ - const bool hasFilter = QueryJob::hasFilter(); - const bool hasKindFilter = QueryJob::hasKindFilter(); - const bool stripParentheses = queryFlags() & QueryMessage::StripParentheses; - - Set out; - auto inserter = [this, &project, hasFilter, hasKindFilter, stripParentheses, &out](Project::SymbolMatchType, - const String &str, - const Set &locations) { - if (hasFilter) { - bool ok = false; - for (const auto &l : locations) { - if (filter(l.path())) { - ok = true; - break; - } - } - if (!ok) - return; - } - if (hasKindFilter) { - const Symbol sym = project->findSymbol(*locations.begin()); - if (!filterKind(sym)) - return; - } - const int paren = str.indexOf('('); - if (paren == -1) { - out.insert(str); - } else { - if (!RTags::isFunctionVariable(str)) - out.insert(str.left(paren)); - if (!stripParentheses) - out.insert(str); - } - }; - - project->findSymbols(string, inserter, queryFlags()); - return out; -} diff --git a/rtags/src/ListSymbolsJob.h b/rtags/src/ListSymbolsJob.h deleted file mode 100644 index 7935879..0000000 --- a/rtags/src/ListSymbolsJob.h +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef ListSymbolsJob_h -#define ListSymbolsJob_h - -#include "QueryJob.h" -#include "rct/String.h" - -template -class List; -class QueryMessage; -class ListSymbolsJob : public QueryJob -{ -public: - ListSymbolsJob(const std::shared_ptr &query, const std::shared_ptr &proj); -protected: - virtual int execute() override; - Set listSymbolsWithPathFilter(const std::shared_ptr &project, const List &paths) const; - Set listSymbols(const std::shared_ptr &project) const; -private: - String string; -}; - -#endif diff --git a/rtags/src/Location.cpp b/rtags/src/Location.cpp deleted file mode 100644 index 8b61ab1..0000000 --- a/rtags/src/Location.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "Location.h" - -#include "rct/Rct.h" -#include "RTags.h" -#include "Server.h" -#include "Project.h" -#include "ClangIndexer.h" - -Hash Location::sPathsToIds; -Hash Location::sIdsToPaths; -uint32_t Location::sLastId = 0; -std::mutex Location::sMutex; -static inline uint64_t createMask(int startBit, int bitCount) -{ - uint64_t mask = 0; - for (int i=startBit; i(1) << i); - } - return mask; -} - -const uint64_t Location::FILEID_MASK = createMask(0, FileBits); -const uint64_t Location::LINE_MASK = createMask(FileBits, LineBits); -const uint64_t Location::COLUMN_MASK = createMask(FileBits + LineBits, ColumnBits); - -String Location::toString(Flags flags, Hash *contextCache) const -{ - if (isNull()) - return String(); - const unsigned int l = line(); - const unsigned int c = column(); - int extra = RTags::digits(l) + RTags::digits(c) + 3; - String ctx; - if (flags & Location::ShowContext) { - ctx += '\t'; - ctx += context(flags, contextCache); - extra += ctx.size(); - } - - Path p = path(); - if (flags & ConvertToRelative) { - Sandbox::encode(p); - } else if (!(flags & AbsolutePath) && Server::instance()) { - Server *server = Server::instance(); - if (std::shared_ptr pp = server->currentProject()) { - const Path projectPath = pp->path(); - if (!projectPath.isEmpty() && p.startsWith(projectPath)) - p.remove(0, projectPath.size()); - } - } - - String ret(p.size() + extra, ' '); - - const int w = snprintf(ret.data(), ret.size() + extra + 1, "%s:%d:%d:", p.constData(), l, c); - if (!ctx.isEmpty()) { - memcpy(ret.data() + w, ctx.constData(), ctx.size()); - } - return ret; -} - -String Location::context(Flags flags, Hash *cache) const -{ - String copy; - String *code = 0; - const Path p = path(); - - auto readAll = [&p, this]() { - if (Server::instance()) { - if (auto project = Server::instance()->currentProject()) { - const Path f = project->sourceFilePath(fileId(), "unsaved"); - String contents = f.readAll(); - if (!contents.isEmpty()) - return contents; - } - } - return p.readAll(); - }; - if (cache) { - String &ref = (*cache)[p]; - if (ref.isEmpty()) { - ref = readAll(); - } - code = &ref; - } else { - copy = readAll(); - code = © - } - - String ret; - if (!code->isEmpty()) { - unsigned int l = line(); - if (!l) - return String(); - const char *ch = code->constData(); - while (--l) { - ch = strchr(ch, '\n'); - if (!ch) - return String(); - ++ch; - } - const char *end = strchr(ch, '\n'); - if (!end) - return String(); - - ret.assign(ch, end - ch); - // error() << "foobar" << ret << bool(flags & NoColor); - if (!(flags & NoColor)) { - const size_t col = column() - 1; - if (col + 1 < ret.size()) { - size_t last = col; - if (ret.at(last) == '~') - ++last; - while (ret.size() > last && (isalnum(ret.at(last)) || ret.at(last) == '_')) - ++last; - static const char *color = "\x1b[32;1m"; // dark yellow - static const char *resetColor = "\x1b[0;0m"; - // error() << "foobar"<< end << col << ret.size(); - ret.insert(last, resetColor); - ret.insert(col, color); - } - // printf("[%s]\n", ret.constData()); - } - } - return ret; -} - -void Location::saveFileIds() -{ - assert(Server::instance()); - Server::instance()->saveFileIds(); -} - -bool Location::init(const Hash &pathsToIds) -{ - LOCK(); - sPathsToIds = pathsToIds; - sIdsToPaths.clear(); - sLastId = 0; - for (const auto &it : sPathsToIds) { - assert(!it.first.isEmpty()); - Path &ref = sIdsToPaths[it.second]; - if (!ref.isEmpty()) { - sPathsToIds.clear(); - sIdsToPaths.clear(); - sLastId = 0; - return false; - } - ref = it.first; - sLastId = std::max(sLastId, it.second); - } - return true; -} - -void Location::init(const Hash &idsToPaths) -{ - LOCK(); - sIdsToPaths = idsToPaths; - sPathsToIds.clear(); - sLastId = 0; - for (const auto &it : sIdsToPaths) { - sPathsToIds[it.second] = it.first; - assert(!it.second.isEmpty()); - sLastId = std::max(sLastId, it.first); - } -} diff --git a/rtags/src/Location.h b/rtags/src/Location.h deleted file mode 100644 index 6d9ccec..0000000 --- a/rtags/src/Location.h +++ /dev/null @@ -1,357 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef Location_h -#define Location_h - -#include -#include -#include -#include -#if defined(OS_Linux) -#include -#elif defined(OS_Darwin) -#include -#endif -#ifndef RTAGS_SINGLE_THREAD -#include -#define LOCK() const std::lock_guard lock(sMutex) -#else -#define LOCK() do {} while (0) -#endif - -#include "rct/Flags.h" -#include "rct/Log.h" -#include "rct/Path.h" -#include "rct/Serializer.h" -#include "rct/String.h" -#include "rct/StackBuffer.h" - -static inline int intCompare(uint32_t l, uint32_t r) -{ - if (l < r) - return -1; - if (l > r) - return 1; - return 0; -} -static inline int comparePosition(uint32_t lline, uint32_t lcol, uint32_t rline, uint32_t rcol) -{ - int ret = intCompare(lline, rline); - if (!ret) - ret = intCompare(lcol, rcol); - return ret; -} - -class Location -{ -public: - uint64_t value; - - Location() - : value(0) - {} - - Location(uint32_t file, uint32_t l, uint32_t col) - : value((static_cast(col) << (FileBits + LineBits)) | (static_cast(l) << (FileBits)) | file) - { - } - - static inline uint32_t fileId(const Path &path) - { - LOCK(); - return sPathsToIds.value(path); - } - static inline Path path(uint32_t id) - { - LOCK(); - return sIdsToPaths.value(id); - } - - static uint32_t lastId() - { - LOCK(); - return sLastId; - } - - static uint32_t count() - { - LOCK(); - return sIdsToPaths.size(); - } - - static inline uint32_t insertFile(const Path &path) - { - bool save = false; - (void)save; - assert(path.isAbsolute()); - assert(!path.contains("..")); - // in the case of Source::compilerId path can be a symlink - uint32_t ret; - { - LOCK(); - uint32_t &id = sPathsToIds[path]; - if (!id) { - id = ++sLastId; - sIdsToPaths[id] = path; - save = true; - } - ret = id; - } -#ifndef RTAGS_SINGLE_THREAD - if (save) - saveFileIds(); -#endif - return ret; - } - - inline uint32_t fileId() const { return static_cast(value & FILEID_MASK); } - inline uint32_t line() const { return static_cast((value & LINE_MASK) >> FileBits); } - inline uint32_t column() const { return static_cast((value & COLUMN_MASK) >> (FileBits + LineBits)); } - - inline Path path() const - { - LOCK(); - return sIdsToPaths.value(fileId()); - } - inline bool isNull() const { return !value; } - inline bool isValid() const { return value; } - inline void clear() { value = 0; } - inline bool operator==(Location other) const { return value == other.value; } - inline bool operator!=(Location other) const { return value != other.value; } - inline int compare(Location other) const - { - int ret = intCompare(fileId(), other.fileId()); - if (!ret) { - ret = intCompare(line(), other.line()); - if (!ret) - ret = intCompare(column(), other.column()); - } - return ret; - } - inline bool operator<(Location other) const - { - return compare(other) < 0; - } - - inline bool operator<=(Location other) const - { - return compare(other) <= 0; - } - - inline bool operator>(Location other) const - { - return compare(other) > 0; - } - - inline bool operator>=(Location other) const - { - return compare(other) >= 0; - } - - enum ToStringFlag { - NoFlag = 0x0, - ShowContext = 0x1, - NoColor = 0x2, - AbsolutePath = 0x4, - ConvertToRelative = 0x8 - }; - - String toString(Flags flags = NoFlag, Hash *contextCache = 0) const; - String context(Flags flags, Hash *cache = 0) const; - - inline String debug() const; - - enum DecodeFlag { - NoDecodeFlag = 0x0, - CreateLocation = 0x1 - }; - - static Location decode(const String &data, DecodeFlag flag = NoDecodeFlag) - { - uint32_t col; - uint32_t line; - memcpy(&col, data.constData() + data.size() - sizeof(col), sizeof(col)); - memcpy(&line, data.constData() + data.size() - sizeof(line) - sizeof(col), sizeof(line)); - Path path(data.constData(), data.size() - sizeof(col) - sizeof(line)); - uint32_t fileId = Location::fileId(path); - if (!fileId) { - path.resolve(); - fileId = Location::fileId(path); - } - if (!fileId && flag == CreateLocation) - fileId = Location::insertFile(path); - if (fileId) - return Location(fileId, line, col); - error("%s:%d:%d is not indexed", path.constData(), line, col); - return Location(); - } - static bool parse(const String &str, const Path &pwd, Path::ResolveMode mode, - Path *path, uint32_t *line, uint32_t *col) - { - const size_t lastColon = str.lastIndexOf(':', str.size() - 2); - if (lastColon == String::npos) - return false; - const size_t secondLastColon = str.lastIndexOf(':', lastColon - 1); - if (secondLastColon == String::npos) - return false; - const char *cstr = str.constData(); - char *end; - assert(line); - *line = static_cast(strtoul(cstr + secondLastColon + 1, &end, 10)); - if (*end != ':' || end == str + secondLastColon + 1) - return false; - assert(col); - *col = static_cast(strtoul(cstr + lastColon + 1, &end, 10)); - if ((*end && *end != ':') || end == str + lastColon + 1) - return false; - - *path = Path::resolved(str.left(secondLastColon), mode, pwd); - return path->isFile(); - } - - static String encode(const String &str, const Path &pwd = Path()) - { - uint32_t line, col; - Path path; - if (!parse(str, pwd, Path::MakeAbsolute, &path, &line, &col)) - return String(); - char buf[8]; - memcpy(buf, &line, sizeof(line)); - memcpy(buf + 4, &col, sizeof(col)); - path.append(buf, 8); - return path; - } - - static Location fromPathLineAndColumn(const String &str, const Path &pwd = Path()) - { - uint32_t line, col; - Path path; - if (!parse(str, pwd, Path::RealPath, &path, &line, &col)) - return Location(); - - const uint32_t fileId = Location::fileId(path); - if (!fileId) - return Location(); - return Location(fileId, line, col); - } - static Hash idsToPaths() - { - LOCK(); - return sIdsToPaths; - } - static Hash pathsToIds() - { - LOCK(); - return sPathsToIds; - } - - static void iterate(std::function func) - { - LOCK(); - for (const auto &it : sPathsToIds) { - func(it.first, it.second); - } - } - static bool init(const Hash &pathsToIds); - static void init(const Hash &idsToPaths); - - static void set(const Path &path, uint32_t fileId) - { - LOCK(); - uint32_t &refId = sPathsToIds[path]; - assert(!refId || refId == fileId); - refId = fileId; - Path &p = sIdsToPaths[fileId]; - if (p.isEmpty()) { - p = path; - } else { - assert(p == path || path.resolved() == p); - } - sLastId = std::max(sLastId, fileId); - } -private: -#ifndef RTAGS_SINGLE_THREAD - static std::mutex sMutex; - static void saveFileIds(); -#endif - static Hash sPathsToIds; - static Hash sIdsToPaths; - static uint32_t sLastId; - enum { - FileBits = 22, - LineBits = 21, - ColumnBits = 64 - FileBits - LineBits - }; - static const uint64_t FILEID_MASK; - static const uint64_t LINE_MASK; - static const uint64_t COLUMN_MASK; -}; - -RCT_FLAGS(Location::ToStringFlag); - -template <> struct FixedSize -{ - static constexpr size_t value = sizeof(Location::value); -}; - -template <> inline Serializer &operator<<(Serializer &s, const Location &t) -{ - s.write(reinterpret_cast(&t.value), sizeof(uint64_t)); - return s; -} - -inline bool operator==(Location loc, const String &str) -{ - const Location fromPath = Location::fromPathLineAndColumn(str); - return loc == fromPath; -} - -inline bool operator!=(Location loc, const String &str) -{ - const Location fromPath = Location::fromPathLineAndColumn(str); - return loc != fromPath; -} - -inline bool operator==(const String &str, Location loc) -{ - const Location fromPath = Location::fromPathLineAndColumn(str); - return loc == fromPath; -} - -inline bool operator!=(const String &str, Location loc) -{ - const Location fromPath = Location::fromPathLineAndColumn(str); - return loc != fromPath; -} - -template <> inline Deserializer &operator>>(Deserializer &s, Location &t) -{ - s.read(reinterpret_cast(&t), sizeof(uint64_t)); - return s; -} - -static inline Log operator<<(Log dbg, Location loc) -{ - dbg << loc.toString(); - return dbg; -} - -inline String Location::debug() const -{ - return toString(NoColor|AbsolutePath); -} - -#endif diff --git a/rtags/src/LogObject.h b/rtags/src/LogObject.h deleted file mode 100644 index a156293..0000000 --- a/rtags/src/LogObject.h +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef LogObject_h -#define LogObject_h - -#include "rct/Connection.h" -#include "rct/Log.h" -#include "rct/String.h" - -class LogObject : public LogOutput -{ -public: - LogObject(const std::shared_ptr &conn, int level) - : LogOutput(level), mConnection(conn) - { - conn->disconnected().connect(std::bind(&LogOutput::remove, this)); - } - - virtual void log(const char *msg, int len) override - { - EventLoop::mainEventLoop()->callLaterMove(std::bind((bool(Connection::*)(Message&&))&Connection::send, mConnection, std::placeholders::_1), - ResponseMessage(String(msg, len))); - } - - virtual bool testLog(int level) const override - { - if (logLevel() < 0 || level < 0) - return level == logLevel(); - return LogOutput::testLog(level); - } -private: - const std::shared_ptr &mConnection; -}; - -#endif diff --git a/rtags/src/LogOutputMessage.h b/rtags/src/LogOutputMessage.h deleted file mode 100644 index c2dd9c7..0000000 --- a/rtags/src/LogOutputMessage.h +++ /dev/null @@ -1,48 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef OutputMessage_h -#define OutputMessage_h - -#include "RTagsMessage.h" - -class LogOutputMessage : public RTagsMessage -{ -public: - enum { MessageId = LogOutputId }; - - LogOutputMessage(LogLevel level = LogLevel::Error, unsigned int flags = 0) - : RTagsMessage(MessageId), mLevel(level), mFlags(flags) - { - } - - LogLevel level() const { return mLevel; } - unsigned int flags() const { return mFlags; } - - void encode(Serializer &serializer) const - { - serializer << mCommandLine << mLevel << mFlags; - } - - void decode(Deserializer &deserializer) - { - deserializer >> mCommandLine >> mLevel >> mFlags; - } -private: - LogLevel mLevel; - unsigned int mFlags; -}; - -#endif diff --git a/rtags/src/Match.h b/rtags/src/Match.h deleted file mode 100644 index f7257c2..0000000 --- a/rtags/src/Match.h +++ /dev/null @@ -1,126 +0,0 @@ - -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef Match_h -#define Match_h - -#include - -#include "Location.h" -#include "rct/Flags.h" -#include "rct/Log.h" -#include "rct/Rct.h" -#include "rct/String.h" - -class Match -{ -public: - enum Flag { - Flag_None = 0x0, - Flag_StringMatch = 0x1, - Flag_Regex = 0x2, - Flag_CaseInsensitive = 0x4 - }; - - inline Match() - {} - - inline Match(const String &pattern, Flags f = Flag_StringMatch); - inline Match(Match &&other) noexcept - : mRegex(std::move(other.mRegex)), mPattern(std::move(other.mPattern)), mFlags(other.mFlags) - {} - inline Match(const Match &other) - : mRegex(other.mRegex), mPattern(other.mPattern), mFlags(other.mFlags) - {} - - Flags flags() const { return mFlags; } - - inline bool match(const String &text) const - { - if (indexIn(text) != String::npos) - return true; - if (mFlags & Flag_StringMatch) - return mPattern.indexOf(text, 0, (mFlags & Flag_CaseInsensitive - ? String::CaseInsensitive - : String::CaseSensitive)) != String::npos; - return false; - } - - inline size_t indexIn(const String &text) const - { - size_t index = String::npos; - if (mFlags & Flag_StringMatch) - index = text.indexOf(mPattern, 0, mFlags & Flag_CaseInsensitive ? String::CaseInsensitive : String::CaseSensitive); - if (index == String::npos && mFlags & Flag_Regex) { - index = Rct::indexIn(text, mRegex); - } - return index; - } - inline bool isEmpty() const - { - return !mFlags || mPattern.isEmpty(); - } - - inline std::regex regex() const - { - return mRegex; - } - - inline String pattern() const - { - return mPattern; - } - uint32_t fileId() const - { - return Location::fileId(mPattern); - } -private: - std::regex mRegex; - String mPattern; - Flags mFlags; -}; -RCT_FLAGS(Match::Flag); - -inline Log operator<<(Log log, const Match &match) -{ - String ret = "Match(flags: "; - ret += String::number(match.flags().cast(), 16); - if (match.flags() & Match::Flag_Regex) - ret += " rx"; - if (!match.pattern().isEmpty()) - ret += " pattern: " + match.pattern(); - ret += ")"; - log << ret; - return log; -} - -inline Match::Match(const String &pattern, Flags f) - : mFlags(f) -{ - if (mFlags & Flag_Regex) { - try { - mRegex = pattern.ref(); - } catch (const std::regex_error &err) { - mFlags &= ~Flag_Regex; - } - } - mPattern = pattern; -} - - - - -#endif diff --git a/rtags/src/Preprocessor.cpp b/rtags/src/Preprocessor.cpp deleted file mode 100644 index be6dc80..0000000 --- a/rtags/src/Preprocessor.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "Preprocessor.h" -#include "Server.h" - -#include "rct/Connection.h" -#include "rct/Log.h" -#include "rct/Process.h" -#include "RTags.h" - -const Flags SourceFlags = (Source::IncludeSourceFile - | Source::IncludeExtraCompiler - | Source::ExcludeDefaultArguments - | Source::ExcludeDefaultIncludePaths - | Source::ExcludeDefaultDefines - | Source::IncludeIncludePaths - | Source::IncludeDefines); - -Preprocessor::Preprocessor(const Source &source, const std::shared_ptr &connection) - : mSource(source), mConnection(connection) -{ - Server::instance()->filterBlockedArguments(mSource); - mArgs = mSource.toCommandLine(SourceFlags); - mArgs.append("-E"); - mProcess.reset(new Process); - mProcess->finished().connect(std::bind(&Preprocessor::onProcessFinished, this)); -} - -void Preprocessor::preprocess() -{ - mProcess->start(mSource.compiler(), mArgs); -} - -void Preprocessor::onProcessFinished() -{ - mConnection->client()->setWriteMode(SocketClient::Synchronous); - mConnection->write<256>("// %s %s", mSource.compiler().constData(), String::join(mArgs, ' ').constData()); - mConnection->write(mProcess->readAllStdOut()); - const String err = mProcess->readAllStdErr(); - if (!err.isEmpty()) { - mConnection->write<1024>("/* %s */", err.constData()); - } - mConnection->finish(); - EventLoop::deleteLater(this); -} diff --git a/rtags/src/Preprocessor.h b/rtags/src/Preprocessor.h deleted file mode 100644 index ea416c7..0000000 --- a/rtags/src/Preprocessor.h +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef PREPROCESSOR_H -#define PREPROCESSOR_H - -#include - -#include "Source.h" - -class Connection; -class Process; -class Preprocessor -{ -public: - Preprocessor(const Source &source, const std::shared_ptr &connection); - - void preprocess(); -private: - void onProcessFinished(); - Source mSource; - List mArgs; - std::shared_ptr mConnection; - std::unique_ptr mProcess; -}; - -#endif diff --git a/rtags/src/ProcThread.cpp b/rtags/src/ProcThread.cpp deleted file mode 100644 index 84dbc56..0000000 --- a/rtags/src/ProcThread.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "ProcThread.h" -#include -#include "RTags.h" -#ifdef RTAGS_HAS_PROC -#include -#include -#endif - -ProcThread::ProcThread(int interval) - : Thread(), mInterval(interval) -{ -#ifdef RTAGS_HAS_PROC - mPath = "/proc/"; -#endif -} - -ProcThread::~ProcThread() -{ -} - -void ProcThread::run() -{ - while (true) { - { - std::unique_lock lock(mMutex); - if (!mInterval) { - break; - } - if (mCond.wait_for(lock, std::chrono::milliseconds(mInterval)) != std::cv_status::timeout) { - break; - } - } - readProc(); - } -} - -void ProcThread::stop() -{ - { - std::unique_lock lock(mMutex); - mInterval = 0; - mCond.notify_one(); - } - join(); -} - -struct ParseNode { - char cmdLine[16384]; - char cwd[PATH_MAX]; - List environ; - -}; -void ProcThread::readProc() -{ - for (auto &pair : mNodes) { - pair.second = true; - } -#ifdef RTAGS_HAS_PROC - DIR *dir = opendir("/proc/"); - int found = 0; - StopWatch sw; - List nodes(1); - while (const dirent *p = readdir(dir)) { -#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE) - if (p->d_type != DT_DIR) - continue; -#endif - const int pid = atoi(p->d_name); - if (!pid) - continue; - auto it = mNodes.find(pid); - if (it != mNodes.end()) { - it->second = false; - continue; - } else { - mNodes[pid] = false; - } - - char file[PATH_MAX]; // should be enough for everyone - snprintf(file, sizeof(file), "/proc/%s/cmdline", p->d_name); - FILE *f = fopen(file, "r"); - if (!f) { - // error("Can't open %s for reading", file); - continue; - } - - auto &node = nodes.back(); - - size_t read = fread(node.cmdLine, 1, sizeof(node.cmdLine), f); - fclose(f); - if (!read) { - // error("Can't read from %s", file); - continue; - } - - if (!strncmp(node.cmdLine, "/bin/bash", 9) || !strncmp(node.cmdLine, "/bin/sh", 7)) - continue; - - while (read > 0 && !node.cmdLine[read-1]) - --read; // skip trailing zeroes - const char *prev = node.cmdLine; - enum { - Dunno, - Yay, - Nay - } hasSource = Dunno; - for (size_t i=0; i prev; --ext) { - if (*ext == '.') { - char extBuf[16]; - const size_t size = i - 1 - (ext - node.cmdLine); - if (size < sizeof(extBuf)) { - memcpy(extBuf, ext + 1, size); - extBuf[size] = '\0'; - if (Path::isSource(extBuf)) { - hasSource = Yay; - } - } - break; - } - } - } - prev = &node.cmdLine[i]; - default: - break; - } - } - if (hasSource != Yay) - continue; - - // error() << "GOT SOURCE" << node.cmdLine; - - snprintf(file, sizeof(file), "/proc/%s/cwd", p->d_name); - const int w = readlink(file, node.cwd, sizeof(node.cwd) - 2); - if (w <= 0) { - // error("Can't follow link from %s", file); - continue; - } - - if (node.cwd[w - 1] != '/') { - node.cwd[w] = '/'; - node.cwd[w + 1] = '\0'; - } else { - node.cwd[w] = '\0'; - } - - snprintf(file, sizeof(file), "/proc/%s/environ", p->d_name); - f = fopen(file, "r"); - if (!f) { - // error("Can't open file %s", file); - continue; - } - - char env[16384]; - read = fread(env, 1, sizeof(env), f); - fclose(f); - if (!read) { - // error("Can't read from from %s", file); - continue; - } - - while (read > 0 && !node.cmdLine[read-1]) - --read; // skip trailing zeroes - size_t last = 0; - for (size_t i=0; i last) { - node.environ.append(String(env + last, read - last)); - } - nodes.append(ParseNode()); - // error() << "GONNA PARSE" << node.cmdLine; - // if (!sources.isEmpty()) { - // error() << "GOT SOURCES" << sources[0].sourceFile(); - // } - ++found; - } - SourceCache cache; - for (size_t i=0; i paths; - SourceList sources = Source::parse(node.cmdLine, node.cwd, node.environ, &paths, &cache); - if (sources.size()) { - error() << "GOT SOURCES" << node.cmdLine; - } - // error() << "GOT SOURCES" << sources.size() << "from" << node.cmdLine - // << paths; - } - - Hash::iterator it = mNodes.begin(); - while (it != mNodes.end()) { - if (it->second) { - mNodes.erase(it++); - } else { - ++it; - } - } - // printf("%d took %llu\n", found, sw.elapsed()); - closedir(dir); -#endif -} diff --git a/rtags/src/ProcThread.h b/rtags/src/ProcThread.h deleted file mode 100644 index d853714..0000000 --- a/rtags/src/ProcThread.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef ProcThread_h -#define ProcThread_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include "Source.h" - -#if defined(OS_Linux) || defined(OS_FreeBSD) || 1 -#define RTAGS_HAS_PROC -#endif - -class ProcThread : public Thread -{ -public: - ProcThread(int interval); - ~ProcThread(); - - void stop(); - virtual void run(); - Signal > &command() { return mCommand; } -private: - void readProc(); - - Signal > mCommand; - std::mutex mMutex; - std::condition_variable mCond; - int mInterval; - -#ifdef RTAGS_HAS_PROC - Path mPath; -#endif - Hash mNodes; -}; - -#endif diff --git a/rtags/src/Project.cpp b/rtags/src/Project.cpp deleted file mode 100644 index b82d895..0000000 --- a/rtags/src/Project.cpp +++ /dev/null @@ -1,2943 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "Project.h" - -#include -#include -#include -#include - -#include "Diagnostic.h" -#include "FileManager.h" -#include "CompilerManager.h" -#include "IndexDataMessage.h" -#include "JobScheduler.h" -#include "LogOutputMessage.h" -#include "rct/DataFile.h" -#include "rct/Log.h" -#include "rct/MemoryMonitor.h" -#include "rct/Path.h" -#include "rct/Rct.h" -#include "rct/ReadLocker.h" -#include "rct/Thread.h" -#include "rct/Value.h" -#include "RTags.h" -#include "RTagsLogOutput.h" -#include "Server.h" -#include "RTagsVersion.h" - -enum { DirtyTimeout = 100, ReloadCompileCommandsTimeout = 500 }; - -class Dirty -{ -public: - virtual ~Dirty() {} - virtual Set dirtied() const = 0; - virtual bool isDirty(const SourceList &) = 0; -}; - -class SimpleDirty : public Dirty -{ -public: - void init(const std::shared_ptr &project, const Set &dirty = Set()) - { - mProject = project; - for (auto fileId : dirty) { - mDirty.insert(fileId); - mDirty += project->dependencies(fileId, Project::DependsOnArg); - } - } - - virtual Set dirtied() const override - { - return mDirty; - } - - void insert(uint32_t fileId) - { - if (mDirty.insert(fileId)) - mDirty += mProject->dependencies(fileId, Project::DependsOnArg); - } - - virtual bool isDirty(const SourceList &sourceList) override - { - return mDirty.contains(sourceList.fileId()); - } - - Set mDirty; - std::shared_ptr mProject; -}; - -class ComplexDirty : public Dirty -{ -public: - virtual Set dirtied() const override - { - return mDirty; - } - void insertDirtyFile(uint32_t fileId) - { - mDirty.insert(fileId); - } - inline uint64_t lastModified(uint32_t fileId) - { - uint64_t &time = mLastModified[fileId]; - if (!time) { - time = Location::path(fileId).lastModifiedMs(); - } - return time; - } - - Hash mLastModified; - Set mDirty; -}; - -class SuspendedDirty : public ComplexDirty -{ -public: - bool isDirty(const SourceList &) override - { - return false; - } -}; - -class IfModifiedDirty : public ComplexDirty -{ -public: - IfModifiedDirty(const std::shared_ptr &project, const Match &match = Match()) - : mProject(project), mMatch(match) - { - } - - virtual bool isDirty(const SourceList &sourceList) override - { - bool ret = false; - - const uint32_t fileId = sourceList.fileId(); - if (mMatch.isEmpty() || mMatch.match(Location::path(fileId))) { - for (auto it : mProject->dependencies(fileId, Project::ArgDependsOn)) { - uint64_t depLastModified = lastModified(it); - if (!depLastModified || depLastModified > sourceList.parsed) { - ret = true; - insertDirtyFile(it); - } - } - if (ret) - mDirty.insert(fileId); - - assert(!ret || mDirty.contains(fileId)); - } - return ret; - } - - std::shared_ptr mProject; - Match mMatch; -}; - - -class WatcherDirty : public ComplexDirty -{ -public: - WatcherDirty(const std::shared_ptr &project, const Set &modified) - { - for (auto it : modified) { - mModified[it] = project->dependencies(it, Project::DependsOnArg); - } - } - - virtual bool isDirty(const SourceList &sourceList) override - { - bool ret = false; - - for (auto it : mModified) { - const auto &deps = it.second; - if (deps.contains(sourceList.fileId())) { - const uint64_t depLastModified = lastModified(it.first); - if (!depLastModified || depLastModified > sourceList.parsed) { - // dependency is gone - ret = true; - insertDirtyFile(it.first); - } - } - } - - if (ret) - insertDirtyFile(sourceList.fileId()); - return ret; - } - - Hash > mModified; -}; - -static Project::DependencyMode modeForSymbol(const Symbol &symbol) -{ - Project::DependencyMode mode = symbol.isDefinition() ? Project::ArgDependsOn : Project::DependsOnArg; - switch (symbol.kind) { - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: - case CXCursor_StructDecl: - case CXCursor_FunctionDecl: - if (!symbol.isDefinition()) // forward declarations for global functions and classes/structs - mode = Project::All; - break; - case CXCursor_VarDecl: - if (symbol.kind == CXCursor_VarDecl && symbol.linkage == CXLinkage_External && !symbol.isDefinition()) - mode = Project::All; - default: - break; - } - - return mode; -} - -static bool loadDependencies(DataFile &file, Dependencies &dependencies) -{ - int size; - file >> size; - for (int i=0; i> fileId; - if (!fileId) - return false; - Flags flags; - file >> flags; - dependencies[fileId] = new DependencyNode(fileId, flags); - } - for (int i=0; i> links; - if (links) { - uint32_t dependee; - file >> dependee; - DependencyNode *ee = dependencies[dependee]; - if (!ee) { - return false; - } - while (links--) { - uint32_t dependent; - file >> dependent; - DependencyNode *ent = dependencies[dependent]; - if (!ent) { - return false; - } - ent->include(ee); - } - } - } - return true; -} - -static void saveDependencies(DataFile &file, const Dependencies &dependencies) -{ - file << static_cast(dependencies.size()); - for (const auto &it : dependencies) { - file << it.first << it.second->flags; - } - for (const auto &it : dependencies) { - file << static_cast(it.second->dependents.size()); - if (!it.second->dependents.isEmpty()) { - file << it.first; - for (const auto &dep : it.second->dependents) { - file << dep.first; - } - } - } -} - -Project::Project(const Path &path) - : mPath(path), mProjectDataDir(RTags::encodeSourceFilePath(Server::instance()->options().dataDir, path)), - mJobCounter(0), mJobsStarted(0), mLastIdleTime(time(0)), mBytesWritten(0), mSaveDirty(false) -{ - mProjectFilePath = mProjectDataDir + "project"; - mSourcesFilePath = mProjectDataDir + "sources"; -} - -Project::~Project() -{ - if (mSaveDirty) - save(); - for (const auto &job : mActiveJobs) { - assert(job.second); - Server::instance()->jobScheduler()->abort(job.second); - } - mDependencies.deleteAll(); - - assert(EventLoop::isMainThread()); - mDirtyTimer.stop(); - mReloadCompileCommandsTimer.stop(); -} - -static bool hasSourceDependency(const DependencyNode *node, const std::shared_ptr &project, Set &seen) -{ - const Path path = Location::path(node->fileId); - // error("%s %d %d", path.constData(), path.isFile(), path.isSource()); - if (path.isFile() && path.isSource() && project->hasSource(node->fileId)) { - return true; - } - for (auto it : node->dependents) { - if (seen.insert(it.first) && hasSourceDependency(it.second, project, seen)) - return true; - } - return false; -} - -static inline bool hasSourceDependency(const DependencyNode *node, const std::shared_ptr &project) -{ - Set seen; - return hasSourceDependency(node, project, seen); -} - -bool Project::readSources(const Path &path, IndexParseData &data, String *err) -{ - DataFile file(path, RTags::SourcesFileVersion); - if (!file.open(DataFile::Read)) { - Path::rm(path); - if (err && !file.error().isEmpty()) - *err = file.error(); - return false; - } - - file >> data; - - if (Sandbox::hasRoot()) { - forEachSource(data, [](Source &source) { - for (String &arg : source.arguments) { - Sandbox::decode(arg); - } - return Continue; - }); - } - return true; -} - -bool Project::init() -{ - const JobScheduler::JobScope scope(Server::instance()->jobScheduler()); - const Server::Options &options = Server::instance()->options(); - if (!(options.options & Server::NoFileSystemWatch)) { - mWatcher.modified().connect(std::bind(&Project::onFileModified, this, std::placeholders::_1)); - mWatcher.added().connect(std::bind(&Project::onFileAdded, this, std::placeholders::_1)); - mWatcher.removed().connect(std::bind(&Project::onFileRemoved, this, std::placeholders::_1)); - } - if (!(options.options & Server::NoFileManager)) { - mFileManager.reset(new FileManager(shared_from_this())); - mWatcher.removed().connect([this](const Path &path) { if (mWatchedPaths.value(path.parentDir()) & Watch_FileManager) mFileManager->onFileRemoved(path); }); - mWatcher.added().connect([this](const Path &path) { if (mWatchedPaths.value(path.parentDir()) & Watch_FileManager) mFileManager->onFileAdded(path); }); - } - - mDirtyTimer.timeout().connect(std::bind(&Project::onDirtyTimeout, this, std::placeholders::_1)); - mReloadCompileCommandsTimer.timeout().connect(std::bind(&Project::reloadCompileCommands, this)); - - String err; - if (!Project::readSources(mSourcesFilePath, mIndexParseData, &err)) { - if (!err.isEmpty()) - error("Sources restore error %s: %s", mPath.constData(), err.constData()); - - return false; - } - - auto reindexAll = [this]() { - mProjectFilePath.visit([](const Path &path) { - if (strcmp(path.fileName(), "sources")) { - if (path.isDir()) { - Path::rmdir(path); - } else { - path.rm(); - } - } - return Path::Continue; - }); - auto parseData = std::move(mIndexParseData); - processParseData(std::move(parseData)); - }; - - DataFile file(mProjectFilePath, RTags::DatabaseVersion); - if (!file.open(DataFile::Read)) { - if (!file.error().isEmpty()) - error("Restore error %s: %s", mPath.constData(), file.error().constData()); - reindexAll(); - return true; - } - - { - std::lock_guard lock(mMutex); - file >> mVisitedFiles; - Sandbox::decode(mVisitedFiles); - } - file >> mDiagnostics; - for (const auto &info : mIndexParseData.compileCommands) - watch(Location::path(info.first), Watch_CompileCommands); - - if (!loadDependencies(file, mDependencies)) { - mDependencies.deleteAll(); - mVisitedFiles.clear(); - mDiagnostics.clear(); - error("Restore error %s: Failed to load dependencies.", mPath.constData()); - reindexAll(); - return true; - } - - for (const auto &dep : mDependencies) { - watchFile(dep.first); - } - - bool needsSave = false; - std::unique_ptr dirty; - - if (Server::instance()->suspended()) { - dirty.reset(new SuspendedDirty); - } else { - dirty.reset(new IfModifiedDirty(shared_from_this())); - } - - Set missingFileMaps; - { - List removed; - int idx = 0; - bool outputDirty = false; - if (mDependencies.size() >= 100) { - logDirect(LogLevel::Error, String::format<128>("Restoring %s ", mPath.constData()), LogOutput::StdOut); - outputDirty = true; - } - const std::shared_ptr project = shared_from_this(); - for (auto it : mDependencies) { - const Path path = Location::path(it.first); - if (!path.isFile()) { - warning() << path << "seems to have disappeared"; - dirty.get()->insertDirtyFile(it.first); - - const Set dependents = dependencies(it.first, DependsOnArg); - for (auto dependent : dependents) { - dirty.get()->insertDirtyFile(dependent); - } - removed << it.first; - needsSave = true; - } else { - String errorString; - if (!validate(it.first, options.options & Server::ValidateFileMaps ? Validate : StatOnly, &errorString)) { - if (!errorString.isEmpty()) { - if (outputDirty) { - outputDirty = false; - logDirect(LogLevel::Error, String("\n"), LogOutput::StdOut); - } - error() << errorString; - } - if (hasSource(it.first) || hasSourceDependency(it.second, project)) { - missingFileMaps.insert(it.first); - } else { - removed << it.first; - needsSave = true; - } - } - } - if (++idx % 100 == 0) { - outputDirty = true; - logDirect(LogLevel::Error, ".", 1, LogOutput::StdOut); - // error("%d/%d (%.2f%%)", idx, count, (idx / static_cast(count)) * 100.0); - } - } - if (outputDirty) - logDirect(LogLevel::Error, "\n", 1, LogOutput::StdOut); - for (uint32_t r : removed) { - removeDependencies(r); - } - } - - forEachSourceList([&dirty, this, &needsSave](SourceList &src) -> VisitResult { - uint32_t fileId = src.fileId(); - const Path sourceFile = Location::path(fileId); - if (!sourceFile.isFile()) { - warning() << sourceFile << "seems to have disappeared"; - removeDependencies(fileId); - dirty.get()->insertDirtyFile(fileId); - needsSave = true; - return Remove; - } - watchFile(fileId); - return Continue; - }); - - reloadCompileCommands(); - - if (needsSave) - save(); - startDirtyJobs(dirty.get(), IndexerJob::Dirty|IndexerJob::NoAbort); - // don't want to abort the jobs we just started from reloadCompileCommands - if (!missingFileMaps.isEmpty()) { - SimpleDirty simple; - simple.init(shared_from_this(), missingFileMaps); - startDirtyJobs(&simple, IndexerJob::Dirty); - } - return true; -} - -bool Project::match(const Match &p, bool *indexed) const -{ - Path paths[] = { p.pattern(), p.pattern() }; - paths[1].resolve(); - const int count = paths[1].compare(paths[0]) ? 2 : 1; - bool ret = false; - const Path resolvedPath = mPath.resolved(); - for (int i=0; i flags, Set &&filter = Set()) -{ - Diagnostics::const_iterator it; - Diagnostics::const_iterator end; - { - if (Server::instance()->hadActiveBuffers()) { - Set active = Server::instance()->activeBuffers(); - if (filter.isEmpty()) { - filter = std::move(active); - } else { - filter = filter.intersected(active); - } - if (filter.isEmpty()) - return String(); - } - } - - const size_t filterSize = filter.size(); - - switch (filterSize) { - case 0: - it = diagnostics.begin(); - end = diagnostics.end(); - break; - case 1: { - uint32_t fileId = *filter.begin(); - it = diagnostics.lower_bound(Location(fileId, 0, 0)); - end = diagnostics.lower_bound(Location(fileId + 1, 0, 0)); - break; } - default: { - it = diagnostics.lower_bound(Location(*filter.begin(), 0, 0)); - auto e = filter.end(); - --e; - end = diagnostics.lower_bound(Location(*e, 0, 0)); - break; } - } - - if (flags & QueryMessage::JSON) { - std::function toValue = [&toValue](uint32_t file, Location loc, const Diagnostic &diagnostic) { - Value value; - if (loc.fileId() != file) - value["file"] = loc.path(); - value["line"] = loc.line(); - value["column"] = loc.column(); - if (diagnostic.length > 0) - value["length"] = diagnostic.length; - value["type"] = severityToString(diagnostic.type()); - if (!diagnostic.message.isEmpty()) - value["message"] = diagnostic.message; - if (!diagnostic.children.isEmpty()) { - Value &children = value["children"]; - for (const auto &c : diagnostic.children) { - Value val = toValue(file, c.first, c.second); - children.push_back(std::move(val)); - } - } - return value; - }; - - Value val; - Value &checkStyle = val["checkStyle"]; - checkStyle = Value(Value::Type_Map); - Value *currentFile = 0; - uint32_t lastFileId = 0; - uint32_t ignoredFileId = 0; - while (it != end) { - const auto &ref = it++; - const uint32_t f = ref->first.fileId(); - if (f == ignoredFileId) { - continue; - } - if (f != lastFileId) { - if (filterSize && !filter.remove(f)) { - ignoredFileId = f; - continue; - } - - currentFile = &checkStyle[ref->first.path()]; - lastFileId = f; - } - currentFile->push_back(toValue(lastFileId, ref->first, ref->second)); - } - for (uint32_t f : filter) { - checkStyle[Location::path(f)] = Value(Value::Type_List); - } - return val.toJSON(); - } - - static const char *header[] = { - "\n ", - "(list 'checkstyle " - }; - static const char *fileEmpty[] = { - "\n ", - "(cons \"%s\" nil)" - }; - static const char *startFile[] = { - "\n ", - "(cons \"%s\" (list" - }; - static const char *endFile[] = { - "\n ", - "))" - }; - static const char *trailer[] = { - "\n ", - ")" - }; - std::function formatDiagnostic; - - enum DiagnosticsFormat { - Diagnostics_XML, - Diagnostics_Elisp - } const format = flags & QueryMessage::Elisp ? Diagnostics_Elisp : Diagnostics_XML; - - if (format == Diagnostics_XML) { - formatDiagnostic = [](Location loc, const Diagnostic &diagnostic, uint32_t) { - return String::format<1024>("\n ", - loc.line(), loc.column(), - (diagnostic.length <= 0 ? "" - : String::format<32>("length=\"%d\" ", diagnostic.length).constData()), - severityToString(diagnostic.type()), RTags::xmlEscape(diagnostic.message).constData()); - }; - } else { - formatDiagnostic = [&formatDiagnostic](Location loc, const Diagnostic &diagnostic, uint32_t file) { - String children; - if (!diagnostic.children.isEmpty()) { - children = "(list"; - for (const auto &c : diagnostic.children) { - children << ' ' << formatDiagnostic(c.first, c.second, file); - } - children << ")"; - } else { - children = "nil"; - } - const bool fn = (loc.fileId() != file); - return String::format<1024>(" (list %s%s%s %d %d %s '%s \"%s\" %s)", - fn ? "\"" : "", - fn ? loc.path().constData() : "nil", - fn ? "\"" : "", - loc.line(), - loc.column(), - diagnostic.length > 0 ? String::number(diagnostic.length).constData() : "nil", - severityToString(diagnostic.type()), - RTags::elispEscape(diagnostic.message).constData(), - children.constData()); - }; - } - String ret; - uint32_t lastFileId = 0; - uint32_t ignoredFileId = 0; - bool first = true; - while (it != end) { - const auto &entry = *it++; - Location loc = entry.first; - const uint32_t f = loc.fileId(); - if (f == ignoredFileId) - continue; - if (f != lastFileId) { - if (filterSize && !filter.remove(f)) { - ignoredFileId = f; - continue; - } - - if (first) { - ret = header[format]; - first = false; - } - if (lastFileId) - ret << endFile[format]; - lastFileId = loc.fileId(); - ret << String::format<1024>(startFile[format], loc.path().constData()); - } - const Diagnostic &diagnostic = entry.second; - ret << formatDiagnostic(loc, diagnostic, lastFileId); - } - if (lastFileId) { - ret << endFile[format]; - } - - for (uint32_t f : filter) { - const Path path = Location::path(f); - // error() << "empty diags for" << path; - first = true; - ret << header[format] - << String::format<256>(fileEmpty[format], path.constData()) - << endFile[format] << trailer[format]; - } - if (!first) - ret << trailer[format]; - - return ret; -} - -void Project::onJobFinished(const std::shared_ptr &job, const std::shared_ptr &msg) -{ - FileMapScopeScope scope(this); - mBytesWritten += msg->bytesWritten(); - std::shared_ptr restart; - const uint32_t fileId = job->fileId(); - auto j = mActiveJobs.take(fileId); - if (!j) { - error() << "Couldn't find JobData for" << Location::path(fileId) << msg->id() << job->id << job.get(); - return; - } else if (j != job) { - error() << "Wrong IndexerJob for" << Location::path(fileId) << msg->id() << job->id << job.get(); - return; - } - - const bool success = job->flags & IndexerJob::Complete; - assert(!(job->flags & IndexerJob::Aborted)); - assert(((job->flags & (IndexerJob::Complete|IndexerJob::Crashed)) == IndexerJob::Complete) - || ((job->flags & (IndexerJob::Complete|IndexerJob::Crashed)) == IndexerJob::Crashed)); - const auto &options = Server::instance()->options(); - if (!success) { - releaseFileIds(job->visited); - } - - if (!hasSource(fileId)) { - releaseFileIds(job->visited); - error() << "Can't find source for" << Location::path(fileId); - return; - } - if (!(msg->flags() & IndexDataMessage::ParseFailure)) { - for (uint32_t file : job->visited) { - if (!validate(file, Validate)) { - releaseFileIds(job->visited); - dirty(fileId); - return; - } - } - } - - const int idx = mJobCounter - mActiveJobs.size(); - updateDiagnostics(fileId, msg->diagnostics()); - if (options.options & Server::Progress) { - log([&](const std::shared_ptr &output) { - if (output->testLog(RTags::DiagnosticsLevel)) { - QueryMessage::Flag format = QueryMessage::XML; - if (output->flags() & RTagsLogOutput::Elisp) { - // I know this is RTagsLogOutput because it returned - // true for testLog(RTags::DiagnosticsLevel) - format = QueryMessage::Elisp; - } - - if (format == QueryMessage::XML) { - output->vlog("\n", - idx, mJobCounter); - } else { - std::shared_ptr scheduler = Server::instance()->jobScheduler(); - output->vlog("(list 'progress %d %d %zu)", idx, mJobCounter, scheduler->activeJobCount() + scheduler->pendingJobCount()); - } - } - }); - } - - - - Set visited = msg->visitedFiles(); - updateFixIts(visited, msg->fixIts()); - updateDependencies(fileId, msg); - if (success) { - forEachSources([&msg, fileId](Sources &sources) -> VisitResult { - // error() << "finished with" << Location::path(fileId) << sources.contains(fileId) << msg->parseTime(); - if (sources.contains(fileId)) { - sources[fileId].parsed = msg->parseTime(); - } - return Continue; - }); - logDirect(LogLevel::Error, String::format("[%3d%%] %d/%d %s %s. (%s)", - static_cast(round((double(idx) / double(mJobCounter)) * 100.0)), idx, mJobCounter, - String::formatTime(time(0), String::Time).constData(), - msg->message().constData(), - String::format<16>("priority %d", job->priority()).constData()), - LogOutput::StdOut|LogOutput::TrailingNewLine); - } else { - assert(msg->indexerJobFlags() & IndexerJob::Crashed); - logDirect(LogLevel::Error, String::format("[%3d%%] %d/%d %s %s indexing crashed.", - static_cast(round((double(idx) / double(mJobCounter)) * 100.0)), idx, mJobCounter, - String::formatTime(time(0), String::Time).constData(), - Location::path(fileId).toTilde().constData()), - LogOutput::StdOut|LogOutput::TrailingNewLine); - } - - if (mActiveJobs.isEmpty()) { - mLastIdleTime = time(0); - save(); - double timerElapsed = (mTimer.elapsed() / 1000.0); - const double averageJobTime = timerElapsed / mJobsStarted; - const String m = String::format<1024>("Jobs took %.2fs%s. We're using %lldmb of memory. ", - timerElapsed, mJobsStarted > 1 ? String::format(", (avg %.2fs)", averageJobTime).constData() : "", - static_cast(MemoryMonitor::usage() / (1024 * 1024))); - Log(LogLevel::Error, LogOutput::StdOut|LogOutput::TrailingNewLine) << m; - mJobsStarted = mJobCounter = 0; - - // error() << "Finished this - } else { - mSaveDirty = true; - } -} - -void Project::diagnose(uint32_t fileId) -{ - log([&](const std::shared_ptr &output) { - if (output->testLog(RTags::DiagnosticsLevel)) { - QueryMessage::Flag format = QueryMessage::XML; - if (output->flags() & RTagsLogOutput::Elisp) { - // I know this is RTagsLogOutput because it returned - // true for testLog(RTags::DiagnosticsLevel) - format = QueryMessage::Elisp; - } else if (output->flags() & RTagsLogOutput::JSON) { - format = QueryMessage::JSON; - } - - Set filter; - if (fileId) - filter.insert(fileId); - const String log = formatDiagnostics(mDiagnostics, format, std::move(filter)); - if (!log.isEmpty()) - output->log(log); - } - }); -} - -void Project::diagnoseAll() -{ - log([&](const std::shared_ptr &output) { - if (output->testLog(RTags::DiagnosticsLevel)) { - QueryMessage::Flag format = QueryMessage::XML; - if (output->flags() & RTagsLogOutput::Elisp) { - // I know this is RTagsLogOutput because it returned - // true for testLog(RTags::DiagnosticsLevel) - format = QueryMessage::Elisp; - } else if (output->flags() & RTagsLogOutput::JSON) { - format = QueryMessage::JSON; - } - - const String log = formatDiagnostics(mDiagnostics, format); - if (!log.isEmpty()) - output->log(log); - } - }); -} - -String Project::diagnosticsToString(Flags flags, uint32_t fileId) -{ - Set filter; - if (fileId) - filter.insert(fileId); - return formatDiagnostics(mDiagnostics, flags, std::move(filter)); -} - -bool Project::save() -{ - Path::mkdir(mSourcesFilePath.parentDir(), Path::Recursive); - { - DataFile file(mSourcesFilePath, RTags::SourcesFileVersion); - if (!file.open(DataFile::Write)) { - error("Save error %s: %s", mSourcesFilePath.constData(), file.error().constData()); - return false; - } - file << mIndexParseData; - if (!file.flush()) { - error("Save error %s: %s", mSourcesFilePath.constData(), file.error().constData()); - return false; - } - } - { - DataFile file(mProjectFilePath, RTags::DatabaseVersion); - if (!file.open(DataFile::Write)) { - error("Save error %s: %s", mProjectFilePath.constData(), file.error().constData()); - return false; - } - { - std::lock_guard lock(mMutex); - if (Sandbox::hasRoot()) { - file << Sandbox::encoded(mVisitedFiles); - } else { - file << mVisitedFiles; - } - } - file << mDiagnostics; - saveDependencies(file, mDependencies); - if (!file.flush()) { - error("Save error %s: %s", mProjectFilePath.constData(), file.error().constData()); - return false; - } - } - mSaveDirty = false; - return true; -} - -void Project::index(const std::shared_ptr &job) -{ - const Path sourceFile = job->sourceFile; - static const char *fileFilter = getenv("RTAGS_FILE_FILTER"); - if (fileFilter && !strstr(job->sourceFile.constData(), fileFilter)) { - error() << "Not indexing" << job->sourceFile.constData() << "because of file filter" - << fileFilter; - return; - } - - if (Server::instance()->suspended() && hasSource(job->fileId()) && (job->flags & IndexerJob::Compile)) { - return; - } - - std::shared_ptr &ref = mActiveJobs[job->fileId()]; - if (ref) { - // warning() << "Aborting a job" << ref.get() << Location::path(job->fileId()); - releaseFileIds(ref->visited); - Server::instance()->jobScheduler()->abort(ref); - --mJobCounter; - } - ref = job; - - ++mJobsStarted; - if (!mJobCounter++) { - mTimer.start(); - } - - Server::instance()->jobScheduler()->add(job); -} - -void Project::onFileModified(const Path &path) -{ - debug() << path << "was modified"; - onFileAddedOrModified(path); -} - -void Project::onFileAdded(const Path &path) -{ - debug() << path << "was added"; - onFileAddedOrModified(path); -} - -void Project::onFileAddedOrModified(const Path &file) -{ - const uint32_t fileId = Location::fileId(file); - debug() << file << "was modified" << fileId; - if (!fileId) - return; - // error() << file.fileName() << mCompileCommandsInfos.dir << file; - if (mIndexParseData.compileCommands.contains(fileId)) { - mReloadCompileCommandsTimer.restart(ReloadCompileCommandsTimeout, Timer::SingleShot); - return; - } - - if (Server::instance()->suspended() || mSuspendedFiles.contains(fileId)) { - warning() << file << "is suspended. Ignoring modification"; - return; - } - Server::instance()->jobScheduler()->clearHeaderError(fileId); - if (mPendingDirtyFiles.insert(fileId)) { - mDirtyTimer.restart(DirtyTimeout, Timer::SingleShot); - } -} - -void Project::onFileRemoved(const Path &file) -{ - const uint32_t fileId = Location::fileId(file); - debug() << file << "was removed" << fileId; - if (!fileId) - return; - - if (mIndexParseData.compileCommands.contains(fileId)) { - reloadCompileCommands(); - return; - } - removeSource(fileId); - - Server::instance()->jobScheduler()->clearHeaderError(fileId); - - if (Server::instance()->suspended() || mSuspendedFiles.contains(fileId)) { - warning() << file << "is suspended. Ignoring modification"; - return; - } - if (mPendingDirtyFiles.insert(fileId)) { - mDirtyTimer.restart(DirtyTimeout, Timer::SingleShot); - } -} - -void Project::onDirtyTimeout(Timer *) -{ - Set dirtyFiles = std::move(mPendingDirtyFiles); - WatcherDirty dirty(shared_from_this(), dirtyFiles); - const int dirtied = startDirtyJobs(&dirty, IndexerJob::Dirty); - debug() << "onDirtyTimeout" << dirtyFiles << dirtied; -} - -SourceList Project::sources(uint32_t fileId) const -{ - SourceList ret; - forEachSources([&ret, fileId](const Sources &srcs) { - const auto it = srcs.find(fileId); - if (it != srcs.end()) - ret += it->second; - return Continue; - }); - return ret; -} - -bool Project::hasSource(uint32_t fileId) const -{ - bool ret = false; - forEachSources([&ret, fileId](const Sources &srcs) { - if (srcs.contains(fileId)) { - ret = true; - return Stop; - } - return Continue; - }); - return ret; -} - -Set Project::dependencies(uint32_t fileId, DependencyMode mode) const -{ - Set ret; - if (mode == All) { - for (const auto &node : mDependencies) { - ret.insert(node.first); - } - return ret; - } - ret.insert(fileId); - std::function fill = [&](uint32_t file) { - if (DependencyNode *node = mDependencies.value(file)) { - const auto &nodes = (mode == ArgDependsOn ? node->includes : node->dependents); - for (const auto &it : nodes) { - if (ret.insert(it.first)) - fill(it.first); - } - } - }; - fill(fileId); - return ret; -} - -bool Project::dependsOn(uint32_t source, uint32_t header) const -{ - Set seen; - std::function dep = [&](DependencyNode *node) { - assert(node); - if (!seen.insert(node->fileId)) - return false; - if (node->dependents.contains(source)) - return true; - for (const auto &n : node->dependents) { - if (dep(n.second)) - return true; - } - return false; - }; - DependencyNode *node = mDependencies.value(header); - return node && dep(node); -} - -void Project::removeDependencies(uint32_t fileId) -{ - // error() << "removeDependencies" << Location::path(fileId); - if (DependencyNode *node = mDependencies.take(fileId)) { - for (auto it : node->includes) - it.second->dependents.remove(fileId); - for (auto it : node->dependents) - it.second->includes.remove(fileId); - delete node; - } -} - -void Project::updateDependencies(uint32_t fileId, const std::shared_ptr &msg) -{ - static_cast(fileId); - const bool prune = !(msg->flags() & (IndexDataMessage::InclusionError|IndexDataMessage::ParseFailure)); - // error() << "updateDependencies" << Location::path(fileId) << prune; - Set includeErrors, dirty; - for (auto pair : msg->files()) { - assert(pair.first); - DependencyNode *&node = mDependencies[pair.first]; - // error() << "checking deps" << Location::path(pair.first) << node; - if (!node) { - node = new DependencyNode(pair.first); - } - - if (pair.second & IndexDataMessage::Visited) { - if (pair.second & IndexDataMessage::IncludeError) { - node->flags |= DependencyNode::Flag_IncludeError; - includeErrors.insert(pair.first); - // error() << "got include error for" << Location::path(pair.first); - } else if (node->flags & DependencyNode::Flag_IncludeError) { - // error() << "used to have include error for" << Location::path(pair.first) << node->includes.size(); - node->flags &= ~DependencyNode::Flag_IncludeError; - dirty.insert(pair.first); - // for (auto dep : node->includes) { - // dirty.insert(dep.first); - // // error() << "dirty" << Location::path(dep.first); - // } - for (auto dep : node->dependents) { - dirty.insert(dep.first); - // error() << "dirty" << Location::path(dep.first); - } - } - if (prune) { - for (auto it : node->includes) { - it.second->dependents.remove(pair.first); - // error() << "removing" << Location::path(pair.first) << "from" << Location::path(it.first); - } - // error() << "Removing all includes for" << Location::path(pair.first) << node->includes.size(); - node->includes.clear(); - } - } - watchFile(pair.first); - } - - // // ### this probably deletes and recreates the same nodes very very often - for (auto it : msg->includes()) { - assert(it.first); - assert(it.second); - DependencyNode *&includer = mDependencies[it.first]; - DependencyNode *&inclusiary = mDependencies[it.second]; - // error() << "adding include for" << Location::path(it.first) << Location::path(it.second); - if (!includer) - includer = new DependencyNode(it.first); - if (!inclusiary) - inclusiary = new DependencyNode(it.second); - includer->include(inclusiary); - } - - if (!includeErrors.isEmpty()) { - // error() << "releasing files"; - // for (uint32_t f : includeErrors) { - // error() << Location::path(f); - // } - releaseFileIds(includeErrors); - } - if (!dirty.isEmpty()) { - // error() << "dirtying"; - // for (uint32_t f : dirty) { - // error() << Location::path(f); - // } - SimpleDirty simple; - simple.init(shared_from_this(), dirty); - startDirtyJobs(&simple, IndexerJob::Dirty); - } - // for (auto node : mDependencies) { - // for (auto inc : node.second->includes) { - // if (!inc.second->dependents.contains(node.first)) { - // error() << "SHIT SHIT SHIT" << Location::path(inc.first) << "doesn't have" << Location::path(node.first) << "in its dependents"; - // } - // } - // for (auto inc : node.second->dependents) { - // if (!inc.second->includes.contains(node.first)) { - // error() << "SHIT SHIT SHIT" << Location::path(inc.first) << "doesn't have" << Location::path(node.first) << "in its includes"; - // } - // } - // } -} - -int Project::reindex(const Match &match, - const std::shared_ptr &query, - const std::shared_ptr &wait) -{ - if (query->type() == QueryMessage::Reindex) { - Set dirtyFiles; - - const auto end = mDependencies.constEnd(); - for (auto it = mDependencies.constBegin(); it != end; ++it) { - if (!dirtyFiles.contains(it->first) && (match.isEmpty() || match.match(Location::path(it->first)))) { - dirtyFiles.insert(it->first); - } - } - if (dirtyFiles.isEmpty()) - return 0; - SimpleDirty dirty; - dirty.init(shared_from_this(), dirtyFiles); - return startDirtyJobs(&dirty, IndexerJob::Reindex, query->unsavedFiles(), wait); - } else { - assert(query->type() == QueryMessage::CheckReindex); - IfModifiedDirty dirty(shared_from_this(), match); - return startDirtyJobs(&dirty, IndexerJob::Dirty, query->unsavedFiles(), wait); - } -} - -int Project::remove(const Match &match) -{ - int count = 0; - forEachSourceList([&match, &count](SourceList &src) -> VisitResult { - if (match.match(Location::path(src.fileId()))) { - ++count; - return Remove; - } - return Continue; - }); - return count; -} - -int Project::startDirtyJobs(Dirty *dirty, Flags flags, - const UnsavedFiles &unsavedFiles, - const std::shared_ptr &wait) -{ - const JobScheduler::JobScope scope(Server::instance()->jobScheduler()); - Set toIndex; - forEachSourceList([dirty, &toIndex](const SourceList &sourceList) -> VisitResult { - if (dirty->isDirty(sourceList)) - toIndex.insert(sourceList.fileId()); - return Continue; - }); - const Set dirtyFiles = dirty->dirtied(); - - { - std::lock_guard lock(mMutex); - for (const auto &fileId : dirtyFiles) { - mVisitedFiles.remove(fileId); - } - } - - const bool noAbort = flags & IndexerJob::NoAbort; - flags &= ~IndexerJob::NoAbort; - assert(flags == IndexerJob::Dirty || flags == IndexerJob::Reindex); - - std::weak_ptr weakConn = wait; - for (uint32_t fileId : toIndex) { - if (noAbort) { - assert(!wait); // this can't happen now, if it could we would have to call finish - if (mActiveJobs.contains(fileId)) - continue; - } - - if (mSuspendedFiles.contains(fileId)) { - warning() << "Not starting job for" << Location::path(fileId) << "because it is suspended"; - continue; - } - - auto job = std::make_shared(sources(fileId), flags, shared_from_this(), unsavedFiles); - if (wait) { - job->destroyed.connect([weakConn](IndexerJob *) { - // should arguably be refcounted but I don't know if anyone waits for multiple jobs - if (auto strong = weakConn.lock()) { - strong->finish(); - } - }); - } - index(job); - } - - return toIndex.size(); -} - -bool Project::isIndexed(uint32_t fileId) const -{ - return mDependencies.contains(fileId); -} - -const Set &Project::suspendedFiles() const -{ - return mSuspendedFiles; -} - -void Project::clearSuspendedFiles() -{ - mSuspendedFiles.clear(); -} - -bool Project::toggleSuspendFile(uint32_t file) -{ - if (!mSuspendedFiles.insert(file)) { - mSuspendedFiles.remove(file); - return false; - } - return true; -} - -void Project::setSuspended(uint32_t file, bool suspended) -{ - if (suspended) { - mSuspendedFiles.insert(file); - } else { - mSuspendedFiles.remove(file); - } -} - -bool Project::isSuspended(uint32_t file) const -{ - return mSuspendedFiles.contains(file); -} - -void Project::updateFixIts(const Set &visited, FixIts &fixIts) -{ - for (auto v : visited) { - const auto fit = fixIts.find(v); - if (fit == fixIts.end()) { - mFixIts.erase(v); - } else { - mFixIts[v] = fit->second; - } - } -} - -void Project::updateDiagnostics(uint32_t fileId, const Diagnostics &diagnostics) -{ - Set files; - { - auto it = mDiagnostics.begin(); - const auto end = mDiagnostics.end(); - uint32_t lastFileId = 0; - while (it != end) { - if (it->second.sourceFileId == fileId) { - const uint32_t f = it->first.fileId(); - if (f != lastFileId) { - files.insert(f); - lastFileId = f; - } - // if (debug) { - // error() << "erasing" << it->first << "for" << Location::path(fileId); - // } - mDiagnostics.erase(it++); - } else { - ++it; - } - } - } - - { - uint32_t lastFileId = 0; - for (const auto &it : diagnostics) { - // if (debug && it.second.flags & Diagnostic::TemplateOnly) - // error() << "checking for" << Location::path(fileId) << it.first; - if (it.second.flags & Diagnostic::TemplateOnly && !isTemplateDiagnostic(it)) { - // if (debug) - // error() << "continuing"; - continue; - } - if (it.second.flags & Diagnostic::Skipped) { - continue; - } - - const uint32_t f = it.first.fileId(); - if (lastFileId != f) { - files.insert(f); - lastFileId = f; - } - // if (debug) { - // error() << "inserting" << it.first << "for" << Location::path(fileId); - // } - - mDiagnostics[it.first] = it.second; - } - } - - if (!files.isEmpty() || !diagnostics.isEmpty()) { - log([&](const std::shared_ptr &output) { - if (output->testLog(RTags::DiagnosticsLevel)) { - QueryMessage::Flag format = QueryMessage::XML; - if (output->flags() & RTagsLogOutput::Elisp) { - // I know this is RTagsLogOutput because it returned - // true for testLog(RTags::DiagnosticsLevel) - format = QueryMessage::Elisp; - } else if (output->flags() & RTagsLogOutput::JSON) { - format = QueryMessage::JSON; - } - const String log = formatDiagnostics(mDiagnostics, format, Set(files)); - if (!log.isEmpty()) { - output->log(log); - } - } - }); - } -} - -String Project::fixIts(uint32_t fileId) const -{ - const auto it = mFixIts.find(fileId); - String out; - if (it != mFixIts.end()) { - const Set &fixIts = it->second; - if (!fixIts.isEmpty()) { - auto f = fixIts.end(); - do { - --f; - if (!out.isEmpty()) - out.append('\n'); - out.append(String::format<32>("%d:%d %d %s", f->line, f->column, f->length, f->text.constData())); - - } while (f != fixIts.begin()); - } - } - return out; -} - -void Project::findSymbols(const String &unencoded, - const std::function &)> &inserter, - Flags queryFlags, - uint32_t fileFilter) -{ - const String string = Sandbox::encoded(unencoded); - const bool wildcard = queryFlags & QueryMessage::WildcardSymbolNames && (string.contains('*') || string.contains('?')); - const bool caseInsensitive = queryFlags & QueryMessage::MatchCaseInsensitive; - std::regex rx; - const bool regex = queryFlags & QueryMessage::MatchRegex; - if (regex) - rx.assign(string.ref()); - const String::CaseSensitivity cs = caseInsensitive ? String::CaseInsensitive : String::CaseSensitive; - String lowerBound; - if (wildcard) { - if (!caseInsensitive) { - const size_t size = string.size(); - for (size_t i=0; icount(); - // error() << "Looking at" << count << Location::path(dep.first) - // << lowerBound << string; - uint32_t idx = 0; - if (!lowerBound.isEmpty()) { - idx = symNames->lowerBound(lowerBound); - if (idx == std::numeric_limits::max()) { - return; - } - } - - for (int i=idx; ikeyAt(i); - // error() << i << count << entry; - SymbolMatchType type = Exact; - if (!string.isEmpty()) { - if (wildcard) { - if (!Rct::wildCmp(string.constData(), entry.constData(), cs)) { - continue; - } - type = Wildcard; - } else if (regex) { - if (!std::regex_search(entry.ref(), rx)) { - continue; - } - type = Regexp; - } else if (!entry.startsWith(string, cs)) { - if (cs == String::CaseInsensitive) { - continue; - } else { - break; - } - } else if (entry.size() != string.size()) { - type = StartsWith; - } - } - inserter(type, entry, symNames->valueAt(i)); - } - }; - - if (fileFilter) { - processFile(fileFilter); - } else { - for (const auto &dep : mDependencies) { - processFile(dep.first); - } - } -} - -List Project::sort(const Set &symbols, Flags flags) -{ - List sorted; - sorted.reserve(symbols.size()); - for (const Symbol &symbol : symbols) { - RTags::SortedSymbol node(symbol.location); - if (!symbol.isNull()) { - node.isDefinition = symbol.isDefinition(); - if (flags & QueryMessage::DeclarationOnly && node.isDefinition) { - const Symbol decl = findTarget(symbol); - if (!decl.isNull() && !decl.isDefinition()) { - assert(decl.usr == symbol.usr); - continue; - } - } else if (flags & QueryMessage::DefinitionOnly && !node.isDefinition) { - continue; - } - node.kind = symbol.kind; - } - sorted.push_back(node); - } - - if (flags & QueryMessage::ReverseSort) { - std::sort(sorted.begin(), sorted.end(), std::greater()); - } else { - std::sort(sorted.begin(), sorted.end()); - } - return sorted; -} - -void Project::watch(const Path &dir, WatchMode mode) -{ - if (!dir.isEmpty()) { - const auto opts = Server::instance()->options().options; - if (opts & Server::WatchSourcesOnly && mode != Watch_SourceFile) - return; - const auto it = mWatchedPaths.find(dir); - if (it != mWatchedPaths.end()) { - it->second |= mode; - return; - } - if (opts & Server::WatchSystemPaths || !dir.isSystem()) { - auto &m = mWatchedPaths[dir]; - if (!m) - mWatcher.watch(dir); - m |= mode; - } - } -} - -void Project::watchFile(uint32_t fileId) -{ - const WatchMode mode = hasSource(fileId) ? Watch_SourceFile : Watch_Dependency; - watch(Location::path(fileId).parentDir(), mode); -} - -void Project::clearWatch(Flags mode) -{ - auto it = mWatchedPaths.begin(); - while (it != mWatchedPaths.end()) { - it->second &= ~mode; - if (!it->second) { - mWatcher.unwatch(it->first); - mWatchedPaths.erase(it++); - } else { - ++it; - } - } -} - -void Project::unwatch(const Path &dir, WatchMode mode) -{ - auto it = mWatchedPaths.find(dir); - if (it == mWatchedPaths.end()) { - it = mWatchedPaths.find(dir.resolved()); - if (it == mWatchedPaths.end()) { - const auto opts = Server::instance()->options().options; - if (!(opts & Server::WatchSourcesOnly) || mode != Watch_Dependency) - error() << "We're not watching this directory" << dir; - return; - } - } - if (!(it->second &= ~mode)) { - mWatcher.unwatch(it->first); - mWatchedPaths.erase(it); - } -} - -String Project::toCompileCommands() const -{ - const Flags flags = (Source::IncludeCompiler - | Source::IncludeSourceFile - | Source::IncludeDefines - | Source::IncludeIncludePaths - | Source::IncludeOutputFilename - | Source::QuoteDefines - | Source::FilterBlacklist); - Value ret; - forEachSource([&ret, flags](const Source &source) -> VisitResult { - Value unit; - unit["directory"] = source.directory; - unit["file"] = source.sourceFile(); - unit["command"] = String::join(source.toCommandLine(flags), " ").constData(); - ret.push_back(unit); - return Continue; - }); - - return ret.toJSON(true); -} - -Symbol Project::findSymbol(Location location, int *index) -{ - if (index) - *index = -1; - if (location.isNull()) - return Symbol(); - auto symbols = openSymbols(location.fileId()); - if (!symbols || !symbols->count()) - return Symbol(); - - bool exact = false; - uint32_t idx = symbols->lowerBound(location, &exact); - if (exact) { - if (index) - *index = idx; - return symbols->valueAt(idx); - } - switch (idx) { - case 0: - return Symbol(); - case std::numeric_limits::max(): - idx = symbols->count() - 1; - break; - default: - --idx; - break; - } - - const Symbol &ret = symbols->valueAt(idx); - if (ret.location.fileId() != location.fileId() - || ret.location.line() != location.line() - || (location.column() - ret.location.column() >= ret.symbolLength)) { - return Symbol(); - } - if (index) - *index = idx; - return ret; -} - -Set Project::findTargets(const Symbol &symbol) -{ - Set ret; - if (symbol.isNull() || symbol.flags & Symbol::ImplicitDestruction) - return ret; - auto sameKind = [&symbol](CXCursorKind kind) { - if (kind == symbol.kind) - return true; - if (symbol.isClass()) - return kind == CXCursor_ClassDecl || kind == CXCursor_StructDecl; - return false; - }; - - for (int i=0; i<2 && ret.isEmpty(); ++i) { - switch (symbol.kind) { - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: - case CXCursor_StructDecl: - if (symbol.isDefinition() && !(symbol.flags & Symbol::TemplateSpecialization)) - return ret; - RCT_FALL_THROUGH; - case CXCursor_FunctionDecl: - case CXCursor_CXXMethod: - case CXCursor_Destructor: - case CXCursor_Constructor: - case CXCursor_FieldDecl: - case CXCursor_VarDecl: - case CXCursor_FunctionTemplate: { - const Set symbols = findByUsr(symbol.usr, symbol.location.fileId(), i == 0 ? modeForSymbol(symbol) : Project::All); - for (const auto &c : symbols) { - if (sameKind(c.kind) && symbol.isDefinition() != c.isDefinition()) { - ret.insert(c); - } - } - - if (!ret.isEmpty() || (symbol.kind != CXCursor_VarDecl && symbol.kind != CXCursor_FieldDecl)) - break; } - // fall through - default: - if (symbol.flags & Symbol::TemplateReference) { - for (const String &usr : findTargetUsrs(symbol)) { - ret.unite(findByUsr(usr, symbol.location.fileId(), i == 0 ? Project::DependsOnArg : Project::All)); - } - } else { - for (const String &usr : findTargetUsrs(symbol)) { - ret.unite(findByUsr(usr, symbol.location.fileId(), i == 0 ? Project::ArgDependsOn : Project::All)); - } - } - break; - } - } - - return ret; -} - -Set Project::findByUsr(const String &usr, uint32_t fileId, DependencyMode mode) -{ - assert(fileId); - Set ret; - String tusr = Sandbox::encoded(usr); - for (uint32_t file : dependencies(fileId, mode)) { - auto usrs = openUsrs(file); - // error() << usrs << Location::path(file) << usr; - if (usrs) { - // SBROOT - for (Location loc : usrs->value(tusr)) { - // error() << "got a loc" << loc; - const Symbol c = findSymbol(loc); - if (!c.isNull()) - ret.insert(c); - } - // for (int i=0; icount(); ++i) { - // error() << i << usrs->count() << usrs->keyAt(i) << usrs->valueAt(i); - // } - } - } - - if (ret.isEmpty() && usr.startsWith("/")) { // for break statements and includes - Symbol sym; - sym.location = Location::fromPathLineAndColumn(usr); - ret.insert(sym); - return ret; - } - - return ret; -} - -static Set findReferences(const Set &inputs, - const std::shared_ptr &project, - std::function filter) -{ - Set ret; - // const bool isClazz = s.isClass(); - for (const Symbol &input : inputs) { - //warning() << "Calling findReferences" << input.location; - auto process = [&](uint32_t dep) { - // error() << "Looking at file" << Location::path(dep) << "for input" << input.location; - auto targets = project->openTargets(dep); - if (targets) { - // SBROOT - const String tusr = Sandbox::encoded(input.usr); - const Set locations = targets->value(tusr); - // error() << "Got locations for usr" << input.usr << locations; - for (const auto &loc : locations) { - auto sym = project->findSymbol(loc); - if (filter(input, sym)) - ret.insert(sym); - } - } - }; - const Set deps = project->dependencies(input.location.fileId(), Project::DependsOnArg); - for (auto dep : deps) - process(dep); - - if (ret.isEmpty()) { - for (auto dep : project->dependencies()) { - if (!deps.contains(dep.first)) - process(dep.first); - } - } - } - return ret; -} - -static Set findReferences(const Symbol &in, - const std::shared_ptr &project, - std::function filter, - Set *inputsPtr = 0) -{ - Set inputs; - Symbol s; - Location location; - if (in.isReference()) { - const Symbol target = project->findTarget(in); - if (!target.isNull()) { - if (target.kind != CXCursor_MacroExpansion) { - s = target; - } else { - s = in; - auto usrs = project->findTargetUsrs(s.location); - if (!usrs.isEmpty()) - s.usr = *usrs.begin(); - // error() << "GOT USRS" << usrs; - s.location = location = target.location; - } - } - } - if (s.isNull()) - s = in; - if (location.isNull()) - location = s.location; - - // error() << "findReferences" << s.location << in.location << s.kind; - switch (s.kind) { - case CXCursor_CXXMethod: - if (s.flags & Symbol::VirtualMethod) { - inputs = project->findVirtuals(s); - break; - } - // fall through - case CXCursor_FunctionTemplate: - case CXCursor_FunctionDecl: - case CXCursor_ClassTemplate: - case CXCursor_ClassDecl: - case CXCursor_StructDecl: - case CXCursor_UnionDecl: - case CXCursor_VarDecl: - case CXCursor_TypedefDecl: - case CXCursor_Namespace: - case CXCursor_Constructor: - case CXCursor_Destructor: - case CXCursor_ConversionFunction: - case CXCursor_NamespaceAlias: - inputs = project->findByUsr(s.usr, location.fileId(), modeForSymbol(s)); - break; - default: - inputs.insert(s); - break; - case CXCursor_FirstInvalid: - return Set(); - } - if (inputsPtr) - *inputsPtr = inputs; - return findReferences(inputs, project, std::move(filter)); -} - -Set Project::findCallers(const Symbol &symbol) -{ - const bool isClazz = symbol.isClass(); - return ::findReferences(symbol, shared_from_this(), [isClazz](const Symbol &input, const Symbol &ref) { - if (isClazz && (ref.isConstructorOrDestructor() || ref.kind == CXCursor_CallExpr)) - return false; - if (ref.isReference() - || (input.kind == CXCursor_Constructor && (ref.kind == CXCursor_VarDecl || ref.kind == CXCursor_FieldDecl))) { - return true; - } - if (input.kind == CXCursor_ClassTemplate && ref.flags & Symbol::TemplateSpecialization) { - return true; - } - return false; - }); -} - -Set Project::findAllReferences(const Symbol &symbol) -{ - if (symbol.isNull()) - return Set(); - - Set inputs; - inputs.insert(symbol); - inputs.unite(findByUsr(symbol.usr, symbol.location.fileId(), modeForSymbol(symbol))); - Set ret = inputs; - for (const auto &input : inputs) { - Set inputLocations; - ret.unite(::findReferences(input, shared_from_this(), [](const Symbol &, const Symbol &) { - return true; - }, &inputLocations)); - ret.unite(inputLocations); - } - return ret; -} - -Set Project::findVirtuals(const Symbol &symbol) -{ - if (symbol.kind != CXCursor_CXXMethod || !(symbol.flags & Symbol::VirtualMethod)) - return Set(); - - Symbol parent = [this](const Symbol &sym) { - for (const String &usr : findTargetUsrs(sym.location)) { - const Set syms = findByUsr(usr, sym.location.fileId(), ArgDependsOn); - for (const Symbol &s : syms) { - if (findTargetUsrs(s.location).isEmpty()) { - return s; - } - } - } - return sym; - }(symbol); - - assert(!parent.isNull()); - if (parent.isDefinition()) { - const auto target = findTarget(parent); - if (!target.isNull()) { - parent = target; - } - } - - Set symSet; - symSet.insert(parent); - Set ret = ::findReferences(symSet, shared_from_this(), [](const Symbol &, const Symbol &ref) { - // error() << "considering" << ref.location << ref.kindSpelling(); - if (ref.kind == CXCursor_CXXMethod) { - return true; - } - return false; - }); - ret.insert(parent); - const Symbol target = findTarget(parent); - if (!target.isNull()) - ret.insert(target); - return ret; -} - -Set Project::findTargetUsrs(Location loc) -{ - Set usrs; - auto targets = openTargets(loc.fileId()); - if (targets) { - const int count = targets->count(); - for (int i=0; ivalueAt(i).contains(loc)) { - // SBROOT - usrs.insert(Sandbox::decoded(targets->keyAt(i))); - } - } - } - return usrs; -} - -Set Project::findTargetUsrs(const Symbol &symbol) -{ - if (!(symbol.flags & Symbol::TemplateReference)) { - return findTargetUsrs(symbol.location); - } - - Set usrs; - for (uint32_t fileId : dependencies(symbol.location.fileId(), DependsOnArg)) { - auto targets = openTargets(fileId); - if (targets) { - const int count = targets->count(); - for (int i=0; ivalueAt(i).contains(symbol.location)) { - // SBROOT - usrs.insert(Sandbox::decoded(targets->keyAt(i))); - } - } - } - } - return usrs; -} - -Set Project::findSubclasses(const Symbol &symbol) -{ - assert(symbol.isClass() && symbol.isDefinition()); - Set ret; - for (uint32_t dep : dependencies(symbol.location.fileId(), DependsOnArg)) { - auto symbols = openSymbols(dep); - if (symbols) { - const int count = symbols->count(); - for (int i=0; ivalueAt(i); - if (s.baseClasses.contains(symbol.usr)) - ret.insert(s); - } - } - } - return ret; -} - -void Project::beginScope() -{ - assert(!mFileMapScope); - mFileMapScope.reset(new FileMapScope(shared_from_this(), Server::instance()->options().maxFileMapScopeCacheSize)); -} - -void Project::endScope() -{ - assert(mFileMapScope); - mFileMapScope.reset(); -} - -static String addDeps(const Dependencies &deps) -{ - if (deps.isEmpty()) - return "nil"; - String ret; - ret << "(list"; - for (const auto &dep : deps) { - ret << " \"" << Location::path(dep.first) << "\""; - } - ret << ")"; - return ret; -} - -String Project::dumpDependencies(uint32_t fileId, const List &args, Flags flags) const -{ - String ret; - - auto dumpRaw = [&ret, flags](DependencyNode *n) { - if (!(flags & QueryMessage::Elisp)) { - ret << Location::path(n->fileId) << "\n"; - for (const auto &inc : n->includes) { - ret << " " << Location::path(inc.second->fileId) << "\n"; - } - for (const auto &dep : n->dependents) { - ret << " " << Location::path(dep.second->fileId) << "\n"; - } - return; - } - - ret << " (cons \"" << Location::path(n->fileId) << "\" (cons " << addDeps(n->includes) << ' ' << addDeps(n->dependents) << "))\n"; - }; - - if (fileId) { - DependencyNode *node = mDependencies.value(fileId); - if (!node) - return String::format<128>("Can't find node for %s", Location::path(fileId).constData()); - - if (!node->includes.isEmpty() && (args.isEmpty() || args.contains("includes"))) { - if (args.size() != 1) - ret += String::format<1024>(" %s includes:\n", Location::path(fileId).constData()); - for (const auto &include : node->includes) { - ret += String::format<1024>(" %s\n", Location::path(include.first).constData()); - } - } - if (!node->dependents.isEmpty() && (args.isEmpty() || args.contains("included-by"))) { - if (args.size() != 1) - ret += String::format<1024>(" %s is included by:\n", Location::path(fileId).constData()); - for (const auto &include : node->dependents) { - ret += String::format<1024>(" %s\n", Location::path(include.first).constData()); - } - } - - if (args.isEmpty() || args.contains("depends-on")) { - bool first = args.size() != 1; - for (auto dep : dependencies(fileId, Project::ArgDependsOn)) { - if (dep == fileId) - continue; - if (first) { - first = false; - ret += String::format<1024>(" %s depends on:\n", Location::path(fileId).constData()); - } - ret += String::format<1024>(" %s\n", Location::path(dep).constData()); - } - } - - if (args.isEmpty() || args.contains("depended-on")) { - bool first = args.size() != 1; - for (auto dep : dependencies(fileId, Project::DependsOnArg)) { - if (dep == fileId) - continue; - if (first) { - first = false; - ret += String::format<1024>(" %s is depended on by:\n", Location::path(fileId).constData()); - } - ret += String::format<1024>(" %s\n", Location::path(dep).constData()); - } - } - - if (args.isEmpty() || args.contains("tree-depends-on")) { - Set seen; - - DependencyNode *depNode = mDependencies.value(fileId); - if (depNode) { - int startDepth = 1; - if (args.size() != 1) { - ++startDepth; - ret += String::format<1024>(" %s include tree:\n", Location::path(fileId).constData()); - } - - std::function process = [&](DependencyNode *n, int depth) { - ret += String::format<1024>("%s%s", String(depth * 2, ' ').constData(), Location::path(n->fileId).constData()); - - if (seen.insert(n) && !n->includes.isEmpty()) { - ret += " includes:\n"; - for (const auto &includeNode : n->includes) { - process(includeNode.second, depth + 1); - } - } else { - ret += '\n'; - } - }; - process(depNode, startDepth); - } - } - if (args.size() == 1 && args.contains("raw")) { - Set all; - std::function add = [&](DependencyNode *depNode) { - assert(depNode); - if (!all.insert(depNode)) - return; - for (const auto &n : depNode->includes) { - add(n.second); - } - }; - add(node); - ret << "(list\n"; - for (DependencyNode *n : all) { - dumpRaw(n); - } - ret.chop(1); - ret << ")\n"; - } - } else { - ret << "(list\n"; - for (const auto &node : mDependencies) { - dumpRaw(node.second); - } - ret.chop(1); - ret << ")\n"; - } - - return ret; -} - -void Project::dirty(uint32_t fileId) -{ - SimpleDirty dirty; - Set dirtyFiles; - dirtyFiles.insert(fileId); - dirty.init(shared_from_this(), dirtyFiles); - startDirtyJobs(&dirty, IndexerJob::Dirty); -} - -bool Project::validate(uint32_t fileId, ValidateMode mode, String *err) const -{ - if (mode == Validate) { - Path path; - String error; - const uint32_t opts = fileMapOptions(); - { - path = sourceFilePath(fileId, fileMapName(SymbolNames)); - FileMap > fileMap; - if (!fileMap.load(path, opts, &error)) - goto error; - } - { - path = sourceFilePath(fileId, fileMapName(Symbols)); - FileMap fileMap; - if (!fileMap.load(path, opts, &error)) - goto error; - } - { - path = sourceFilePath(fileId, fileMapName(Targets)); - FileMap > fileMap; - if (!fileMap.load(path, opts, &error)) - goto error; - } - { - path = sourceFilePath(fileId, fileMapName(Usrs)); - FileMap > fileMap; - if (!fileMap.load(path, opts, &error)) - goto error; - } - return true; - error: - if (err) - Log(err) << "Error during validation:" << Location::path(fileId) << error << path; - return false; - } else { - assert(mode == StatOnly); - for (auto type : { Symbols, SymbolNames, Targets, Usrs }) { - const Path p = sourceFilePath(fileId, fileMapName(type)); - if (!p.isFile()) { - Log(err) << "Error during validation:" << Location::path(fileId) << p << "doesn't exist"; - return false; - } - } - } - return true; -} - -template -static inline String toString(const T &t, size_t &max) -{ - String ret; - Log(&ret, LogOutput::NoTypename) << t; - max = std::max(max, ret.size()); - ret.replace('\n', ' '); - return ret; -} - -template <> -inline String toString(const String &str, size_t &max) -{ - max = std::max(max, str.size()); - String ret = str; - ret.replace('\n', ' '); - return ret; -} - -static inline void fixString(String &string, size_t size) -{ - if (string.size() != size) - string.append(String(size - string.size(), ' ')); -} - -static List split(const String &value, size_t max) -{ - List words = value.split(' ', String::KeepSeparators); - List ret(1); - size_t i = 0; - while (i < words.size()) { - const String &word = words.at(i); - if (ret.last().size() && ret.last().size() + word.size() > max) { - fixString(ret.last(), max); - ret.append(String()); - continue; - } - - if (word.size() > max) { - assert(ret.last().isEmpty()); - for (size_t j=0; j struct PreferComma { enum { value = 0 }; }; -template struct PreferComma > { enum { value = 1 }; }; - -template -static List formatField(const String &value, size_t max) -{ - List ret; - if (value.size() <= max) { - ret << value.padded(String::End, max); - } else { - if (PreferComma::value) - ret = value.split(',', String::KeepSeparators); - - if (ret.size() > 1) { - for (size_t i=0; i max) { - auto split = ::split(ret.at(i), max); - ret.remove(i, 1); - ret.insert(i, split); - i += split.size() - 1; - } else if (ret.at(i).size() != max) { - ret[i].append(String(max - ret.at(i).size(), ' ')); - } - } - } else { - ret = split(value, max); - } - } - return ret; -} -template -static String formatTable(const String &name, const std::shared_ptr > &fileMap, size_t width) -{ - width -= 7; // padding - List keys, values; - const int count = fileMap->count(); - size_t maxKey = 0; - size_t maxValue = 0; - for (int i=0; ikeyAt(i), maxKey); - values << toString(fileMap->valueAt(i), maxValue); - } - if (maxKey + maxValue > width) { - if (maxKey < maxValue) { - maxKey = std::min(maxKey, static_cast(width * .4)); - maxValue = std::min(maxValue, width - maxKey); - } else { - maxValue = std::min(maxValue, static_cast(width * .4)); - maxKey = std::min(maxKey, width - maxValue); - - } - } - - String ret; - ret.reserve((count + 3) * (maxKey + maxValue + 7)); - ret << name << '\n' << String(name.size(), '-') << '\n'; - const String keyFill(maxKey, ' '); - const String valueFill(maxValue, ' '); - for (int i=0; i key = formatField(keys.at(i), maxKey); - const List value = formatField(values.at(i), maxValue); - const int c = std::max(key.size(), value.size()); - char ch = '|'; - for (int j=0; j &msg, const std::shared_ptr &conn) -{ - FileMapScopeScope scope(this); - String err; - - Path path; - List args; - Deserializer deserializer(msg->query()); - deserializer >> path >> args; - const uint32_t fileId = Location::fileId(path); - assert(fileId); - assert(isIndexed(fileId)); - - if (args.empty() || args.contains("symbols")) { - if (auto tbl = openSymbols(fileId, &err)) { - conn->write(formatTable("Symbols:", tbl, msg->terminalWidth())); - } else { - conn->write(err); - } - } - - if (args.empty() || args.contains("symbolnames")) { - if (auto tbl = openSymbolNames(fileId, &err)) { - conn->write(formatTable("Symbol names:", tbl, msg->terminalWidth())); - } else { - conn->write(err); - } - } - - if (args.empty() || args.contains("targets")) { - if (auto tbl = openTargets(fileId, &err)) { - conn->write(formatTable("Targets:", tbl, msg->terminalWidth())); - } else { - conn->write(err); - } - } - - if (args.empty() || args.contains("usrs")) { - if (auto tbl = openUsrs(fileId, &err)) { - conn->write(formatTable("Usrs:", tbl, msg->terminalWidth())); - } else { - conn->write(err); - } - } - - if (args.empty() || args.contains("tokens")) { - if (auto tbl = openTokens(fileId, &err)) { - conn->write(formatTable("Tokens:", tbl, msg->terminalWidth())); - } else { - conn->write(err); - } - } -} - -void Project::prepare(uint32_t fileId) -{ - if (fileId && isIndexed(fileId)) { - FileMapScopeScope scope(this); - String err; - openSymbolNames(fileId, &err); - openSymbols(fileId, &err); - openTargets(fileId, &err); - openUsrs(fileId, &err); - debug() << "Prepared" << Location::path(fileId); - } -} - -template -size_t estimateMemory(const T &t); -size_t estimateMemory(const String &string); -size_t estimateMemory(const Source::Define &define); -size_t estimateMemory(const Source::Include &include); -size_t estimateMemory(const Source &source); -template -size_t estimateMemory(const std::shared_ptr &ptr); -template -size_t estimateMemory(const T *t); -template -size_t estimateMemory(const Set &container); -template -size_t estimateMemory(const List &container); -template -size_t estimateMemory(const Map &container); -template -size_t estimateMemory(const Hash &container); - -// impl -template -size_t estimateMemory(const T &t) -{ - return sizeof(t); -} - -size_t estimateMemory(const String &string) -{ - return string.size() + 1 + sizeof(string) + (sizeof(size_t) + sizeof(size_t)); -} - -size_t estimateMemory(const Source::Define &define) -{ - return estimateMemory(define.define) + estimateMemory(define.value); -} - -size_t estimateMemory(const Source::Include &include) -{ - return estimateMemory(include.type) + estimateMemory(include.path); -} - -size_t estimateMemory(const Source &source) -{ - size_t ret = sizeof(Source); - ret += estimateMemory(source.extraCompiler); - ret += estimateMemory(source.defines); - ret += estimateMemory(source.includePaths); - ret += estimateMemory(source.directory); - return ret; -} - -template -size_t estimateMemory(const std::shared_ptr &ptr) -{ - size_t ret = sizeof(ptr) + sizeof(size_t); - if (ptr) { - ret += estimateMemory(*ptr); - } else { - ret += sizeof(T); - } - return ret; -} - -template -size_t estimateMemory(const T *t) -{ - if (t) - return estimateMemory(*t); - return 0; -} - -template -size_t estimateMemory(const Set &container) -{ - size_t ret = sizeof(Set) + sizeof(void*); - for (const T &value : container) { - ret += estimateMemory(value) + (sizeof(void*) * 2); // might not be entirely fair to std::vector - } - return ret; -} - -template -size_t estimateMemory(const List &container) -{ - size_t ret = sizeof(List) + sizeof(void*); - for (const T &value : container) { - ret += estimateMemory(value); - } - return ret; -} - -template -size_t estimateKeyValueContainer(const T &t) -{ - size_t ret = sizeof(T) + sizeof(void*); - for (const auto &pair : t) { - ret += estimateMemory(pair.first) + estimateMemory(pair.second) + (sizeof(void*) * 2); - } - return ret; -} - -template -size_t estimateMemory(const Map &container) -{ - return estimateKeyValueContainer(container); -} - -template -size_t estimateMemory(const Hash &container) -{ - return estimateKeyValueContainer(container); -} - -String Project::estimateMemory() const -{ - List ret; - size_t total = 0; - auto add = [&ret, &total](const char *name, size_t size) { - total += size; - ret << String::format<128>("%s: %.2fmb", name, size / (1024.0 * 1024.0)); - }; - add("Paths", ::estimateMemory(mFiles)); - add("Visited files", ::estimateMemory(mVisitedFiles)); - add("Diagnostics", ::estimateMemory(mDiagnostics)); - add("Active jobs", ::estimateMemory(mActiveJobs)); - add("Fixits", ::estimateMemory(mFixIts)); - add("Pending dirty files", ::estimateMemory(mPendingDirtyFiles)); - add("Sources", ::estimateMemory(mIndexParseData.sources)); - add("Suspended files", ::estimateMemory(mSuspendedFiles)); - size_t deps = ::estimateMemory(mDependencies); - for (const auto &dep : mDependencies) { - deps += ::estimateMemory(*dep.second); - } - add("Dependencies", deps); - add("Total", total); - return String::join(ret, "\n"); -} - -void Project::reloadCompileCommands() -{ - mReloadCompileCommandsTimer.stop(); - if (!Server::instance()->suspended()) { - SourceCache cache; - Hash removed; - IndexParseData data; - data.project = mPath; - data.environment = mIndexParseData.environment; - bool found = false; - auto it = mIndexParseData.compileCommands.begin(); - while (it != mIndexParseData.compileCommands.end()) { - const Path file = Location::path(it->first); - const uint64_t lastModified = file.lastModifiedMs(); - if (!lastModified) { - for (auto src : it->second.sources) { - removed[src.first] = it->first; - } - mIndexParseData.compileCommands.erase(it++); - continue; - } - - if (lastModified != it->second.lastModifiedMs - && Server::instance()->loadCompileCommands(data, file, it->second.environment, &cache)) { - found = true; - } - ++it; - } - removeSources(removed); - if (found) - processParseData(std::move(data)); - } -} - -uint32_t Project::fileMapOptions() const -{ - uint32_t options = FileMap::None; - if (Server::instance()->options().options & Server::NoFileLock) - options |= FileMap::NoLock; - return options; -} - -void Project::fixPCH(Source &source) -{ - for (Source::Include &inc : source.includePaths) { - if (inc.type == Source::Include::Type_PCH) { - const uint32_t fileId = Location::insertFile(inc.path); - inc.path = RTags::encodeSourceFilePath(Server::instance()->options().dataDir, mPath, fileId) + "pch.h"; - error() << "PREPARING" << inc.path; - } - } -} - -void Project::includeCompletions(Flags flags, const std::shared_ptr &conn, Source &&source) const -{ - CompilerManager::applyToSource(source, CompilerManager::IncludeIncludePaths); - source.includePaths.append(Server::instance()->options().includePaths); - source.includePaths.sort(); - Set seen; - if (flags & QueryMessage::Elisp) { - conn->write("(list"); - } - for (const Source::Include &inc : source.includePaths) { - Path root; - switch (inc.type) { - case Source::Include::Type_Framework: - case Source::Include::Type_SystemFramework: - root = inc.path.ensureTrailingSlash() + "Headers/"; - break; - default: - root = inc.path.ensureTrailingSlash(); - break; - } - if (!seen.insert(root)) - continue; - int depth = 0; - int maxDepth = Server::instance()->options().maxIncludeCompletionDepth; - if (!maxDepth) - maxDepth = INT_MAX; - std::function visitor = [&depth, flags, &conn, &visitor, &root, maxDepth](const Path &path) { - if (path.isHeader()) { - const String p = path.mid(root.size()); - if (flags & QueryMessage::Elisp) { - conn->write<1024>(" \"%s\"", p.constData()); - } else { - conn->write(p); - } - } else if (depth < maxDepth && path.isDir()) { - ++depth; - path.visit(visitor); - --depth; - } - - return Path::Continue; - }; - root.visit(visitor); - } - if (flags & QueryMessage::Elisp) - conn->write(")"); -} - -Source Project::source(uint32_t fileId, int buildIndex) const -{ - Source ret; - forEachSources([fileId, &buildIndex, &ret](const Sources &sources) { - auto it = sources.find(fileId); - if (it != sources.end()) { - for (const auto &src : it->second) { - if (!buildIndex--) { - ret = src; - return Stop; - } - } - } - return Continue; - }); - return ret; -} - -void Project::reindex(uint32_t fileId, Flags flags) -{ - index(std::make_shared(sources(fileId), flags, shared_from_this())); -} - -void Project::processParseData(IndexParseData &&data) -{ - Set index; - Hash removed; - if (mIndexParseData.isEmpty()) { - mIndexParseData = std::move(data); - forEachSources([&index](const Sources &sources) -> VisitResult { - for (auto pair : sources) { - index.insert(pair.first); - } - return Continue; - }); - } else { - forEachSource(data.sources, [this, &index](const Source &source) -> VisitResult { - // only allowing one "loose" build per fileId - auto &ref = mIndexParseData.sources[source.fileId]; - if (Server::instance()->options().options & Server::AllowMultipleSources) { - if (!ref.contains(source)) { - ref.append(source); - ref.parsed = 0; // dirty - if (!(Server::instance()->options().options & Server::NoFileSystemWatch)) - index.insert(source.fileId); - } - } else { - if (ref.isEmpty()) { - index.insert(source.fileId); - ref.push_back(source); - } else if (ref[0] != source) { - if (!ref[0].compareArguments(source)) { - if (!(Server::instance()->options().options & Server::NoFileSystemWatch)) - index.insert(source.fileId); - ref.parsed = 0; // dirty - } - ref[0] = source; - } - } - return Continue; - }); - - for (auto &cc : data.compileCommands) { - Sources oldSources; - auto oldIt = mIndexParseData.compileCommands.find(cc.first); - if (oldIt != mIndexParseData.compileCommands.end()) { - oldSources = std::move(oldIt->second.sources); - } - - mIndexParseData.compileCommands[cc.first] = std::move(cc.second); - forEachSourceList(mIndexParseData.compileCommands[cc.first].sources, [&oldSources, &index](SourceList &list) { - const uint32_t fileId = list.fileId(); - auto oit = oldSources.find(fileId); - if (oit != oldSources.end()) { - bool same; - const auto &oitSources = oit->second; - if (list.size() == oitSources.size()) { - same = true; - for (size_t idx=0; idxsecond.parsed; // don't want to reparse these, maintain parseTime - } else if (!(Server::instance()->options().options & Server::NoFileSystemWatch)) { - index.insert(fileId); - } - oldSources.erase(oit); - } else { - index.insert(fileId); - } - return Continue; - }); - - for (auto it : oldSources) { - removed[it.first] = cc.first; - } - } - } - removeSources(removed); - - for (const auto &info : mIndexParseData.compileCommands) - watch(Location::path(info.first), Watch_CompileCommands); - - for (uint32_t fileId : index) { - reindex(fileId, IndexerJob::Compile); - } -} - -void Project::forEachSourceList(const IndexParseData &data, std::function cb) -{ - bool done = false; - forEachSources(data, [&done, &cb](const Sources &sources) { - forEachSourceList(sources, [&done, &cb](const SourceList &list) { - auto ret = cb(list); - assert(ret != Remove); - if (ret == Stop) - done = true; - return ret; - }); - return done ? Stop : Continue; - }); -} - -void Project::forEachSourceList(IndexParseData &data, std::function cb) -{ - bool done = false; - forEachSources(data, [&done, &cb](Sources &sources) { - forEachSourceList(sources, [&done, &cb](SourceList &list) { - auto ret = cb(list); - if (ret == Stop) - done = true; - return ret; - }); - return done ? Stop : Continue; - }); -} - -void Project::forEachSourceList(Sources &sources, const std::function& cb) -{ - auto it = sources.begin(); - while (it != sources.end()) { - const auto ret = cb(it->second); - if (ret == Remove) { - sources.erase(it++); - } else if (ret == Stop) { - break; - } else { - ++it; - } - } -} - -void Project::forEachSourceList(const Sources &sources, const std::function& cb) -{ - auto it = sources.begin(); - while (it != sources.end()) { - const auto ret = cb(it->second); - assert(ret != Remove); - if (ret == Stop) { - break; - } else { - ++it; - } - } -} - -void Project::forEachSource(const Sources &sources, const std::function& cb) -{ - for (auto &src : sources) { - for (const Source &s : src.second) { - auto ret = cb(s); - assert(ret != Remove); - if (ret == Stop) - return; - } - } -} - -void Project::forEachSource(Sources &sources, const std::function& cb) -{ - Sources::iterator sit = sources.begin(); - while (sit != sources.end()) { - SourceList &list = sit->second; - SourceList::iterator it = list.begin(); - bool done = false; - while (it != list.end()) { - const auto ret = cb(*it); - if (ret == Remove) { - it = list.erase(it); - } else if (ret == Stop) { - done = true; - break; - } else { - ++it; - } - } - if (list.isEmpty()) { - sources.erase(sit++); - } else { - ++sit; - } - if (done) - break; - } -} - -void Project::forEachSources(const IndexParseData &data, const std::function& cb) -{ - for (const auto &compileCommands : data.compileCommands) { - const auto ret = cb(compileCommands.second.sources); - assert(ret != Remove); - if (ret == Stop) - return; - } - const auto ret = cb(data.sources); - (void)ret; - assert(ret != Remove); -} - -void Project::forEachSources(IndexParseData &data, const std::function& cb) -{ - auto it = data.compileCommands.begin(); - while (it != data.compileCommands.end()) { - const auto ret = cb(it->second.sources); - if (ret == Remove) { - data.compileCommands.erase(it++); - } else if (ret == Stop) { - return; - } else { - ++it; - } - } - if (cb(data.sources) == Remove) - data.sources.clear(); -} - -void Project::forEachSource(const IndexParseData &data, std::function cb) -{ - bool stop = false; - forEachSources(data, [&stop, &cb](const Sources &sources) { - forEachSource(sources, [&stop, &cb](const Source &src) { - const auto ret = cb(src); - assert(ret != Remove); - if (ret == Stop) - stop = true; - return ret; - }); - return stop ? Stop : Continue; - }); -} - -void Project::forEachSource(IndexParseData &data, std::function cb) -{ - bool stop = false; - forEachSources(data, [&stop, &cb](Sources &sources) { - forEachSource(sources, [&stop, &cb](Source &src) { - const auto ret = cb(src); - if (ret == Stop) - stop = true; - return ret; - }); - return stop ? Stop : Continue; - }); -} - -void Project::removeSources(const Hash &removed) -{ - for (auto it : removed) { - if (!hasSource(it.first)) { - if (it.second) - error() << Location::path(it.first) << "is no longer in" << Location::path(it.second) << "removing"; - removeSource(it.first); - } - } -} - -void Project::removeSource(uint32_t fileId) -{ - std::shared_ptr job = mActiveJobs.take(fileId); - if (job) { - releaseFileIds(job->visited); - Server::instance()->jobScheduler()->abort(job); - } - Set file; - file.insert(fileId); - dirty(fileId); - releaseFileIds(file); - removeDependencies(fileId); - Path::rmdir(sourceFilePath(fileId)); -} - -void Project::validateAll() -{ - SimpleDirty dirty; - dirty.init(shared_from_this()); - bool clean = true; - for (auto dep : mDependencies) { - String err; - if (!validate(dep.first, Validate, &err)) { - clean = false; - dirty.insert(dep.first); - error() << err; - } - } - if (!clean) - startDirtyJobs(&dirty, IndexerJob::Dirty); -} - -bool Project::isTemplateDiagnostic(const std::pair &diagnostic) -{ - const uint32_t fileId = diagnostic.first.fileId(); - auto symbols = openSymbols(fileId); - if (!symbols || !symbols->count()) { - return true; - } - - bool exact = false; - uint32_t idx = symbols->lowerBound(diagnostic.first, &exact); - if (idx == std::numeric_limits::max()) { - return true; - } - while (true) { - Symbol sym = symbols->valueAt(idx); - if (RTags::isFunction(sym.kind)) { - if (!(sym.flags & Symbol::TemplateFunction)) { - // error() << "no template here" << diagnostic.first << sym.location << sym.flags; - return false; - } - return true; - } - if (idx > 0) { - --idx; - } else { - return true; - } - } - return false; -} diff --git a/rtags/src/Project.h b/rtags/src/Project.h deleted file mode 100644 index b919b05..0000000 --- a/rtags/src/Project.h +++ /dev/null @@ -1,502 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef Project_h -#define Project_h - -#include -#include - -#include "Diagnostic.h" -#include "FileMap.h" -#include "IndexerJob.h" -#include "IndexMessage.h" -#include "QueryMessage.h" -#include "IndexParseData.h" -#include "rct/EmbeddedLinkedList.h" -#include "rct/FileSystemWatcher.h" -#include "rct/Flags.h" -#include "rct/Path.h" -#include "rct/StopWatch.h" -#include "rct/Timer.h" -#include "rct/Serializer.h" -#include "RTags.h" -#include "Token.h" - -class Connection; -class Dirty; -class FileManager; -class IndexDataMessage; -class Match; -class RestoreThread; -struct DependencyNode -{ - enum Flag { - Flag_None = 0x0, - Flag_IncludeError = 0x1 - }; - DependencyNode(uint32_t f, Flags l = NullFlags) - : fileId(f), flags(l) - {} - void include(DependencyNode *dependee) - { - assert(!includes.contains(dependee->fileId) || includes.value(dependee->fileId) == dependee); - includes[dependee->fileId] = dependee; - assert(!dependee->dependents.contains(fileId) || dependee->dependents.value(fileId) == this); - dependee->dependents[fileId] = this; - } - - Dependencies dependents, includes; - uint32_t fileId; - - Flags flags; -}; - -RCT_FLAGS(DependencyNode::Flag); - -class Project : public std::enable_shared_from_this -{ -public: - Project(const Path &path); - ~Project(); - bool init(); - - std::shared_ptr fileManager() const { return mFileManager; } - - Path path() const { return mPath; } - Path projectDataDir() const { return mProjectDataDir; } - bool match(const Match &match, bool *indexed = 0) const; - - enum FileMapType { - Symbols, - SymbolNames, - Targets, - Usrs, - Tokens - }; - static const char *fileMapName(FileMapType type) - { - switch (type) { - case Symbols: return "symbols"; - case SymbolNames: return "symnames"; - case Targets: return "targets"; - case Usrs: return "usrs"; - case Tokens: return "tokens"; - } - return 0; - } - std::shared_ptr > > openSymbolNames(uint32_t fileId, String *err = 0) - { - assert(mFileMapScope); - return mFileMapScope->openFileMap >(SymbolNames, fileId, mFileMapScope->symbolNames, err); - } - std::shared_ptr > openSymbols(uint32_t fileId, String *err = 0) - { - assert(mFileMapScope); - return mFileMapScope->openFileMap(Symbols, fileId, mFileMapScope->symbols, err); - } - std::shared_ptr > > openTargets(uint32_t fileId, String *err = 0) - { - assert(mFileMapScope); - return mFileMapScope->openFileMap >(Targets, fileId, mFileMapScope->targets, err); - } - std::shared_ptr > > openUsrs(uint32_t fileId, String *err = 0) - { - assert(mFileMapScope); - return mFileMapScope->openFileMap >(Usrs, fileId, mFileMapScope->usrs, err); - } - - std::shared_ptr > openTokens(uint32_t fileId, String *err = 0) - { - assert(mFileMapScope); - return mFileMapScope->openFileMap(Tokens, fileId, mFileMapScope->tokens, err); - } - - - enum DependencyMode { - DependsOnArg, - ArgDependsOn, - All - }; - - Set dependencies(uint32_t fileId, DependencyMode mode) const; - bool dependsOn(uint32_t source, uint32_t header) const; - String dumpDependencies(uint32_t fileId, - const List &args = List(), - Flags flags = Flags()) const; - const Hash &dependencies() const { return mDependencies; } - DependencyNode *dependencyNode(uint32_t fileId) const { return mDependencies.value(fileId); } - - static bool readSources(const Path &path, IndexParseData &data, String *error); - enum SymbolMatchType { - Exact, - Wildcard, - Regexp, - StartsWith - }; - void findSymbols(const String &symbolName, - const std::function &)> &func, - Flags queryFlags, - uint32_t fileFilter = 0); - - static bool matchSymbolName(const String &pattern, const String &symbolName, String::CaseSensitivity cs) - { - return Rct::wildCmp(pattern.constData(), symbolName.constData(), cs); - } - - Symbol findSymbol(Location location, int *index = 0); - Set findTargets(Location location) { return findTargets(findSymbol(location)); } - Set findTargets(const Symbol &symbol); - Symbol findTarget(Location location) { return RTags::bestTarget(findTargets(location)); } - Symbol findTarget(const Symbol &symbol) { return RTags::bestTarget(findTargets(symbol)); } - Set findAllReferences(Location location) { return findAllReferences(findSymbol(location)); } - Set findAllReferences(const Symbol &symbol); - Set findCallers(Location location) { return findCallers(findSymbol(location)); } - Set findCallers(const Symbol &symbol); - Set findVirtuals(Location location) { return findVirtuals(findSymbol(location)); } - Set findVirtuals(const Symbol &symbol); - Set findTargetUsrs(const Symbol &symbol); - Set findTargetUsrs(Location loc); - Set findSubclasses(const Symbol &symbol); - - Set findByUsr(const String &usr, uint32_t fileId, DependencyMode mode); - - Path sourceFilePath(uint32_t fileId, const char *path = "") const; - - List sort(const Set &symbols, - Flags flags = Flags()); - - const Files &files() const { return mFiles; } - Files &files() { return mFiles; } - - const Set &suspendedFiles() const; - bool toggleSuspendFile(uint32_t file); - void setSuspended(uint32_t file, bool suspended); - bool isSuspended(uint32_t file) const; - void clearSuspendedFiles(); - - bool isIndexed(uint32_t fileId) const; - - void processParseData(IndexParseData &&data); - const IndexParseData &indexParseData() const { return mIndexParseData; } - void index(const std::shared_ptr &job); - void reindex(uint32_t fileId, Flags flags); - SourceList sources(uint32_t fileId) const; - Source source(uint32_t fileId, int buildIndex) const; - bool hasSource(uint32_t fileId) const; - bool isActiveJob(uint32_t sourceFileId) { return !sourceFileId || mActiveJobs.contains(sourceFileId); } - inline bool visitFile(uint32_t fileId, const Path &path, uint32_t sourceFileId); - inline void releaseFileIds(const Set &fileIds); - String fixIts(uint32_t fileId) const; - int reindex(const Match &match, - const std::shared_ptr &query, - const std::shared_ptr &wait); - int remove(const Match &match); - void onJobFinished(const std::shared_ptr &job, const std::shared_ptr &msg); - String toCompileCommands() const; - enum WatchMode { - Watch_FileManager = 0x1, - Watch_SourceFile = 0x2, - Watch_Dependency = 0x4, - Watch_CompileCommands = 0x8 - }; - - void watch(const Path &dir, WatchMode mode); - void unwatch(const Path &dir, WatchMode mode); - void clearWatch(Flags mode); - Hash > watchedPaths() const { return mWatchedPaths; } - - time_t lastIdleTime() const { return mLastIdleTime; } - bool isIndexing() const { return !mActiveJobs.isEmpty(); } - void onFileAdded(const Path &path); - void onFileModified(const Path &path); - void onFileRemoved(const Path &path); - void dumpFileMaps(const std::shared_ptr &msg, const std::shared_ptr &conn); - void removeSources(const Hash &sources); // key fileid, value fileid for compile_commands.json - void removeSource(uint32_t fileId); - Hash visitedFiles() const - { - std::lock_guard lock(mMutex); - return mVisitedFiles; - } - void encodeVisitedFiles(Serializer &serializer) - { - std::lock_guard lock(mMutex); - serializer << mVisitedFiles; - } - - class FileMapScopeScope - { - public: - FileMapScopeScope(Project *p) - : mProject(p) - { - if (mProject) - mProject->beginScope(); - } - FileMapScopeScope(const std::shared_ptr &p) - : FileMapScopeScope(p.get()) - {} - - ~FileMapScopeScope() - { - if (mProject) - mProject->endScope(); - } - private: - Project *mProject; - }; - - void beginScope(); - void endScope(); - void dirty(uint32_t fileId); - bool save(); - void prepare(uint32_t fileId); - String estimateMemory() const; - String diagnosticsToString(Flags flags, uint32_t fileId); - void diagnose(uint32_t fileId); - void diagnoseAll(); - uint32_t fileMapOptions() const; - void fixPCH(Source &source); - void includeCompletions(Flags flags, const std::shared_ptr &conn, Source &&source) const; - size_t bytesWritten() const { return mBytesWritten; } - void destroy() { mSaveDirty = false; } - enum VisitResult { - Stop, - Continue, - Remove // not allowed for const calls - }; - static void forEachSources(const IndexParseData &data, const std::function& cb); - static void forEachSources(IndexParseData &data, const std::function& cb); - void forEachSources(std::function cb) const { forEachSources(mIndexParseData, cb); } - void forEachSources(std::function cb) { forEachSources(mIndexParseData, cb); } - - static void forEachSourceList(const IndexParseData &data, std::function cb); - static void forEachSourceList(IndexParseData &data, std::function cb); - static void forEachSourceList(Sources &sources, const std::function& cb); - static void forEachSourceList(const Sources &sources, const std::function& cb); - void forEachSourceList(std::function cb) const { forEachSourceList(mIndexParseData, cb); } - void forEachSourceList(std::function cb) { forEachSourceList(mIndexParseData, cb); } - - static void forEachSource(Sources &sources, const std::function& cb); - static void forEachSource(const Sources &sources, const std::function& cb); - static void forEachSource(IndexParseData &data, std::function cb); - static void forEachSource(const IndexParseData &data, std::function cb); - void forEachSource(std::function cb) const { forEachSource(mIndexParseData, cb); } - void forEachSource(std::function cb) { forEachSource(mIndexParseData, cb); } - void validateAll(); - void updateDiagnostics(uint32_t fileId, const Diagnostics &diagnostics); -private: - void reloadCompileCommands(); - void onFileAddedOrModified(const Path &path); - void watchFile(uint32_t fileId); - enum ValidateMode { - StatOnly, - Validate - }; - bool validate(uint32_t fileId, ValidateMode mode, String *error = 0) const; - void removeDependencies(uint32_t fileId); - void updateDependencies(uint32_t fileId, const std::shared_ptr &msg); - void loadFailed(uint32_t fileId); - void updateFixIts(const Set &visited, FixIts &fixIts); - int startDirtyJobs(Dirty *dirty, - Flags type, - const UnsavedFiles &unsavedFiles = UnsavedFiles(), - const std::shared_ptr &wait = std::shared_ptr()); - void onDirtyTimeout(Timer *); - bool isTemplateDiagnostic(const std::pair &diagnostic); - - struct FileMapScope { - FileMapScope(const std::shared_ptr &proj, int m) - : project(proj), openedFiles(0), totalOpened(0), max(m), loadFailed(false) - {} - ~FileMapScope() - { - warning() << "Query opened" << totalOpened << "files for project" << project->path(); - if (loadFailed) - project->validateAll(); - } - - struct LRUKey { - FileMapType type; - uint32_t fileId; - bool operator<(const LRUKey &other) const - { - return fileId < other.fileId || (fileId == other.fileId && type < other.type); - } - }; - struct LRUEntry { - LRUEntry(FileMapType t, uint32_t f) - : key({ t, f }) - {} - const LRUKey key; - - std::shared_ptr next, prev; - }; - - void poke(FileMapType t, uint32_t f) - { - const LRUKey key = { t, f }; - auto ptr = entryMap.value(key); - assert(ptr); - entryList.remove(ptr); - entryList.append(ptr); - } - - template - std::shared_ptr > openFileMap(FileMapType type, uint32_t fileId, - Hash > > &cache, - String *errPtr) - { - auto it = cache.find(fileId); - if (it != cache.end()) { - poke(type, fileId); - return it->second; - } - const Path path = project->sourceFilePath(fileId, Project::fileMapName(type)); - auto fileMap = std::make_shared>(); - String err; - if (fileMap->load(path, project->fileMapOptions(), &err)) { - ++totalOpened; - cache[fileId] = fileMap; - auto entry = std::make_shared(type, fileId); - entryList.append(entry); - entryMap[entry->key] = entry; - if (++openedFiles > max) { - const std::shared_ptr e = entryList.takeFirst(); - assert(e); - entryMap.remove(e->key); - switch (e->key.type) { - case SymbolNames: - assert(symbolNames.contains(e->key.fileId)); - symbolNames.remove(e->key.fileId); - break; - case Symbols: - assert(symbols.contains(e->key.fileId)); - symbols.remove(e->key.fileId); - break; - case Targets: - assert(targets.contains(e->key.fileId)); - targets.remove(e->key.fileId); - break; - case Usrs: - assert(usrs.contains(e->key.fileId)); - usrs.remove(e->key.fileId); - break; - case Tokens: - assert(tokens.contains(e->key.fileId)); - tokens.remove(e->key.fileId); - break; - } - --openedFiles; - } - assert(openedFiles <= max); - } else { - if (errPtr) { - *errPtr = "Failed to open: " + path + " " + Location::path(fileId) + ": " + err; - } else { - error() << "Failed to open" << path << Location::path(fileId) << err; - } - loadFailed = true; - fileMap.reset(); - } - return fileMap; - } - - Hash > > > symbolNames; - Hash > > symbols; - Hash > > > targets, usrs; - Hash > > tokens; - std::shared_ptr project; - int openedFiles, totalOpened; - const int max; - bool loadFailed; - - EmbeddedLinkedList > entryList; - Map > entryMap; - }; - - std::shared_ptr mFileMapScope; - - const Path mPath, mProjectDataDir; - Path mProjectFilePath, mSourcesFilePath; - - Files mFiles; - - Hash mVisitedFiles; - int mJobCounter, mJobsStarted; - - time_t mLastIdleTime; - - Diagnostics mDiagnostics; - - Hash > mActiveJobs; - - Timer mDirtyTimer, mReloadCompileCommandsTimer; - Set mPendingDirtyFiles; - - StopWatch mTimer; - FileSystemWatcher mWatcher; - IndexParseData mIndexParseData; - Hash > mWatchedPaths; - std::shared_ptr mFileManager; - FixIts mFixIts; - - Hash mDependencies; - Set mSuspendedFiles; - - size_t mBytesWritten; - bool mSaveDirty; - - mutable std::mutex mMutex; -}; - -RCT_FLAGS(Project::WatchMode); - -inline bool Project::visitFile(uint32_t visitFileId, const Path &path, uint32_t id) -{ - assert(id); - std::lock_guard lock(mMutex); - assert(visitFileId); - Path &p = mVisitedFiles[visitFileId]; - assert(id); - assert(mActiveJobs.contains(id)); - std::shared_ptr &job = mActiveJobs[id]; - assert(job); - if (p.isEmpty()) { - p = path; - job->visited.insert(visitFileId); - return true; - } - return job->visited.contains(visitFileId); -} - -inline void Project::releaseFileIds(const Set &fileIds) -{ - if (!fileIds.isEmpty()) { - std::lock_guard lock(mMutex); - for (const auto &f : fileIds) { - // error() << "Returning files" << Location::path(f); - mVisitedFiles.remove(f); - } - } -} - -inline Path Project::sourceFilePath(uint32_t fileId, const char *type) const -{ - return String::format<1024>("%s%d/%s", mProjectDataDir.constData(), fileId, type); -} - -#endif diff --git a/rtags/src/QueryJob.cpp b/rtags/src/QueryJob.cpp deleted file mode 100644 index e5f75b2..0000000 --- a/rtags/src/QueryJob.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "QueryJob.h" - -#include - -#include "Project.h" -#include "QueryMessage.h" -#include "rct/Connection.h" -#include "rct/EventLoop.h" -#include "RTags.h" -#include "Server.h" - -QueryJob::QueryJob(const std::shared_ptr &query, - const std::shared_ptr &proj, - Flags jobFlags) - : Project::FileMapScopeScope(proj), mAborted(false), mLinesWritten(0), mQueryMessage(query), mJobFlags(jobFlags), mProject(proj), mFileFilter(0) -{ - assert(query); - if (query->flags() & QueryMessage::SilentQuery) - setJobFlag(QuietJob); - const List &pathFilters = query->pathFilters(); - if (!pathFilters.isEmpty()) { - if (pathFilters.size() == 1 && pathFilters.first().mode == QueryMessage::PathFilter::Self) { - mFileFilter = Location::fileId(pathFilters.first().pattern); - } - if (!mFileFilter) { - for (const QueryMessage::PathFilter &filter : pathFilters) { - if (filter.mode == QueryMessage::PathFilter::Dependency) { - uint32_t f = Location::fileId(filter.pattern); - if (f && mProject) - mFilters.append(std::make_shared(f, mProject)); - } else if (query->flags() & QueryMessage::MatchRegex) { - mFilters.append(std::make_shared(filter.pattern)); - } else { - mFilters.append(std::make_shared(filter.pattern)); - } - } - } - } - mKindFilters = query->kindFilters(); -} - -QueryJob::~QueryJob() -{ -} - -bool QueryJob::write(const String &out, Flags flags) -{ - if ((mJobFlags & WriteUnfiltered) || (flags & Unfiltered) || filter(out)) { - if ((mJobFlags & QuoteOutput) && !(flags & DontQuote)) { - String o((out.size() * 2) + 2, '"'); - char *ch = o.data() + 1; - int l = 2; - for (size_t i=0; i flags) -{ - assert(mConnection); - if (!(flags & IgnoreMax) && mQueryMessage) { - const int max = mQueryMessage->max(); - if (max != -1 && mLinesWritten == max) { - return false; - } - assert(mLinesWritten < max || max == -1); - ++mLinesWritten; - } - - if (!(mJobFlags & QuietJob)) - warning("=> %s", out.constData()); - - if (mConnection) { - if (!mConnection->write(out)) { - abort(); - return false; - } - return true; - } - - return true; -} - -bool QueryJob::locationToString(Location location, - const std::function &cb, - Flags writeFlags) -{ - if (location.isNull()) - return false; - Flags kf = locationToStringFlags(); - kf &= ~Location::ShowContext; - cb(Piece_Location, location.toString(kf, &mContextCache)); - if (!(writeFlags & NoContext) && !(queryFlags() & QueryMessage::NoContext)) - cb(Piece_Context, location.context(kf, &mContextCache)); - - const bool containingFunction = queryFlags() & QueryMessage::ContainingFunction; - const bool containingFunctionLocation = queryFlags() & QueryMessage::ContainingFunctionLocation; - const bool cursorKind = queryFlags() & QueryMessage::CursorKind; - const bool displayName = queryFlags() & QueryMessage::DisplayName; - if (containingFunction || containingFunctionLocation || cursorKind || displayName || !mKindFilters.isEmpty()) { - int idx; - Symbol symbol = project()->findSymbol(location, &idx); - if (symbol.isNull()) { - error() << "Somehow can't find" << location << "in symbols"; - } else { - if (!mKindFilters.filter(symbol)) - return false; - if (displayName) - cb(Piece_SymbolName, symbol.displayName()); - if (cursorKind) - cb(Piece_Kind, symbol.kindSpelling()); - if (containingFunction || containingFunctionLocation) { - const uint32_t fileId = location.fileId(); - const unsigned int line = location.line(); - const unsigned int column = location.column(); - auto fileMap = project()->openSymbols(location.fileId()); - if (fileMap) { - while (idx > 0) { - symbol = fileMap->valueAt(--idx); - if (symbol.location.fileId() != fileId) - break; - if (symbol.isDefinition() - && RTags::isContainer(symbol.kind) - && comparePosition(line, column, symbol.startLine, symbol.startColumn) >= 0 - && comparePosition(line, column, symbol.endLine, symbol.endColumn) <= 0) { - if (containingFunction) - cb(Piece_ContainingFunctionName, symbol.symbolName); - if (containingFunctionLocation) - cb(Piece_ContainingFunctionLocation, symbol.location.toString(locationToStringFlags() & ~Location::ShowContext)); - break; - } - } - } - } - } - } - return true; -} - -bool QueryJob::write(Location location, Flags flags) -{ - if (location.isNull()) - return false; - if (!(flags & Unfiltered)) { - if (!filterLocation(location)) - return false; - flags |= Unfiltered; - } - - String out; - if (!locationToString(location, [&out](LocationPiece piece, const String &string) { - switch (piece) { - case Piece_Location: - break; - case Piece_SymbolName: - case Piece_Kind: - case Piece_Context: - out << '\t'; - break; - case Piece_ContainingFunctionName: - case Piece_ContainingFunctionLocation: - out << "\tfunction: "; - break; - } - out << string; - }, flags)) - return false; - return write(out, flags); -} - -bool QueryJob::write(const Symbol &symbol, Flags writeFlags) -{ - Flags toStringFlags; - if (queryFlags() & QueryMessage::SymbolInfoIncludeTargets) - toStringFlags |= Symbol::IncludeTargets; - if (queryFlags() & QueryMessage::SymbolInfoIncludeReferences) - toStringFlags |= Symbol::IncludeReferences; - if (queryFlags() & QueryMessage::SymbolInfoIncludeParents) - toStringFlags |= Symbol::IncludeParents; - if (queryFlags() & QueryMessage::SymbolInfoIncludeBaseClasses) - toStringFlags |= Symbol::IncludeBaseClasses; - if (queryFlags() & (QueryMessage::ContainingFunction|QueryMessage::JSON|QueryMessage::Elisp)) - toStringFlags |= Symbol::IncludeContainingFunction; - if (queryFlags() & (QueryMessage::ContainingFunctionLocation|QueryMessage::JSON|QueryMessage::Elisp)) - toStringFlags |= Symbol::IncludeContainingFunctionLocation; - - if (symbol.isNull()) - return false; - - if (!filterLocation(symbol.location)) - return false; - - if (!mKindFilters.filter(symbol)) - return false; - - String out; - if (queryFlags() & (QueryMessage::Elisp|QueryMessage::JSON)) { - Value val = symbol.toValue(project(), toStringFlags, locationToStringFlags() | Location::NoColor, mPieceFilters); - if (queryFlags() & QueryMessage::Elisp) { - out = RTags::toElisp(val); - } else { - out = val.toJSON(); - } - } else { - out = symbol.toString(project(), toStringFlags, locationToStringFlags(), mPieceFilters); - } - return write(out, writeFlags|Unfiltered); -} - -bool QueryJob::filter(const String &value) const -{ - if (mFilters.isEmpty() && !(queryFlags() & QueryMessage::FilterSystemIncludes)) - return true; - - const char *val = value.constData(); - while (*val && isspace(*val)) - ++val; - const char *space = strchr(val, ' '); - Path path; - uint32_t fileId = 0; - if (space) { - path.assign(val, space - val); - } else { - path = val; - } - - if (!path.isFile()) - return true; // non-file things go unfiltered - - if (queryFlags() & QueryMessage::FilterSystemIncludes && Path::isSystem(val)) - return false; - fileId = Location::fileId(path); - - if (mFilters.isEmpty()) - return true; - - for (const std::shared_ptr &filter : mFilters) { - if (filter->match(fileId, path)) - return true; - } - return false; -} - -int QueryJob::run(const std::shared_ptr &connection) -{ - assert(connection); - mConnection = connection; - const int ret = execute(); - mConnection = 0; - return ret; -} - -bool QueryJob::filterLocation(Location loc) const -{ - if (mFileFilter && loc.fileId() != mFileFilter) - return false; - const int minLine = mQueryMessage ? mQueryMessage->minLine() : -1; - if (minLine != -1) { - assert(mQueryMessage); - assert(mQueryMessage->maxLine() != -1); - const int maxLine = mQueryMessage->maxLine(); - assert(maxLine != -1); - const int line = loc.line(); - if (line < minLine || line > maxLine) { - return false; - } - } - if (!mFilters.isEmpty()) { - for (const std::shared_ptr &filter : mFilters) { - if (filter->match(loc.fileId(), loc.path())) - return true; - } - return false; - } - return true; -} diff --git a/rtags/src/QueryJob.h b/rtags/src/QueryJob.h deleted file mode 100644 index 83ef20a..0000000 --- a/rtags/src/QueryJob.h +++ /dev/null @@ -1,177 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef QueryJob_h -#define QueryJob_h - -#include -#include - -#include "Project.h" -#include "QueryMessage.h" -#include "rct/Flags.h" -#include "rct/List.h" -#include "rct/SignalSlot.h" -#include "rct/String.h" - -class Location; -class QueryMessage; -class Connection; -struct Symbol; -class QueryJob : public Project::FileMapScopeScope -{ -public: - enum JobFlag { - None = 0x0, - WriteUnfiltered = 0x1, - QuoteOutput = 0x2, - QuietJob = 0x4 - }; - enum { Priority = 10 }; - QueryJob(const std::shared_ptr &msg, - const std::shared_ptr &proj, - Flags jobFlags = Flags()); - virtual ~QueryJob(); - - bool hasFilter() const { return mFileFilter || !mFilters.isEmpty(); } - bool hasKindFilter() const { return !mKindFilters.isEmpty(); } - bool hasPieceFilter() const { return !mPieceFilters.isEmpty(); } - List pathFilters() const - { - if (mQueryMessage) - return mQueryMessage->pathFilters(); - return List(); - } - Set pieceFilters() const { return mPieceFilters; } - void setPieceFilters(Set &&pieceFilters) { mPieceFilters = std::move(pieceFilters); } - uint32_t fileFilter() const { return mFileFilter; } - enum WriteFlag { - NoWriteFlags = 0x00, - IgnoreMax = 0x01, - DontQuote = 0x02, - Unfiltered = 0x04, - NoContext = 0x08 - }; - bool write(const String &out, Flags flags = Flags()); - bool write(const Symbol &symbol, Flags writeFlags = Flags()); - bool write(Location location, Flags writeFlags = Flags()); - enum LocationPiece { - Piece_Location, - Piece_Context, - Piece_SymbolName, - Piece_Kind, - Piece_ContainingFunctionName, - Piece_ContainingFunctionLocation - }; - bool locationToString(Location location, - const std::function &cb, - Flags writeFlags = Flags()); - - template - bool write(Flags writeFlags, const char *format, ...) RCT_PRINTF_WARNING(3, 4); - template - bool write(const char *format, ...) RCT_PRINTF_WARNING(2, 3); - Flags jobFlags() const { return mJobFlags; } - void setJobFlags(Flags flags) { mJobFlags = flags; } - void setJobFlag(JobFlag flag, bool on = true) { mJobFlags.set(flag, on); } - Flags queryFlags() const { return mQueryMessage ? mQueryMessage->flags() : Flags(); } - std::shared_ptr queryMessage() const { return mQueryMessage; } - Flags locationToStringFlags() const { return QueryMessage::locationToStringFlags(queryFlags()); } - bool filter(const String &val) const; - Signal > &output() { return mOutput; } - std::shared_ptr project() const { return mProject; } - virtual int execute() = 0; - int run(const std::shared_ptr &connection = 0); - bool isAborted() const { std::lock_guard lock(mMutex); return mAborted; } - void abort() { std::lock_guard lock(mMutex); mAborted = true; } - std::mutex &mutex() const { return mMutex; } - const std::shared_ptr &connection() const { return mConnection; } - bool filterLocation(Location loc) const; - bool filterKind(const Symbol &symbol) const { return mKindFilters.filter(symbol); } -private: - class Filter - { - public: - virtual ~Filter() {} - virtual bool match(uint32_t fileId, const Path &path) const = 0; - }; - class PathFilter : public Filter - { - public: - PathFilter(const Path &p) : pattern(p) {} - virtual bool match(uint32_t, const Path &path) const { return path.startsWith(pattern); } - - const Path pattern; - }; - class RegexFilter : public Filter - { - public: - RegexFilter(const String &str) : regex(str.ref()) {} - virtual bool match(uint32_t, const Path &path) const { return std::regex_search(path.constData(), regex); } - - const std::regex regex; - }; - - class DependencyFilter : public Filter - { - public: - DependencyFilter(uint32_t f, const std::shared_ptr &p) : fileId(f), project(p) {} - virtual bool match(uint32_t f, const Path &) const { return project->dependsOn(fileId, f); } - - const uint32_t fileId; - const std::shared_ptr project; - }; - - mutable std::mutex mMutex; - bool mAborted; - int mLinesWritten; - bool writeRaw(const String &out, Flags flags); - std::shared_ptr mQueryMessage; - Flags mJobFlags; - Signal > mOutput; - std::shared_ptr mProject; - uint32_t mFileFilter; - List > mFilters; - QueryMessage::KindFilters mKindFilters; - Set mPieceFilters; - String mBuffer; - std::shared_ptr mConnection; - Hash mContextCache; -}; - -RCT_FLAGS(QueryJob::JobFlag); -RCT_FLAGS(QueryJob::WriteFlag); - -template -inline bool QueryJob::write(Flags flags, const char *format, ...) -{ - va_list args; - va_start(args, format); - const String ret = String::format(format, args); - va_end(args); - return write(ret, flags); -} - -template -inline bool QueryJob::write(const char *format, ...) -{ - va_list args; - va_start(args, format); - const String ret = String::format(format, args); - va_end(args); - return write(ret); -} - -#endif diff --git a/rtags/src/QueryMessage.cpp b/rtags/src/QueryMessage.cpp deleted file mode 100644 index 67402fc..0000000 --- a/rtags/src/QueryMessage.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "QueryMessage.h" - -#include "rct/Serializer.h" -#include "RTags.h" - -QueryMessage::QueryMessage(Type type) - : RTagsMessage(MessageId), mType(type), mMax(-1), mMinLine(-1), mMaxLine(-1), mBuildIndex(0), mTerminalWidth(-1) -{ -} - -void QueryMessage::encode(Serializer &serializer) const -{ - serializer << mCommandLine << mQuery << mCodeCompletePrefix << mType << mFlags << mMax - << mMinLine << mMaxLine << mBuildIndex << mPathFilters << mKindFilters - << mCurrentFile << mUnsavedFiles << mTerminalWidth -#ifdef RTAGS_HAS_LUA - << mVisitASTScripts -#endif - ; -} - -void QueryMessage::decode(Deserializer &deserializer) -{ - deserializer >> mCommandLine >> mQuery >> mCodeCompletePrefix >> mType >> mFlags >> mMax - >> mMinLine >> mMaxLine >> mBuildIndex >> mPathFilters >> mKindFilters - >> mCurrentFile >> mUnsavedFiles >> mTerminalWidth -#ifdef RTAGS_HAS_LUA - >> mVisitASTScripts -#endif - ; -} - -Flags QueryMessage::locationToStringFlags(Flags queryFlags) -{ - Flags ret; - if (!(queryFlags & NoContext)) - ret |= Location::ShowContext; - if (queryFlags & NoColor) - ret |= Location::NoColor; - if (queryFlags & AbsolutePath) - ret |= Location::AbsolutePath; - return ret; -} - -Match QueryMessage::match() const -{ - Flags flags = Match::Flag_StringMatch; - if (mFlags & MatchRegex) - flags |= Match::Flag_Regex; - - return Match(mQuery, flags); -} - -QueryMessage::Flag QueryMessage::flagFromString(const String &string) -{ - if (string == "no-context") { - return NoContext; - } else if (string == "filter-system-includes") { - return FilterSystemIncludes; - } else if (string == "strip-parentheses") { - return StripParentheses; - } else if (string == "all-references") { - return AllReferences; - } else if (string == "reverse-sort") { - return ReverseSort; - } else if (string == "elisp") { - return Elisp; - } else if (string == "match-regexp") { - return MatchRegex; - } else if (string == "match-case-insensitive") { - return MatchCaseInsensitive; - } else if (string == "find-virtuals") { - return FindVirtuals; - } else if (string == "silent") { - return Silent; - } else if (string == "absolute-path") { - return AbsolutePath; - } else if (string == "find-file-prefer-exact") { - return FindFilePreferExact; - } else if (string == "symbol-info-include-parents") { - return SymbolInfoIncludeParents; - } else if (string == "symbol-info-include-targets") { - return SymbolInfoIncludeTargets; - } else if (string == "symbol-info-include-references") { - return SymbolInfoIncludeReferences; - } else if (string == "symbol-info-include-base-classes") { - return SymbolInfoIncludeBaseClasses; - } else if (string == "declaration-only") { - return DeclarationOnly; - } else if (string == "definiton-only") { - return DefinitionOnly; - } else if (string == "containing-function") { - return ContainingFunction; - } else if (string == "cursor-kind") { - return CursorKind; - } else if (string == "display-name") { - return DisplayName; - } else if (string == "compilation-flags-only") { - return CompilationFlagsOnly; - } else if (string == "compilation-flags-split-line") { - return CompilationFlagsSplitLine; - } else if (string == "dump-include-headers") { - return DumpIncludeHeaders; - } else if (string == "silent-query") { - return SilentQuery; - } else if (string == "synchronous-completions") { - return SynchronousCompletions; - } else if (string == "no-sort-references-by-input") { - return NoSortReferencesByInput; - } else if (string == "has-location") { - return HasLocation; - } else if (string == "wildcard-symbol-names") { - return WildcardSymbolNames; - } else if (string == "no-color") { - return NoColor; - } else if (string == "target-usrs") { - return TargetUsrs; - } - return NoFlag; -} - -bool QueryMessage::KindFilters::filter(const Symbol &symbol) const -{ - if (isEmpty()) - return true; - - String spelling = Symbol::kindSpelling(symbol.kind).toLower(); - spelling.remove(' '); - auto match = [&spelling, &symbol](const Map > &map, bool hasWildcardsOrCategories) { - auto it = map.find(spelling); - auto matchDefinition = [&symbol](Flags f) { - f &= Definition|NotDefinition; - switch (f.cast()) { - case Definition: - if (symbol.isDefinition()) - return true; - break; - case NotDefinition: - if (!symbol.isDefinition()) - return true; - break; - default: - assert(f == (Definition|NotDefinition)); - return true; - } - return false; - }; - if (it != map.end() && matchDefinition(it->second)) { - return true; - } - if (hasWildcardsOrCategories) { - for (const auto &pair : map) { - if (pair.second & Wildcard) { - if (matchDefinition(pair.second) && Rct::wildCmp(pair.first.constData(), spelling.constData())) { - return true; - } - } else if (pair.second & Category && matchDefinition(pair.second)) { - if (pair.first == "references") { - if (symbol.isReference()) - return true; - } else if (pair.first == "statements") { - if (clang_isStatement(symbol.kind)) - return true; - } else if (pair.first == "declarations") { - if (clang_isDeclaration(symbol.kind)) - return true; - } else if (pair.first == "expressions") { - if (clang_isExpression(symbol.kind)) - return true; - } else if (pair.first == "attributes") { - if (clang_isAttribute(symbol.kind)) - return true; - } else if (pair.first == "preprocessing") { - if (clang_isPreprocessing(symbol.kind)) - return true; - } else { - assert(0); - } - } - } - } - return false; - }; - if (!out.isEmpty() && match(out, flags & (OutHasWildcards|OutHasCategories))) { - return false; - } - if (in.isEmpty() || match(in, flags & (InHasWildcards|InHasCategories))) { - return true; - } else { - return false; - } -} - -void QueryMessage::KindFilters::insert(const String &arg) -{ - for (String a : arg.toLower().split(',', String::SkipEmpty)) { - Flags f = Definition|NotDefinition; - Map > *target = ∈ - const bool hasWildCard = a.contains("?") || a.contains("*"); - if (hasWildCard) - f |= Wildcard; - - if (a.endsWith('+')) { - a.chop(1); - f &= ~NotDefinition; - } else if (a.endsWith('-')) { - a.chop(1); - f &= ~Definition; - } - - const bool o = a.startsWith('-'); - if (o) { - target = &out; - if (hasWildCard) - flags |= OutHasWildcards; - a.remove(0, 1); - } else if (hasWildCard) { - flags |= InHasWildcards; - } - if (a == "references" || a == "statements" || a == "declarations" - || a == "expressions" || a == "attributes" || a == "preprocessing") { - f |= Category; - flags |= (o ? OutHasCategories : InHasCategories); - } - (*target)[a] |= f; - } -} diff --git a/rtags/src/QueryMessage.h b/rtags/src/QueryMessage.h deleted file mode 100644 index 3b58b12..0000000 --- a/rtags/src/QueryMessage.h +++ /dev/null @@ -1,292 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef QUERYMESSAGE_H -#define QUERYMESSAGE_H - -#include -#include "Location.h" -#include "Match.h" -#include "rct/Flags.h" -#include "rct/Log.h" -#include "rct/Path.h" -#include "rct/Serializer.h" -#include "RTags.h" -#include "RTagsMessage.h" - -class QueryMessage : public RTagsMessage -{ -public: - enum { MessageId = QueryId }; - enum Type { - Invalid, - GenerateTest, - CheckReindex, - ClassHierarchy, - ClearProjects, - CodeCompleteAt, - DebugLocations, - DeleteProject, - Dependencies, - Diagnose, - DumpCompileCommands, - DumpCompletions, - DumpFile, - DumpFileMaps, - FindFile, - FindSymbols, - FixIts, - FollowLocation, - HasFileManager, - IncludeFile, - IsIndexed, - IsIndexing, - JobCount, - LastIndexed, - ListSymbols, - PreprocessFile, - Project, - ReferencesLocation, - ReferencesName, - Reindex, - ReloadFileManager, - RemoveFile, - SendDiagnostics, - SetBuffers, - Sources, - Status, - Suspend, - SymbolInfo, - Validate, -#ifdef RTAGS_HAS_LUA - VisitAST, -#endif - Tokens - }; - - enum Flag { - NoFlag = 0x0, - NoContext = (1ull << 0), - FilterSystemIncludes = (1ull << 1), - StripParentheses = (1ull << 2), - AllReferences = (1ull << 3), - ReverseSort = (1ull << 4), - Elisp = (1ull << 5), - MatchRegex = (1ull << 6), - MatchCaseInsensitive = (1ull << 7), - FindVirtuals = (1ull << 8), - Silent = (1ull << 9), - AbsolutePath = (1ull << 10), - FindFilePreferExact = (1ull << 11), - SymbolInfoIncludeParents = (1ull << 12), - SymbolInfoIncludeTargets = (1ull << 13), - SymbolInfoIncludeReferences = (1ull << 14), - SymbolInfoIncludeBaseClasses = (1ull << 15), - DeclarationOnly = (1ull << 16), - DefinitionOnly = (1ull << 17), - TargetUsrs = (1ull << 18), - CursorKind = (1ull << 19), - DisplayName = (1ull << 20), - CompilationFlagsOnly = (1ull << 21), - CompilationFlagsSplitLine = (1ull << 22), - CompilationFlagsPwd = (1ull << 23), - DumpIncludeHeaders = (1ull << 24), - SilentQuery = (1ull << 25), - SynchronousCompletions = (1ull << 26), - NoSortReferencesByInput = (1ull << 27), - HasLocation = (1ull << 28), - WildcardSymbolNames = (1ull << 29), - NoColor = (1ull << 30), - Rename = (1ull << 31), - ContainingFunction = (1ull << 32), - ContainingFunctionLocation = (1ull << 33), - DumpCheckIncludes = (1ull << 34), - CurrentProjectOnly = (1ull << 35), - Wait = (1ull << 36), - CodeCompleteIncludeMacros = (1ull << 37), - XML = (1ull << 38), - NoSpellChecking = (1ull << 39), - CodeCompleteIncludes = (1ull << 40), - TokensIncludeSymbols = (1ull << 41), - JSON = (1ull << 42), - CodeCompletionEnabled = (1ull << 43), - SynchronousDiagnostics = (1ull << 44), - CodeCompleteNoWait = (1ull << 45), - AllTargets = (1ull << 46) - }; - - QueryMessage(Type type = Invalid); - - Type type() const { return mType; } - - struct KindFilters { - enum Flag { - None = 0x0, - InHasWildcards = 0x1, - InHasCategories = 0x2, - OutHasWildcards = 0x4, - OutHasCategories = 0x8 - }; - enum DefinitionType { - Unset = 0x0, - NotDefinition = 0x1, - Definition = 0x2, - Wildcard = 0x4, - Category = 0x8 - }; - Flags flags; - Map > in, out; - bool filter(const Symbol &symbol) const; - void insert(const String &arg); - bool isEmpty() const { return in.isEmpty() && out.isEmpty(); } - }; - - struct PathFilter { - String pattern; - enum Mode { - Self, - Dependency - } mode; - - bool operator<(const PathFilter &other) const - { - const int cmp = pattern.compare(other.pattern); - if (!cmp) - return mode < other.mode; - return cmp < 0; - } - }; - const List &pathFilters() const { return mPathFilters; } - void setPathFilters(const Set &filters) - { - mPathFilters = filters.toList(); - std::sort(mPathFilters.begin(), mPathFilters.end()); - } - -#ifdef RTAGS_HAS_LUA - void setVisitASTScripts(const List &scripts) { mVisitASTScripts = scripts; } - List visitASTScripts() const { return mVisitASTScripts; } -#endif - - void setKindFilters(const KindFilters &kindFilters) { mKindFilters = kindFilters; } - const KindFilters &kindFilters() const { return mKindFilters; } - - void setUnsavedFiles(const UnsavedFiles &unsavedFiles) { mUnsavedFiles = unsavedFiles; } - const UnsavedFiles &unsavedFiles() const { return mUnsavedFiles; } - - String query() const { return mQuery; } - Location location(Location::DecodeFlag flag = Location::NoDecodeFlag) const - { - return Location::decode(mQuery, flag); - } - void setQuery(String &&query) { mQuery = std::move(query); } - void setBuildIndex(int index) { mBuildIndex = index; } - int buildIndex() const { return mBuildIndex; } - - int terminalWidth() const { return mTerminalWidth; } - void setTerminalWidth(int w) { mTerminalWidth = w; } - - Match match() const; - - void setRangeFilter(int min, int max) - { - mMinLine = min; - mMaxLine = max; - } - - int minLine() const { return mMinLine; } - int maxLine() const { return mMaxLine; } - - int max() const { return mMax; } - void setMax(int max) { mMax = max; } - - Flags flags() const { return mFlags; } - void setFlags(Flags flags) - { - mFlags = flags; - switch (mType) { - case ClearProjects: - case Project: - case DeleteProject: - case Reindex: - case RemoveFile: - case Sources: - mFlags |= MatchRegex; - break; - default: - break; - } - } - - void setFlag(Flag flag, bool on = true) { mFlags.set(flag, on); } - static Flag flagFromString(const String &string); - static Flags locationToStringFlags(Flags queryFlags); - inline Flags locationToStringFlags() const { return locationToStringFlags(mFlags); } - - virtual void encode(Serializer &serializer) const override; - virtual void decode(Deserializer &deserializer) override; - - void setCurrentFile(const Path ¤tFile) { mCurrentFile = currentFile; } - Path currentFile() const { return mCurrentFile; } - - String codeCompletePrefix() const { return mCodeCompletePrefix; } - void setCodeCompletePrefix(String &&prefix) { mCodeCompletePrefix = std::move(prefix); } -private: - String mQuery, mCodeCompletePrefix; - Type mType; - Flags mFlags; - int mMax, mMinLine, mMaxLine, mBuildIndex; - List mPathFilters; - KindFilters mKindFilters; - Path mCurrentFile; - UnsavedFiles mUnsavedFiles; - int mTerminalWidth; -#ifdef RTAGS_HAS_LUA - List mVisitASTScripts; -#endif -}; - -DECLARE_NATIVE_TYPE(QueryMessage::Type); -RCT_FLAGS(QueryMessage::Flag); -RCT_FLAGS(QueryMessage::KindFilters::DefinitionType); -RCT_FLAGS(QueryMessage::KindFilters::Flag); - -inline Serializer &operator<<(Serializer &s, const QueryMessage::PathFilter &filter) -{ - s << filter.pattern << static_cast(filter.mode); - return s; -} - -inline Deserializer &operator>>(Deserializer &s, QueryMessage::PathFilter &filter) -{ - uint8_t mode; - s >> filter.pattern >> mode; - filter.mode = static_cast(mode); - return s; -} - -inline Serializer &operator<<(Serializer &s, const QueryMessage::KindFilters &filter) -{ - s << filter.flags << filter.in << filter.out; - return s; -} - -inline Deserializer &operator>>(Deserializer &s, QueryMessage::KindFilters &filter) -{ - s >> filter.flags >> filter.in >> filter.out; - return s; -} - -#endif // QUERYMESSAGE_H diff --git a/rtags/src/RClient.cpp b/rtags/src/RClient.cpp deleted file mode 100644 index 937a0a2..0000000 --- a/rtags/src/RClient.cpp +++ /dev/null @@ -1,1361 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "RClient.h" - -#include -#include - -#include "FileMap.h" -#include "IndexMessage.h" -#include "LogOutputMessage.h" -#include "rct/Connection.h" -#include "rct/EventLoop.h" -#include "rct/Log.h" -#include "rct/QuitMessage.h" -#include "rct/Rct.h" -#include "rct/StopWatch.h" -#include "rct/OnDestruction.h" -#include "RTags.h" -#include "RTagsLogOutput.h" - -#define DEFAULT_CONNECT_TIMEOUT 1000 -#define XSTR(s) #s -#define STR(s) XSTR(s) - -std::initializer_list > opts = { - { RClient::None, String(), 0, CommandLineParser::NoValue, "Options:" }, - { RClient::Verbose, "verbose", 'v', CommandLineParser::NoValue, "Be more verbose." }, - { RClient::Version, "version", 0, CommandLineParser::NoValue, "Print current version." }, - { RClient::VerifyVersion, "verify-version", 0, CommandLineParser::Required, "Verify that the correct protocol version is used." }, - { RClient::Silent, "silent", 'Q', CommandLineParser::NoValue, "Be silent." }, - { RClient::Help, "help", 'h', CommandLineParser::NoValue, "Display this help." }, - { RClient::Noop, "config", 0, CommandLineParser::Required, "Use this file (instead of ~/.rcrc)." }, - { RClient::Noop, "no-rc", 0, CommandLineParser::NoValue, "Don't load any rc files." }, - - { RClient::None, String(), 0, CommandLineParser::NoValue, "" }, - { RClient::None, String(), 0, CommandLineParser::NoValue, "Rdm:" }, - { RClient::QuitRdm, "quit-rdm", 'q', CommandLineParser::NoValue, "Tell server to shut down with optional exit code as argument." }, - { RClient::ConnectTimeout, "connect-timeout", 0, CommandLineParser::Required, "Timeout for connecting to rdm in ms (default " STR(DEFAULT_CONNECT_TIMEOUT) ")." }, - - { RClient::None, String(), 0, CommandLineParser::NoValue, "" }, - { RClient::None, String(), 0, CommandLineParser::NoValue, "Project management:" }, - { RClient::Clear, "clear", 'C', CommandLineParser::NoValue, "Clear projects." }, - { RClient::Project, "project", 'w', CommandLineParser::Optional, "With arg, select project matching that if unique, otherwise list all projects." }, - { RClient::DeleteProject, "delete-project", 'W', CommandLineParser::Required, "Delete all projects matching regex." }, - { RClient::JobCount, "job-count", 'j', CommandLineParser::Optional, "Set or query current job count. (Prefix with l to set low-priority-job-count)." }, - - { RClient::None, String(), 0, CommandLineParser::NoValue, "" }, - { RClient::None, String(), 0, CommandLineParser::NoValue, "Indexing commands:" }, - { RClient::Compile, "compile", 'c', CommandLineParser::Optional, "Pass compilation arguments to rdm." }, - { RClient::GuessFlags, "guess-flags", 0, CommandLineParser::NoValue, "Guess compile flags (used with -c)." }, - { RClient::LoadCompileCommands, "load-compile-commands", 'J', CommandLineParser::Optional, "Load compile_commands.json from directory" }, - { RClient::Suspend, "suspend", 'X', CommandLineParser::Optional, "Dump suspended files (don't track changes in these files) with no arg. Otherwise toggle suspension for arg." }, - - { RClient::None, String(), 0, CommandLineParser::NoValue, "" }, - { RClient::None, String(), 0, CommandLineParser::NoValue, "Query commands:" }, - { RClient::FollowLocation, "follow-location", 'f', CommandLineParser::Required, "Follow this location." }, - { RClient::ReferenceName, "references-name", 'R', CommandLineParser::Required, "Find references matching arg." }, - { RClient::ReferenceLocation, "references", 'r', CommandLineParser::Required, "Find references matching this location." }, - { RClient::ListSymbols, "list-symbols", 'S', CommandLineParser::Optional, "List symbol names matching arg." }, - { RClient::FindSymbols, "find-symbols", 'F', CommandLineParser::Optional, "Find symbols matching arg." }, - { RClient::SymbolInfo, "symbol-info", 'U', CommandLineParser::Required, "Get cursor info for this location." }, - { RClient::Status, "status", 's', CommandLineParser::Optional, "Dump status of rdm. Arg can be symbols or symbolNames." }, - { RClient::Diagnose, "diagnose", 0, CommandLineParser::Required, "Resend diagnostics for file." }, - { RClient::DiagnoseAll, "diagnose-all", 0, CommandLineParser::NoValue, "Resend diagnostics for all files." }, - { RClient::LastIndexed, "last-indexed", 0, CommandLineParser::NoValue, "Get timestamp of the last time indexing completed for the current project." }, - { RClient::IsIndexed, "is-indexed", 'T', CommandLineParser::Required, "Check if rtags knows about, and is ready to return information about, this source file." }, - { RClient::IsIndexing, "is-indexing", 0, CommandLineParser::NoValue, "Check if rtags is currently indexing files." }, - { RClient::HasFileManager, "has-filemanager", 0, CommandLineParser::Optional, "Check if rtags has info about files in this directory." }, - { RClient::PreprocessFile, "preprocess", 'E', CommandLineParser::Required, "Preprocess file." }, - { RClient::Reindex, "reindex", 'V', CommandLineParser::Optional, "Reindex all files or all files matching pattern." }, - { RClient::CheckReindex, "check-reindex", 'x', CommandLineParser::Optional, "Check if reindexing is necessary for all files matching pattern." }, - { RClient::FindFile, "path", 'P', CommandLineParser::Optional, "Print files matching pattern." }, - { RClient::CurrentProject, "current-project", 0, CommandLineParser::NoValue, "Print path for current project." }, - { RClient::DumpFile, "dump-file", 'd', CommandLineParser::Required, "Dump source file." }, - { RClient::CheckIncludes, "check-includes", 0, CommandLineParser::Required, "Check includes for source file." }, - { RClient::DumpFileMaps, "dump-file-maps", 0, CommandLineParser::Required, "Dump file maps for file." }, - { RClient::GenerateTest, "generate-test", 0, CommandLineParser::Required, "Generate a test for a given source file." }, - { RClient::RdmLog, "rdm-log", 'g', CommandLineParser::NoValue, "Receive logs from rdm." }, - { RClient::FixIts, "fixits", 0, CommandLineParser::Required, "Get fixits for file." }, - { RClient::RemoveFile, "remove", 'D', CommandLineParser::Required, "Remove file from project." }, - { RClient::FindProjectRoot, "find-project-root", 0, CommandLineParser::Required, "Use to check behavior of find-project-root." }, - { RClient::FindProjectBuildRoot, "find-project-build-root", 0, CommandLineParser::Required, "Use to check behavior of find-project-root for builds." }, - { RClient::IncludeFile, "include-file", 0, CommandLineParser::Required, "Use to generate include statement for symbol." }, - { RClient::Sources, "sources", 0, CommandLineParser::Optional, "Dump sources for source file." }, - { RClient::Dependencies, "dependencies", 0, CommandLineParser::Required, "Dump dependencies for source file [(includes, included-by, depends-on, depended-on, tree-depends-on, raw)]." }, - { RClient::AllDependencies, "all-dependencies", 0, CommandLineParser::NoValue, "Dump dependencies for all source files [(includes, included-by, depends-on, depended-on, tree-depends-on, raw)]." }, - { RClient::ReloadFileManager, "reload-file-manager", 'B', CommandLineParser::NoValue, "Reload file manager." }, - { RClient::Man, "man", 0, CommandLineParser::NoValue, "Output XML for xmltoman to generate man page for rc :-)" }, - { RClient::CodeCompleteAt, "code-complete-at", 'l', CommandLineParser::Required, "Code complete at location: arg is file:line:col." }, - { RClient::SendDiagnostics, "send-diagnostics", 0, CommandLineParser::Required, "Only for debugging. Send data to all -G connections." }, - { RClient::DumpCompletions, "dump-completions", 0, CommandLineParser::NoValue, "Dump cached completions." }, - { RClient::DumpCompileCommands, "dump-compile-commands", 0, CommandLineParser::NoValue, "Dump compilation database for project." }, - { RClient::SetBuffers, "set-buffers", 0, CommandLineParser::Optional, "Set active buffers (list of filenames for active buffers in editor)." }, - { RClient::ListBuffers, "list-buffers", 0, CommandLineParser::NoValue, "List active buffers." }, - { RClient::AddBuffers, "add-buffers", 0, CommandLineParser::Required, "Add additional buffers." }, - { RClient::RemoveBuffers, "remove-buffers", 0, CommandLineParser::Required, "Remove buffers." }, - { RClient::ListCursorKinds, "list-cursor-kinds", 0, CommandLineParser::NoValue, "List spelling for known cursor kinds." }, - { RClient::ClassHierarchy, "class-hierarchy", 0, CommandLineParser::Required, "Dump class hierarcy for struct/class at location." }, - { RClient::DebugLocations, "debug-locations", 0, CommandLineParser::Optional, "Manipulate debug locations." }, -#ifdef RTAGS_HAS_LUA - { RClient::VisitAST, "visit-ast", 0, CommandLineParser::Required, "Visit AST of a source file." }, -#endif - { RClient::Validate, "validate", 0, CommandLineParser::NoValue, "Validate database files for current project." }, - { RClient::Tokens, "tokens", 0, CommandLineParser::Required, "Dump tokens for file. --tokens file.cpp:123-321 for range." }, - { RClient::None, String(), 0, CommandLineParser::NoValue, "" }, - { RClient::None, String(), 0, CommandLineParser::NoValue, "Command flags:" }, - { RClient::StripParen, "strip-paren", 'p', CommandLineParser::NoValue, "Strip parens in various contexts." }, - { RClient::Max, "max", 'M', CommandLineParser::Required, "Max lines of output for queries." }, - { RClient::ReverseSort, "reverse-sort", 'O', CommandLineParser::NoValue, "Sort output reversed." }, - { RClient::Rename, "rename", 0, CommandLineParser::NoValue, "Used for --references to indicate that we're using the results to rename symbols." }, - { RClient::UnsavedFile, "unsaved-file", 0, CommandLineParser::Required, "Pass unsaved file on command line. E.g. --unsaved-file=main.cpp:1200 then write 1200 bytes on stdin." }, - { RClient::LogFile, "log-file", 'L', CommandLineParser::Required, "Log to this file." }, - { RClient::NoContext, "no-context", 'N', CommandLineParser::NoValue, "Don't print context for locations." }, - { RClient::PathFilter, "path-filter", 'i', CommandLineParser::Required, "Filter out results not matching with arg." }, - { RClient::DependencyFilter, "dependency-filter", 0, CommandLineParser::Required, "Filter out results unless argument depends on them." }, - { RClient::RangeFilter, "range-filter", 0, CommandLineParser::Required, "Filter out results not in the specified range." }, - { RClient::FilterSystemHeaders, "filter-system-headers", 'H', CommandLineParser::NoValue, "Don't exempt system headers from path filters." }, - { RClient::AllReferences, "all-references", 'e', CommandLineParser::NoValue, "Include definitions/declarations/constructors/destructors for references. Used for rename symbol." }, - { RClient::TargetUsrs, "target-usrs", 0, CommandLineParser::NoValue, "Print all matching usr targets for -f. Used for debugging." }, - { RClient::AllTargets, "all-targets", 0, CommandLineParser::NoValue, "Print multiple targets for -f. Sorted by best match." }, - { RClient::Elisp, "elisp", 'Y', CommandLineParser::NoValue, "Output elisp: (list \"one\" \"two\" ...)." }, - { RClient::JSON, "json", 0, CommandLineParser::NoValue, "Output json." }, - { RClient::Diagnostics, "diagnostics", 'm', CommandLineParser::NoValue, "Receive async formatted diagnostics from rdm." }, - { RClient::MatchRegex, "match-regexp", 'Z', CommandLineParser::NoValue, "Treat various text patterns as regexps (-P, -i, -V, -F)." }, - { RClient::MatchCaseInsensitive, "match-icase", 'I', CommandLineParser::NoValue, "Match case insensitively" }, - { RClient::AbsolutePath, "absolute-path", 'K', CommandLineParser::NoValue, "Print files with absolute path." }, - { RClient::SocketFile, "socket-file", 'n', CommandLineParser::Required, "Use this socket file (default ~/.rdm)." }, - { RClient::SocketAddress, "socket-address", 0, CommandLineParser::Required, "Use this host:port combination (instead of --socket-file)." }, - { RClient::Timeout, "timeout", 'y', CommandLineParser::Required, "Max time in ms to wait for job to finish (default no timeout)." }, - { RClient::FindVirtuals, "find-virtuals", 'k', CommandLineParser::NoValue, "Use in combinations with -R or -r to show other implementations of this function." }, - { RClient::FindFilePreferExact, "find-file-prefer-exact", 'A', CommandLineParser::NoValue, "Use to make --find-file prefer exact matches over partial matches." }, - { RClient::SymbolInfoIncludeParents, "symbol-info-include-parents", 0, CommandLineParser::NoValue, "Use to make --symbol-info include parent symbols." }, - { RClient::SymbolInfoIncludeTargets, "symbol-info-include-targets", 0, CommandLineParser::NoValue, "Use to make --symbol-info include target symbols." }, - { RClient::SymbolInfoIncludeReferences, "symbol-info-include-references", 0, CommandLineParser::NoValue, "Use to make --symbol-info include reference symbols." }, - { RClient::SymbolInfoIncludeBaseClasses, "symbol-info-include-base-classes", 0, CommandLineParser::NoValue, "Use to make --symbol-info include baseclasses' symbols." }, - { RClient::CursorKind, "cursor-kind", 0, CommandLineParser::NoValue, "Include cursor kind in --find-symbols output." }, - { RClient::DisplayName, "display-name", 0, CommandLineParser::NoValue, "Include display name in --find-symbols output." }, - { RClient::CurrentFile, "current-file", 0, CommandLineParser::Required, "Pass along which file is being edited to give rdm a better chance at picking the right project." }, - { RClient::DeclarationOnly, "declaration-only", 'G', CommandLineParser::NoValue, "Filter out definitions (unless inline).", }, - { RClient::DefinitionOnly, "definition-only", 0, CommandLineParser::NoValue, "Filter out declarations (unless inline).", }, - { RClient::KindFilter, "kind-filter", 0, CommandLineParser::Required, "Only return results matching this kind.", }, - { RClient::ContainingFunction, "containing-function", 'o', CommandLineParser::NoValue, "Include name of containing function in output."}, - { RClient::ContainingFunctionLocation, "containing-function-location", 0, CommandLineParser::NoValue, "Include location of containing function in output."}, - { RClient::BuildIndex, "build-index", 0, CommandLineParser::Required, "For sources with multiple builds, use the arg'th." }, - { RClient::CompilationFlagsOnly, "compilation-flags-only", 0, CommandLineParser::NoValue, "For --source, only print compilation flags." }, - { RClient::CompilationFlagsSplitLine, "compilation-flags-split-line", 0, CommandLineParser::NoValue, "For --source, print one compilation flag per line." }, - { RClient::CompilationFlagsPwd, "compilation-flags-pwd", 0, CommandLineParser::NoValue, "For --source, print pwd for compile command on the first line." }, - { RClient::DumpIncludeHeaders, "dump-include-headers", 0, CommandLineParser::NoValue, "For --dump-file, also dump dependencies." }, - { RClient::SilentQuery, "silent-query", 0, CommandLineParser::NoValue, "Don't log this request in rdm." }, - { RClient::SynchronousCompletions, "synchronous-completions", 0, CommandLineParser::NoValue, "Wait for completion results and print them to stdout." }, - { RClient::SynchronousDiagnostics, "synchronous-diagnostics", 0, CommandLineParser::NoValue, "Wait for diagnostics and print them to stdout." }, - { RClient::XML, "xml", 0, CommandLineParser::NoValue, "Output XML" }, - { RClient::NoSortReferencesByInput, "no-sort-references-by-input", 0, CommandLineParser::NoValue, "Don't sort references by input position." }, - { RClient::ProjectRoot, "project-root", 0, CommandLineParser::Required, "Override project root for compile commands." }, - { RClient::RTagsConfig, "rtags-config", 0, CommandLineParser::Required, "Print out .rtags-config for argument." }, - { RClient::WildcardSymbolNames, "wildcard-symbol-names", 'a', CommandLineParser::NoValue, "Expand * like wildcards in --list-symbols and --find-symbols." }, - { RClient::NoColor, "no-color", 'z', CommandLineParser::NoValue, "Don't colorize context." }, - { RClient::Wait, "wait", 0, CommandLineParser::NoValue, "Wait for reindexing to finish." }, - { RClient::CodeCompleteIncludeMacros, "code-complete-include-macros", 0, CommandLineParser::NoValue, "Include macros in code completion results." }, - { RClient::CodeCompleteIncludes, "code-complete-includes", 0, CommandLineParser::NoValue, "Give includes in completion results." }, - { RClient::CodeCompleteNoWait, "code-complete-no-wait", 0, CommandLineParser::NoValue, "Don't wait for synchronous completion if the translation unit has to be created." }, - { RClient::CodeCompletePrefix, "code-complete-prefix", 0, CommandLineParser::Required, "Filter out code completion results that don't start with this prefix." }, - { RClient::CodeCompletionEnabled, "code-completion-enabled", 'b', CommandLineParser::NoValue, "Inform rdm that we're code-completing. Use with --diagnose" }, - { RClient::NoSpellCheckinging, "no-spell-checking", 0, CommandLineParser::NoValue, "Don't produce spell check info in diagnostics." }, -#ifdef RTAGS_HAS_LUA - { RClient::VisitASTScript, "visit-ast-script", 0, CommandLineParser::Required, "Use this script visit AST (@file.js|sourcecode)." }, -#endif - { RClient::TokensIncludeSymbols, "tokens-include-symbols", 0, CommandLineParser::NoValue, "Include symbols for tokens." }, - { RClient::NoRealPath, "no-realpath", 0, CommandLineParser::NoValue, "Don't resolve paths using realpath(3)." }, - { RClient::None, String(), 0, CommandLineParser::NoValue, 0 } -}; - -class RCCommand -{ -public: - RCCommand() {} - virtual ~RCCommand() {} - virtual RTags::ExitCode exec(RClient *rc, const std::shared_ptr &connection) = 0; - virtual String description() const = 0; -}; - -class QueryCommand : public RCCommand -{ -public: - QueryCommand(QueryMessage::Type t, String &&q) - : RCCommand(), type(t), query(std::move(q)) - {} - - const QueryMessage::Type type; - String query; - Flags extraQueryFlags; - - virtual RTags::ExitCode exec(RClient *rc, const std::shared_ptr &connection) override - { -#ifndef HAS_JSON_H - if (type == QueryMessage::CodeCompleteAt && rc->queryFlags() & QueryMessage::JSON) { - fprintf(stdout, "{\"error\": \"JSON output for completions is not supported with this compiler\"}\n"); - return RTags::ArgumentParseError; - } -#endif - QueryMessage msg(type); - msg.setCommandLine(rc->commandLine()); - msg.setQuery(std::move(query)); - msg.setBuildIndex(rc->buildIndex()); - msg.setUnsavedFiles(rc->unsavedFiles()); - msg.setFlags(extraQueryFlags | rc->queryFlags()); - msg.setMax(rc->max()); - msg.setPathFilters(rc->pathFilters()); - msg.setKindFilters(rc->kindFilters()); - msg.setRangeFilter(rc->minOffset(), rc->maxOffset()); - msg.setTerminalWidth(rc->terminalWidth()); - msg.setCurrentFile(rc->currentFile()); - msg.setCodeCompletePrefix(rc->codeCompletePrefix()); -#ifdef RTAGS_HAS_LUA - msg.setVisitASTScripts(rc->visitASTScripts()); -#endif - return connection->send(msg) ? RTags::Success : RTags::NetworkFailure; - } - - virtual String description() const override - { - return ("QueryMessage " + String::number(type) + " " + query); - } -}; - -class QuitCommand : public RCCommand -{ -public: - QuitCommand(int exit) - : RCCommand(), mExitCode(exit) - {} - - virtual RTags::ExitCode exec(RClient *, const std::shared_ptr &connection) override - { - const QuitMessage msg(mExitCode); - return connection->send(msg) ? RTags::Success : RTags::NetworkFailure; - } - virtual String description() const override - { - return String::format<32>("QuitMessage(%d)", mExitCode); - } -private: - const int mExitCode; -}; - -class RdmLogCommand : public RCCommand -{ -public: - static const LogLevel Default; - - RdmLogCommand(LogLevel level) - : RCCommand(), mLevel(level) - { - } - virtual RTags::ExitCode exec(RClient *rc, const std::shared_ptr &connection) override - { - unsigned int flags = RTagsLogOutput::None; - if (rc->queryFlags() & QueryMessage::Elisp) { - flags |= RTagsLogOutput::Elisp; - } else if (rc->queryFlags() & QueryMessage::XML) { - flags |= RTagsLogOutput::XML; - } else if (rc->queryFlags() & QueryMessage::JSON) { - flags |= RTagsLogOutput::JSON; - } else if (rc->queryFlags() & QueryMessage::NoSpellChecking) { - flags |= RTagsLogOutput::NoSpellChecking; - } - - const LogLevel level = mLevel == Default ? rc->logLevel() : mLevel; - LogOutputMessage msg(level, flags); - msg.setCommandLine(rc->commandLine()); - return connection->send(msg) ? RTags::Success : RTags::NetworkFailure; - } - virtual String description() const override - { - return "RdmLogCommand"; - } - const LogLevel mLevel; -}; - -const LogLevel RdmLogCommand::Default(-1); - -class CompileCommand : public RCCommand -{ -public: - CompileCommand(String &&a, const Path &c) - : RCCommand(), args(std::move(a)), cwd(c) - {} - CompileCommand(Path &&path) - : RCCommand(), compileCommands(std::move(path)) - {} - - String args; - Path cwd; - Path compileCommands; - virtual RTags::ExitCode exec(RClient *rc, const std::shared_ptr &connection) override - { - IndexMessage msg; - msg.setCommandLine(rc->commandLine()); - msg.setWorkingDirectory(std::move(cwd)); - msg.setFlag(IndexMessage::GuessFlags, rc->mGuessFlags); - msg.setArguments(std::move(args)); - msg.setCompileCommands(std::move(compileCommands)); - msg.setEnvironment(rc->environment()); - if (!rc->projectRoot().isEmpty()) - msg.setProjectRoot(rc->projectRoot()); - - return connection->send(msg) ? RTags::Success : RTags::NetworkFailure; - } - virtual String description() const override - { - return ("IndexMessage " + cwd); - } -}; - -RClient::RClient() - : mMax(-1), mTimeout(-1), mMinOffset(-1), mMaxOffset(-1), - mConnectTimeout(DEFAULT_CONNECT_TIMEOUT), mBuildIndex(0), - mLogLevel(LogLevel::Error), mTcpPort(0), mGuessFlags(false), - mTerminalWidth(-1), mExitCode(RTags::ArgumentParseError) -{ - struct winsize w; - ioctl(0, TIOCGWINSZ, &w); - mTerminalWidth = w.ws_col; - if (mTerminalWidth <= 0) - mTerminalWidth = 1024; -} - -RClient::~RClient() -{ - cleanupLogging(); -} - -void RClient::addQuery(QueryMessage::Type type, String &&query, Flags extraQueryFlags) -{ - auto cmd = std::make_shared(type, std::move(query)); - cmd->extraQueryFlags = extraQueryFlags; - mCommands.append(cmd); -} - -void RClient::addQuitCommand(int exitCode) -{ - auto cmd = std::make_shared(exitCode); - mCommands.append(cmd); -} - -void RClient::addLog(LogLevel level) -{ - mCommands.append(std::make_shared(level)); -} - -void RClient::addCompile(String &&args, const Path &cwd) -{ - mCommands.append(std::make_shared(std::move(args), cwd)); -} - -void RClient::addCompile(Path &&path) -{ - mCommands.append(std::make_shared(std::move(path))); -} - -void RClient::exec() -{ - RTags::initMessages(); - OnDestruction onDestruction([]() { Message::cleanup(); }); - EventLoop::SharedPtr loop(new EventLoop); - loop->init(EventLoop::MainEventLoop); - - const int commandCount = mCommands.size(); - std::shared_ptr connection = Connection::create(NumOptions); - connection->newMessage().connect(std::bind(&RClient::onNewMessage, this, - std::placeholders::_1, std::placeholders::_2)); - connection->finished().connect(std::bind([](){ EventLoop::eventLoop()->quit(); })); - connection->disconnected().connect(std::bind([](){ EventLoop::eventLoop()->quit(); })); - if (mTcpPort) { - if (!connection->connectTcp(mTcpHost, mTcpPort, mConnectTimeout)) { - if (mLogLevel >= LogLevel::Error) - fprintf(stdout, "Can't seem to connect to server (%s:%d)\n", mTcpHost.constData(), mTcpPort); - mExitCode = RTags::ConnectionFailure; - return; - } - connection->connected().connect(std::bind(&EventLoop::quit, loop.get())); - loop->exec(mConnectTimeout); - if (!connection->isConnected()) { - if (mLogLevel >= LogLevel::Error) { - if (mTcpPort) { - fprintf(stdout, "Can't seem to connect to server (%s:%d)\n", mTcpHost.constData(), mTcpPort); - } else { - fprintf(stdout, "Can't seem to connect to server (%s)\n", mSocketFile.constData()); - } - } - mExitCode = RTags::ConnectionFailure; - return; - } - } else if (!connection->connectUnix(mSocketFile, mConnectTimeout)) { - if (mLogLevel >= LogLevel::Error) - fprintf(stdout, "Can't seem to connect to server (%s)\n", mSocketFile.constData()); - mExitCode = RTags::ConnectionFailure; - return; - } - - for (int i=0; i &cmd = mCommands.at(i); - debug() << "running command " << cmd->description(); - mExitCode = cmd->exec(this, connection); - if (mExitCode != RTags::Success) { - break; - } else if (loop->exec(timeout()) != EventLoop::Success) { - mExitCode = RTags::TimeoutFailure; - break; - } - mExitCode = connection->finishStatus(); - } - if (connection->client()) - connection->client()->close(); - mCommands.clear(); -} - -CommandLineParser::ParseStatus RClient::parse(size_t argc, char **argv) -{ - Rct::findExecutablePath(*argv); - const char * runtimeDir = getenv("XDG_RUNTIME_DIR"); - if (runtimeDir == NULL) { - mSocketFile = Path::home() + ".rdm"; - } else { - mSocketFile = runtimeDir; - mSocketFile += "/rdm.socket"; - } - - List > projectCommands; - - Path logFile; - Flags logFlags = LogStderr; - - if (!isatty(STDOUT_FILENO)) { - mQueryFlags |= QueryMessage::NoColor; - } - - - std::function &args)> cb; - cb = [this, &projectCommands, &logFile](RClient::OptionType type, String &&value, size_t &idx, const List &arguments) -> CommandLineParser::ParseStatus { - switch (type) { - case None: - case NumOptions: { - assert(0); - break; } - case Noop: { - break; } - case NoRealPath: { - Path::setRealPathEnabled(false); - break; } - case Help: { - CommandLineParser::help(stdout, "rc", opts); - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok } ; } - case Man: { - CommandLineParser::man(opts); - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok }; } - case SocketFile: { - mSocketFile = std::move(value); - mSocketFile.resolve(); - break; } - case SocketAddress: { - mTcpHost = std::move(value); - const int colon = mTcpHost.lastIndexOf(':'); - if (colon == -1) { - return { String::format<1024>("invalid --socket-address %s\n", mTcpHost.constData()), CommandLineParser::Parse_Error }; - } - mTcpPort = atoi(mTcpHost.constData() + colon + 1); - if (!mTcpPort) { - return { String::format<1024>("invalid --socket-address %s", mTcpHost.constData()), CommandLineParser::Parse_Error }; - } - mTcpHost.truncate(colon); - break; } - case GuessFlags: { - mGuessFlags = true; - break; } - case Wait: { - mQueryFlags |= QueryMessage::Wait; - break; } - case NoSpellCheckinging: { - mQueryFlags |= QueryMessage::NoSpellChecking; - break; } - case CodeCompleteIncludeMacros: { - mQueryFlags |= QueryMessage::CodeCompleteIncludeMacros; - break; } - case CodeCompletePrefix: { - mCodeCompletePrefix = std::move(value); - break; } - case CodeCompleteIncludes: { - mQueryFlags |= QueryMessage::CodeCompleteIncludes; - break; } - case CodeCompleteNoWait: { - mQueryFlags |= QueryMessage::CodeCompleteNoWait; - break; } - case CodeCompletionEnabled: { - mQueryFlags |= QueryMessage::CodeCompletionEnabled; - break; } - case CompilationFlagsOnly: { - mQueryFlags |= QueryMessage::CompilationFlagsOnly; - break; } - case CompilationFlagsPwd: { - mQueryFlags |= QueryMessage::CompilationFlagsPwd; - break; } - case CompilationFlagsSplitLine: { - mQueryFlags |= QueryMessage::CompilationFlagsSplitLine; - break; } - case ContainingFunction: { - mQueryFlags |= QueryMessage::ContainingFunction; - break; } - case ContainingFunctionLocation: { - mQueryFlags |= QueryMessage::ContainingFunctionLocation; - break; } - case DeclarationOnly: { - mQueryFlags |= QueryMessage::DeclarationOnly; - break; } - case DefinitionOnly: { - mQueryFlags |= QueryMessage::DefinitionOnly; - break; } - case FindVirtuals: { - mQueryFlags |= QueryMessage::FindVirtuals; - break; } - case FindFilePreferExact: { - mQueryFlags |= QueryMessage::FindFilePreferExact; - break; } - case SymbolInfoIncludeParents: { - mQueryFlags |= QueryMessage::SymbolInfoIncludeParents; - break; } - case SymbolInfoIncludeTargets: { - mQueryFlags |= QueryMessage::SymbolInfoIncludeTargets; - break; } - case SymbolInfoIncludeReferences: { - mQueryFlags |= QueryMessage::SymbolInfoIncludeReferences; - break; } - case SymbolInfoIncludeBaseClasses: { - mQueryFlags |= QueryMessage::SymbolInfoIncludeBaseClasses; - break; } - case CursorKind: { - mQueryFlags |= QueryMessage::CursorKind; - break; } - case SynchronousCompletions: { - mQueryFlags |= QueryMessage::SynchronousCompletions; - break; } - case SynchronousDiagnostics: { - mQueryFlags |= QueryMessage::SynchronousDiagnostics; - break; } - case DisplayName: { - mQueryFlags |= QueryMessage::DisplayName; - break; } - case AllReferences: { - mQueryFlags |= QueryMessage::AllReferences; - break; } - case AllTargets: { - mQueryFlags |= QueryMessage::AllTargets; - break; } - case TargetUsrs: { - mQueryFlags |= QueryMessage::TargetUsrs; - break; } - case MatchCaseInsensitive: { - mQueryFlags |= QueryMessage::MatchCaseInsensitive; - break; } - case MatchRegex: { - mQueryFlags |= QueryMessage::MatchRegex; - break; } - case AbsolutePath: { - mQueryFlags |= QueryMessage::AbsolutePath; - break; } - case ReverseSort: { - mQueryFlags |= QueryMessage::ReverseSort; - break; } - case Rename: { - mQueryFlags |= QueryMessage::Rename; - break; } - case Elisp: { - mQueryFlags |= QueryMessage::Elisp; - break; } - case JSON: { - mQueryFlags |= QueryMessage::JSON; - break; } - case XML: { - mQueryFlags |= QueryMessage::XML; - break; } - case FilterSystemHeaders: { - mQueryFlags |= QueryMessage::FilterSystemIncludes; - break; } - case NoColor: { - mQueryFlags |= QueryMessage::NoColor; - break; } - case NoContext: { - mQueryFlags |= QueryMessage::NoContext; - break; } - case PathFilter: { - mPathFilters.insert({ Path::resolved(value), QueryMessage::PathFilter::Self }); - break; } - case DependencyFilter: { - Path p = std::move(value); - if (!p.isFile()) { - return { String::format<1024>("%s doesn't seem to be a file", p.constData()), CommandLineParser::Parse_Error }; - } - mPathFilters.insert({ Path::resolved(p), QueryMessage::PathFilter::Dependency }); - break; } - case KindFilter: { - mKindFilters.insert(value); - break; } - case WildcardSymbolNames: { - mQueryFlags |= QueryMessage::WildcardSymbolNames; - break; } - case RangeFilter: { - char *end; - mMinOffset = strtoul(value.constData(), &end, 10); - if (*end != '-') { - return { String::format<1024>("Can't parse range, must be uint-uint. E.g. 1-123"), CommandLineParser::Parse_Error }; - } - mMaxOffset = strtoul(end + 1, &end, 10); - if (*end) { - return { String::format<1024>("Can't parse range, must be uint-uint. E.g. 1-123"), CommandLineParser::Parse_Error }; - } - if (mMaxOffset <= mMinOffset || mMinOffset < 0) { - return { String::format<1024>("Invalid range (%d-%d), must be uint-uint. E.g. 1-123", mMinOffset, mMaxOffset), - CommandLineParser::Parse_Error }; - } - break; } - case Validate: { - addQuery(QueryMessage::Validate); - break; } - case Version: { - fprintf(stdout, "%s\n", RTags::versionString().constData()); - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok }; } - case VerifyVersion: { - const int version = strtoul(value.constData(), 0, 10); - if (version != NumOptions) { - fprintf(stdout, "Protocol version mismatch\n"); - mExitCode = RTags::ProtocolFailure; - return { String(), CommandLineParser::Parse_Error }; - } - break; } - case Verbose: { - ++mLogLevel; - break; } - case CodeCompleteAt: { - String encoded = Location::encode(value); - if (encoded.isEmpty()) { - return { String::format<1024>("Can't resolve argument %s", value.constData()), CommandLineParser::Parse_Error }; - } - - addQuery(QueryMessage::CodeCompleteAt, std::move(encoded)); - break; } - case Silent: { - mLogLevel = LogLevel::None; - break; } - case LogFile: { - logFile = std::move(value); - break; } - case StripParen: { - mQueryFlags |= QueryMessage::StripParentheses; - break; } - case DumpIncludeHeaders: { - mQueryFlags |= QueryMessage::DumpIncludeHeaders; - break; } - case SilentQuery: { - mQueryFlags |= QueryMessage::SilentQuery; - break; } - case BuildIndex: { - bool ok; - mBuildIndex = String(value).toULongLong(&ok); - if (!ok) { - return { String::format<1024>("--build-index [arg] must be >= 0"), CommandLineParser::Parse_Error }; - } - break; } - case ConnectTimeout: { - mConnectTimeout = atoi(value.constData()); - if (mConnectTimeout < 0) { - return { String::format<1024>("--connect-timeout [arg] must be >= 0"), CommandLineParser::Parse_Error }; - } - break; } - case Max: { - bool ok; - mMax = value.toULongLong(&ok); - if (!ok) { - return { String::format<1024>("-M [arg] must be >= 0"), CommandLineParser::Parse_Error }; - } - break; } - case Timeout: { - mTimeout = atoi(value.constData()); - if (!mTimeout) { - mTimeout = -1; - } else if (mTimeout < 0) { - return { String::format<1024>("-y [arg] must be >= 0"), CommandLineParser::Parse_Error }; - } - break; } - case UnsavedFile: { - const int colon = value.lastIndexOf(':'); - if (colon == -1) { - return { String::format<1024>("Can't parse -u [%s]", value.constData()), CommandLineParser::Parse_Error }; - } - const int bytes = atoi(value.constData() + colon + 1); - if (!bytes) { - return { String::format<1024>("Can't parse -u [%s]", value.constData()), CommandLineParser::Parse_Error }; - } - const Path path = value.left(colon); - if (!path.isFile()) { - return { String::format<1024>("Can't open [%s] for reading", path.nullTerminated()), CommandLineParser::Parse_Error }; - } - - String contents(bytes, '\0'); - const int r = fread(contents.data(), 1, bytes, stdin); - if (r != bytes) { - return { String::format<1024>("Read error %d (%s). Got %d, expected %d", errno, Rct::strerror(errno).constData(), r, bytes), CommandLineParser::Parse_Error }; - } - mUnsavedFiles[path] = contents; - break; } - case FollowLocation: - case ClassHierarchy: - case ReferenceLocation: { - String encoded = Location::encode(value); - if (encoded.isEmpty()) { - return { String::format<1024>("Can't resolve argument %s", value.constData()), CommandLineParser::Parse_Error }; - } - QueryMessage::Type queryType = QueryMessage::Invalid; - switch (type) { - case FollowLocation: - queryType = QueryMessage::FollowLocation; - break; - case ReferenceLocation: - queryType = QueryMessage::ReferencesLocation; - break; - case ClassHierarchy: - queryType = QueryMessage::ClassHierarchy; - break; - default: - assert(0); - break; - } - addQuery(queryType, std::move(encoded), QueryMessage::HasLocation); - break; } - case SymbolInfo: { - std::cmatch match; - std::regex rx("^(.*):([0-9]+):([0-9]+):?-:?([0-9]+):([0-9]+):?(@[A-Za-z,]+)?", std::regex_constants::extended); - Path path; - List kinds; - uint32_t line = 0, col = 0, line2 = 0, col2 = 0; - if (std::regex_match(value.constData(), match, rx)) { - path.assign(value.constData(), match.length(1)); - line = atoi(value.constData() + match.position(2)); - col = atoi(value.constData() + match.position(3)); - line2 = atoi(value.constData() + match.position(4)); - col2 = atoi(value.constData() + match.position(5)); - if (match.length(6) > 1) - kinds = String(value.constData() + match.position(6) + 1, match.length(6) - 1).split(","); - if (!line || !col || !line2 || !col2 || !path.resolve(Path::MakeAbsolute)) { - return { String::format<1024>("Can't parse range %s", value.constData()), CommandLineParser::Parse_Error }; - } - } else { - std::regex rx2("^(.*):([0-9]+):([0-9]+):?(@[A-Za-z,]+)?", std::regex_constants::basic); - if (std::regex_match(value.constData(), match, rx2)) { - path.assign(value.constData(), match.length(1)); - line = atoi(value.constData() + match.position(2)); - col = atoi(value.constData() + match.position(3)); - if (match.length(4) > 1) - kinds = String(value.constData() + match.position(4) + 1, match.length(4) - 1).split(","); - if (!line || !col || !path.resolve(Path::MakeAbsolute)) { - return { String::format<1024>("Can't parse range %s", value.constData()), CommandLineParser::Parse_Error }; - } - } else if (!Location::parse(value, Path(), Path::MakeAbsolute, &path, &line, &col)) { - return { String::format<1024>("Can't parse range %s", value.constData()), CommandLineParser::Parse_Error }; - } - } - for (String &k : kinds) { - k.lowerCase(); - } - String query; - Serializer serializer(query); - serializer << path << line << col << line2 << col2 << kinds; - addQuery(QueryMessage::SymbolInfo, std::move(query)); - break; } - case CurrentFile: { - mCurrentFile = Path(value).resolved(); - break; } - case ReloadFileManager: { - addQuery(QueryMessage::ReloadFileManager); - break; } - case DumpCompletions: { - addQuery(QueryMessage::DumpCompletions); - break; - case DumpCompileCommands: - addQuery(QueryMessage::DumpCompileCommands); - break; - case Clear: - addQuery(QueryMessage::ClearProjects); - break; } - case RdmLog: { - addLog(RdmLogCommand::Default); - break; } - case Diagnostics: { - addLog(RTags::DiagnosticsLevel); - break; } - case QuitRdm: { - String arg; - if (!value.isEmpty()) { - arg = std::move(value); - } else if (idx < arguments.size() && arguments[idx][0] != '-') { - arg = arguments[idx++]; - } - int exit = 0; - if (!arg.isEmpty()) { - bool ok; - exit = String(arg).toLongLong(&ok); - if (!ok) { - return { String::format<1024>("Invalid argument to -q"), CommandLineParser::Parse_Error }; - } - } - addQuitCommand(exit); - break; } - case DeleteProject: { - addQuery(QueryMessage::DeleteProject, std::move(value)); - break; } - case DebugLocations: { - String arg; - if (!value.isEmpty()) { - arg = std::move(value); - } else if (idx < arguments.size() && arguments[idx][0] != '-') { - arg = arguments[idx++]; - } - addQuery(QueryMessage::DebugLocations, std::move(arg)); - break; } - case SendDiagnostics: { - addQuery(QueryMessage::SendDiagnostics, std::move(value)); - break; } - case FindProjectRoot: { - const Path p = Path::resolved(value); // this won't work correctly with --no-realpath unless --no-realpath is passed first - printf("findProjectRoot [%s] => [%s]\n", p.constData(), RTags::findProjectRoot(p, RTags::SourceRoot).constData()); - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok }; } - case FindProjectBuildRoot: { - const Path p = Path::resolved(value); // this won't work correctly with --no-realpath unless --no-realpath is passed first - printf("findProjectRoot [%s] => [%s]\n", p.constData(), RTags::findProjectRoot(p, RTags::BuildRoot).constData()); - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok }; } - case RTagsConfig: { - const Path p = Path::resolved(value); // this won't work correctly with --no-realpath unless --no-realpath is passed first - Map config = RTags::rtagsConfig(p); - printf("rtags-config: %s:\n", p.constData()); - for (const auto &it : config) { - printf("%s: \"%s\"\n", it.first.constData(), it.second.constData()); - } - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok }; } - case CurrentProject: { - addQuery(QueryMessage::Project, String(), QueryMessage::CurrentProjectOnly); - break; } - case CheckReindex: - case Reindex: - case Project: - case FindFile: - case ListSymbols: - case FindSymbols: - case Sources: - case IncludeFile: - case JobCount: - case Status: { - Flags extraQueryFlags; - QueryMessage::Type queryType = QueryMessage::Invalid; - bool resolve = true; - switch (type) { - case CheckReindex: - queryType = QueryMessage::CheckReindex; - break; - case Reindex: - queryType = QueryMessage::Reindex; - break; - case Project: - queryType = QueryMessage::Project; - break; - case FindFile: - queryType = QueryMessage::FindFile; - resolve = false; - break; - case Sources: - queryType = QueryMessage::Sources; - break; - case IncludeFile: - queryType = QueryMessage::IncludeFile; - resolve = false; - break; - case Status: - queryType = QueryMessage::Status; - break; - case ListSymbols: - queryType = QueryMessage::ListSymbols; - break; - case FindSymbols: - queryType = QueryMessage::FindSymbols; - break; - case JobCount: - queryType = QueryMessage::JobCount; - break; - default: - assert(0); - break; - } - - String arg; - if (!value.isEmpty()) { - arg = std::move(value); - } else if (idx < arguments.size() && arguments[idx][0] != '-') { - arg = arguments[idx++]; - } - if (!arg.isEmpty()) { - Path p(arg); - if (resolve && p.exists()) { - p.resolve(); - addQuery(queryType, std::move(p), extraQueryFlags); - } else { - addQuery(queryType, std::move(arg), extraQueryFlags); - } - } else { - addQuery(queryType, String(), extraQueryFlags); - } - assert(!mCommands.isEmpty()); - if (queryType == QueryMessage::Project) - projectCommands.append(std::static_pointer_cast(mCommands.back())); - break; } - case ListBuffers: { - addQuery(QueryMessage::SetBuffers); - break; } - case ListCursorKinds: { - auto print = [](CXCursorKind from, CXCursorKind to) { - for (int i = from; i <= to; ++i) { - const CXCursorKind kind = static_cast(i); - String spelling = RTags::eatString(clang_getCursorKindSpelling(kind)); - spelling.remove(' '); - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << spelling; - } - }; - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << "Declarations:"; - print(CXCursor_FirstDecl, CXCursor_LastDecl); - print(CXCursor_FirstExtraDecl, CXCursor_LastExtraDecl); - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << "References:"; - print(CXCursor_FirstRef, CXCursor_LastRef); - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << "Expressions:"; - print(CXCursor_FirstExpr, CXCursor_LastExpr); - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << "Statements:"; - print(CXCursor_FirstStmt, CXCursor_LastStmt); - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << "Attributes:"; - print(CXCursor_FirstAttr, CXCursor_LastAttr); - Log(LogLevel::Error, LogOutput::StdOut | LogOutput::TrailingNewLine) << "Preprocessing:"; - print(CXCursor_FirstPreprocessing, CXCursor_LastPreprocessing); - mExitCode = RTags::Success; - return { String(), CommandLineParser::Parse_Ok }; } - case SetBuffers: - case AddBuffers: - case RemoveBuffers: { - String arg; - if (!value.isEmpty()) { - arg = std::move(value); - } else if (idx < arguments.size() && (arguments[idx][0] != '-' || arguments[idx] == "-")) { - arg = arguments[idx++]; - } - String encoded; - if (!arg.isEmpty()) { - List paths; - auto addBuffer = [&paths](const String &p) { - if (p.isEmpty()) - return; - Path path(p); - if (path.resolve() && path.isFile()) { - paths.append(path); - } else { - fprintf(stderr, "\"%s\" doesn't seem to be a file.\n", p.constData()); - } - }; - - if (arg == "-") { - char buf[1024]; - while (fgets(buf, sizeof(buf), stdin)) { - String a(buf); - if (a.endsWith('\n')) - a.chop(1); - addBuffer(a); - } - } else { - for (const String &buffer : arg.split(';')) { - addBuffer(buffer); - } - } - Serializer serializer(encoded); - switch (type) { - case AddBuffers: serializer << 1; break; - case SetBuffers: serializer << 0; break; - case RemoveBuffers: serializer << -1; break; - default: assert(0); break; - } - serializer << paths; - } - addQuery(QueryMessage::SetBuffers, std::move(encoded)); - break; } - case LoadCompileCommands: { - Path path; - if (!value.isEmpty()) { - path = std::move(value); - } else if (idx < arguments.size() && arguments[idx][0] != '-') { - path = arguments[idx++]; - } else { - path = Path::pwd(); - } - path.resolve(Path::MakeAbsolute); - if (!path.exists()) { - return { String::format<1024>("%s does not seem to exist", path.constData()), CommandLineParser::Parse_Error }; - } else if (path.isDir()) { - path = path.ensureTrailingSlash() + "compile_commands.json"; - } else if (!path.endsWith("/compile_commands.json")) { - return { "The file has to be called compile_commands.json", CommandLineParser::Parse_Error }; - } - if (!path.exists()) { - return { String::format<1024>("no compile_commands.json file in %s", path.constData()), CommandLineParser::Parse_Error }; - } - - addCompile(std::move(path)); - break; } - case HasFileManager: { - Path p; - if (!value.isEmpty()) { - p = std::move(value); - } else if (idx < arguments.size() && arguments[idx][0] != '-') { - p = arguments[idx++]; - } else { - p = "."; - } - p.resolve(Path::MakeAbsolute); - if (!p.exists()) { - return { String::format<1024>("%s does not seem to exist", p.constData()), CommandLineParser::Parse_Error }; - } - if (p.isDir() && !p.endsWith('/')) - p.append('/'); - addQuery(QueryMessage::HasFileManager, std::move(p)); - break; } - case ProjectRoot: { - Path p = std::move(value); - if (!p.isDir()) { - return { String::format<1024>("%s does not seem to be a directory", p.constData()), CommandLineParser::Parse_Error }; - } - - p.resolve(Path::MakeAbsolute); - mProjectRoot = p.ensureTrailingSlash(); - break; } - case Suspend: { - Path p; - if (!value.isEmpty()) { - p = std::move(value); - } else if (idx < arguments.size() && arguments[idx][0] != '-') { - p = arguments[idx++]; - } - String change; - if (!p.isEmpty() && p != "clear" && p != "all") { - p.resolve(Path::MakeAbsolute); - if (!p.isFile()) { - return { String::format<1024>("%s is not a file", p.constData()), CommandLineParser::Parse_Error }; - } - if (idx + 1 < arguments.size()) { - if (arguments[idx + 1] == "on" || arguments[idx + 1] == "off") { - change = std::move(arguments[++idx]); - } else if (arguments[idx + 1] == "toggle") { - ++idx; - } - } - } - String data; - Serializer serializer(data); - serializer << p << change; - addQuery(QueryMessage::Suspend, std::move(data)); - break; } - case Compile: { - auto quote = [](const String &str) -> String { - if (str.contains(' ')) { - String ret = str; - ret.replace("\"", "\\\""); - ret.insert(0, "\""); - ret.append("\""); - return ret; - } - return str; - }; - String args; - if (idx + 1 < arguments.size()) { - args = quote(std::move(value)); - while (++idx < arguments.size()) { - if (!args.isEmpty()) - args.append(' '); - args.append(quote(arguments[idx])); - } - } else { - args = std::move(value); - } - if (args == "-" || args.isEmpty()) { - String pending; - char buf[16384]; - while (fgets(buf, sizeof(buf), stdin)) { - pending += buf; - if (!pending.endsWith("\\\n")) { - addCompile(std::move(pending), Path::pwd()); - } else { - memset(pending.data() + pending.size() - 2, ' ', 2); - } - } - if (!pending.isEmpty()) { - addCompile(std::move(pending), Path::pwd()); - } - } else { - addCompile(std::move(args), Path::pwd()); - } - break; } - case IsIndexing: { - addQuery(QueryMessage::IsIndexing); - break; } - case LastIndexed: { - addQuery(QueryMessage::LastIndexed); - break; } - case NoSortReferencesByInput: { - mQueryFlags |= QueryMessage::NoSortReferencesByInput; - break; } - case DiagnoseAll: { - addQuery(QueryMessage::Diagnose, String()); - break; } - case IsIndexed: - case DumpFile: - case CheckIncludes: - case GenerateTest: - case Diagnose: - case FixIts: { - Path p = std::move(value); - if (!p.exists()) { - return { String::format<1024>("%s does not exist", p.constData()), CommandLineParser::Parse_Error }; - } - - if (!p.isAbsolute()) - p.prepend(Path::pwd()); - - if (p.isDir()) { - if (type != IsIndexed) { - return { String::format<1024>("%s is not a file", p.constData()), CommandLineParser::Parse_Error }; - } else if (!p.endsWith('/')) { - p.append('/'); - } - } - p.resolve(); - Flags extraQueryFlags; - QueryMessage::Type queryType = QueryMessage::Invalid; - switch (type) { - case GenerateTest: - queryType = QueryMessage::GenerateTest; - break; - case FixIts: - queryType = QueryMessage::FixIts; - break; - case DumpFile: - queryType = QueryMessage::DumpFile; - break; - case CheckIncludes: - queryType = QueryMessage::DumpFile; - extraQueryFlags |= QueryMessage::DumpCheckIncludes; - break; - case Diagnose: - queryType = QueryMessage::Diagnose; - break; - case IsIndexed: - queryType = QueryMessage::IsIndexed; - break; - default: - assert(0); - break; - } - - addQuery(queryType, std::move(p), extraQueryFlags); - break; } - case AllDependencies: { - String encoded; - List args; - while (idx < arguments.size() && arguments[idx][0] != '-') { - args.append(arguments[idx++]); - } - Serializer s(encoded); - s << Path() << args; - addQuery(QueryMessage::Dependencies, std::move(encoded)); - break; } - case DumpFileMaps: - case Dependencies: { - Path p = std::move(value); - if (!p.isFile()) { - return { String::format<1024>("%s is not a file", p.constData()), CommandLineParser::Parse_Error }; - } - p.resolve(); - List args; - while (idx + 1 < arguments.size() && arguments[idx + 1][0] != '-') { - args.append(arguments[++idx]); - } - - String encoded; - Serializer s(encoded); - s << p << args; - addQuery(type == DumpFileMaps ? QueryMessage::DumpFileMaps : QueryMessage::Dependencies, std::move(encoded)); - break; } - case Tokens: { - char path[PATH_MAX]; - uint32_t from, to; - if (sscanf(value.constData(), "%[^':']:%u-%u", path, &from, &to) != 3) { - if (sscanf(value.constData(), "%[^':']:%u-", path, &from) == 2) { - to = UINT_MAX; - } else if (sscanf(value.constData(), "%[^':']:-%u", path, &to) == 2) { - from = 0; - } else { - strncpy(path, value.constData(), value.size()); - from = 0; - to = UINT_MAX; - } - } - - const Path p = Path::resolved(path); - if (!p.isFile()) { - return { String::format<1024>("%s is not a file", value.constData()), CommandLineParser::Parse_Error }; - } - if (from >= to) { - return { String::format<1024>("Invalid range: %s", value.constData()), CommandLineParser::Parse_Error }; - } - String data; - Serializer s(data); - s << p << from << to; - addQuery(QueryMessage::Tokens, std::move(data)); - break; } - case TokensIncludeSymbols: { - mQueryFlags |= QueryMessage::TokensIncludeSymbols; - break; } - case PreprocessFile: { - Path p = std::move(value); - p.resolve(Path::MakeAbsolute); - if (!p.isFile()) { - return { String::format<1024>("%s is not a file", p.constData()), CommandLineParser::Parse_Error }; - } - addQuery(QueryMessage::PreprocessFile, std::move(p)); - break; } - case RemoveFile: { - Path p = Path::resolved(value, Path::MakeAbsolute); - if (!p.exists()) { - addQuery(QueryMessage::RemoveFile, std::move(p)); - } else { - addQuery(QueryMessage::RemoveFile, std::move(value)); - } - break; } - case ReferenceName: { - addQuery(QueryMessage::ReferencesName, std::move(value)); - break; } - case VisitAST: { -#ifdef RTAGS_HAS_LUA - Path p = std::move(value); - p.resolve(Path::MakeAbsolute); - if (!p.isFile()) { - return { String::format<1024>("%s is not a file", p.constData()), CommandLineParser::Parse_Error }; - } - addQuery(QueryMessage::VisitAST, std::move(p)); -#endif - break; } - case VisitASTScript: { -#ifdef RTAGS_HAS_LUA - String code = std::move(value); - if (code.startsWith("@")) { - const Path p = code.mid(1); - if (!p.isFile()) { - return { String::format<1024>("%s is not a file", p.constData()), CommandLineParser::Parse_Error }; - } - code = p.readAll(); - } - if (code.isEmpty()) { - return { String::format<1024>("Script is empty"), CommandLineParser::Parse_Error }; - } - mVisitASTScripts.push_back(std::move(code)); -#endif - break; } - } - return { String(), CommandLineParser::Parse_Exec }; - }; - - const std::initializer_list > configOpts = { - { CommandLineParser::Config, "config", 0, CommandLineParser::Required, "Use this file (instead of ~/.rcrc)." }, - { CommandLineParser::NoRc, "no-rc", 0, CommandLineParser::NoValue, "Don't load any rc files." } - }; - - auto ret = CommandLineParser::parse(argc, argv, opts, NullFlags, cb, "rc", configOpts, &mCommandLine); - if (ret.status == CommandLineParser::Parse_Error) { - ret.error += "\nTry 'rc --help' for more information."; - } - if (ret.status != CommandLineParser::Parse_Exec) - return ret; - - if (!initLogging(argv[0], logFlags, mLogLevel, logFile)) { - return { String::format<1024>("Can't initialize logging with %d %s %s", mLogLevel.toInt(), logFile.constData(), logFlags.toString().constData()), CommandLineParser::Parse_Error }; - } - - if (mCommands.isEmpty()) { - help(stderr, argv[0], opts); - return { "No commands", CommandLineParser::Parse_Error }; - } - if (mCommands.size() > projectCommands.size()) { - // If there's more than one command one likely does not want output from - // the queryCommand (unless there's no arg specified for it). This is so - // we don't have to pass a different flag for auto-updating project - // using the current buffer but rather piggy-back on --project - const int count = projectCommands.size(); - for (int i = 0; i < count; ++i) { - std::shared_ptr &cmd = projectCommands[i]; - if (!cmd->query.isEmpty()) { - cmd->extraQueryFlags |= QueryMessage::Silent; - } - } - } - - if (!logFile.isEmpty() || mLogLevel > LogLevel::Error) { - Log l(LogLevel::Warning); - l << argc; - for (size_t i = 0; i < argc; ++i) - l << " " << argv[i]; - } - - return { String(), CommandLineParser::Parse_Exec }; -} - -void RClient::onNewMessage(const std::shared_ptr &message, const std::shared_ptr &) -{ - if (message->messageId() == ResponseMessage::MessageId) { - const String response = std::static_pointer_cast(message)->data(); - if (!response.isEmpty() && mLogLevel >= LogLevel::Error) { - fprintf(stdout, "%s\n", response.constData()); - fflush(stdout); - } - } else { - error("Unexpected message: %d", message->messageId()); - } -} - -List RClient::environment() const -{ - if (mEnvironment.isEmpty()) { - mEnvironment = Rct::environment(); - } - return mEnvironment; -} diff --git a/rtags/src/RClient.h b/rtags/src/RClient.h deleted file mode 100644 index d0740fe..0000000 --- a/rtags/src/RClient.h +++ /dev/null @@ -1,234 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef RClient_h -#define RClient_h - -#include "QueryMessage.h" -#include "rct/List.h" -#include "rct/Message.h" -#include "rct/Path.h" -#include "rct/Set.h" -#include "rct/String.h" -#include "CommandLineParser.h" -#include "rct/rct-config.h" - -class RCCommand; -class QueryCommand; -class Connection; -class RClient -{ -public: - enum OptionType { - None = 0, - AbsolutePath, - AddBuffers, - AllDependencies, - AllReferences, - AllTargets, - BuildIndex, - CheckIncludes, - CheckReindex, - ClassHierarchy, - Clear, - CodeCompleteAt, - CodeCompleteIncludeMacros, - CodeCompleteIncludes, - CodeCompleteNoWait, - CodeCompletePrefix, - CodeCompletionEnabled, - CompilationFlagsOnly, - CompilationFlagsPwd, - CompilationFlagsSplitLine, - Compile, - ConnectTimeout, - ContainingFunction, - ContainingFunctionLocation, - CurrentFile, - CurrentProject, - CursorKind, - DebugLocations, - DeclarationOnly, - DefinitionOnly, - DeleteProject, - Dependencies, - DependencyFilter, - Diagnose, - DiagnoseAll, - Diagnostics, - DisplayName, - DumpCompileCommands, - DumpCompletions, - DumpFile, - DumpFileMaps, - DumpIncludeHeaders, - Elisp, - FilterSystemHeaders, - FindFile, - FindFilePreferExact, - FindProjectBuildRoot, - FindProjectRoot, - FindSymbols, - FindVirtuals, - FixIts, - FollowLocation, - GenerateTest, - GuessFlags, - HasFileManager, - Help, - IncludeFile, - IsIndexed, - IsIndexing, - JSON, - JobCount, - KindFilter, - LastIndexed, - ListBuffers, - ListCursorKinds, - ListSymbols, - LoadCompileCommands, - LogFile, - Man, - MatchCaseInsensitive, - MatchRegex, - Max, - NoColor, - NoContext, - NoRealPath, - NoSortReferencesByInput, - NoSpellCheckinging, - Noop, - PathFilter, - PreprocessFile, - Project, - ProjectRoot, - QuitRdm, - RTagsConfig, - RangeFilter, - RdmLog, - ReferenceLocation, - ReferenceName, - Reindex, - ReloadFileManager, - RemoveBuffers, - RemoveFile, - Rename, - ReverseSort, - SendDiagnostics, - SetBuffers, - Silent, - SilentQuery, - SocketAddress, - SocketFile, - Sources, - Status, - StripParen, - Suspend, - SymbolInfo, - SymbolInfoIncludeBaseClasses, - SymbolInfoIncludeParents, - SymbolInfoIncludeReferences, - SymbolInfoIncludeTargets, - SynchronousCompletions, - SynchronousDiagnostics, - TargetUsrs, - Timeout, - Tokens, - TokensIncludeSymbols, - UnsavedFile, - Validate, - Verbose, - VerifyVersion, - Version, - VisitAST, - VisitASTScript, - Wait, - WildcardSymbolNames, - XML, - NumOptions - }; - - RClient(); - ~RClient(); - void exec(); - int exitCode() const { return mExitCode; } - CommandLineParser::ParseStatus parse(size_t argc, char **argv); - - int max() const { return mMax; } - LogLevel logLevel() const { return mLogLevel; } - int timeout() const { return mTimeout; } - int buildIndex() const { return mBuildIndex; } - - const Set &pathFilters() const { return mPathFilters; } - int minOffset() const { return mMinOffset; } - int maxOffset() const { return mMaxOffset; } - - const QueryMessage::KindFilters &kindFilters() const { return mKindFilters; } - - const UnsavedFiles &unsavedFiles() const { return mUnsavedFiles; } - - const List &rdmArgs() const { return mRdmArgs; } - const Path ¤tFile() const { return mCurrentFile; } - - String socketFile() const { return mSocketFile; } - String tcpHost() const { return mTcpHost; } - uint16_t tcpPort() const { return mTcpPort; } - Path projectRoot() const { return mProjectRoot; } - Flags queryFlags() const { return mQueryFlags; } - int terminalWidth() const { return mTerminalWidth; } - - String commandLine() const { return mCommandLine; } - void onNewMessage(const std::shared_ptr &message, const std::shared_ptr &); - List environment() const; - String codeCompletePrefix() const { return mCodeCompletePrefix; } -#ifdef RTAGS_HAS_LUA - List visitASTScripts() const { return mVisitASTScripts; } -#endif -private: - void addQuery(QueryMessage::Type t, String &&query = String(), - Flags extraQueryFlags = Flags()); - void addQuitCommand(int exitCode); - - void addLog(LogLevel level); - void addCompile(String &&args, const Path &cwd); - void addCompile(Path &&compileCommands); - - Flags mQueryFlags; - int mMax, mTimeout, mMinOffset, mMaxOffset, mConnectTimeout, mBuildIndex; - LogLevel mLogLevel; - Set mPathFilters; - QueryMessage::KindFilters mKindFilters; - UnsavedFiles mUnsavedFiles; - List > mCommands; - List mRdmArgs; - Path mSocketFile; - Path mCurrentFile; - String mTcpHost; - String mCodeCompletePrefix; - uint16_t mTcpPort; - bool mGuessFlags; - Path mProjectRoot; - int mTerminalWidth; - int mExitCode; -#ifdef RTAGS_HAS_LUA - List mVisitASTScripts; -#endif - mutable List mEnvironment; - - String mCommandLine; - friend class CompileCommand; -}; - -#endif diff --git a/rtags/src/RTags.cpp b/rtags/src/RTags.cpp deleted file mode 100644 index 0aca0bc..0000000 --- a/rtags/src/RTags.cpp +++ /dev/null @@ -1,1278 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "RTags.h" - -#include -#include -#include -#include -#ifdef OS_FreeBSD -#include -#endif -#ifdef OS_Darwin -#include -#endif - -#include "IndexDataMessage.h" -#include "LogOutputMessage.h" -#include "QueryMessage.h" -#include "rct/Rct.h" -#include "rct/Connection.h" -#include "rct/StopWatch.h" -#include "Server.h" -#include "ClangIndexer.h" -#include "Project.h" -#include "VisitFileMessage.h" -#include "VisitFileResponseMessage.h" -#include "RTagsVersion.h" -#include - -namespace RTags { -String versionString() -{ - return String::format<64>("%d.%d.%d", MajorVersion, MinorVersion, DatabaseVersion); -} - -String encodeUrlComponent(const String &str) -{ - String new_str = ""; - char c; - int ic; - const char* chars = str.c_str(); - char bufHex[10]; - const size_t len = str.size(); - - for(size_t i=0; i(ii); - ret += ch; - i = i + 2; - } - } - return ret; -} - -void encodePath(Path &path) -{ - if (Sandbox::encode(path)) - return; - - path = encodeUrlComponent(path); -} - -void decodePath(Path &path) -{ - if (Sandbox::decode(path)) - return; - - path = decodeUrlComponent(path); -} - -Path encodeSourceFilePath(const Path &dataDir, const Path &project, uint32_t fileId) -{ - String str = dataDir; - Path p = project; - encodePath(p); - str << p << '/'; - if (fileId) - str << fileId << '/'; - return str; -} - -Path findAncestor(const Path& path, const String &fn, Flags flags, SourceCache *cache) -{ - Path *cacheResult = 0; - if (cache) { - const Path parent = path.parentDir(); - cacheResult = &cache->ancestorCache[parent][SourceCache::AncestorCacheKey { fn, flags }]; - if (!cacheResult->isEmpty()) { - return *cacheResult; - } - } - Path ret; - char buf[PATH_MAX + sizeof(dirent) + 1]; - int slash = path.size(); - const int len = fn.size() + 1; - struct stat st; - - memcpy(buf, path.constData(), path.size() + 1); - while ((slash = path.lastIndexOf('/', slash - 1)) > 0) { // We don't want to search in / - if (!(flags & Wildcard)) { - memcpy(buf + slash + 1, fn.constData(), len); - if (!stat(buf, &st)) { - buf[slash + 1] = '\0'; - ret = buf; - if (flags & Shallow) { - break; - } - } - } else { - buf[slash + 1] = '\0'; - DIR *dir = opendir(buf); - bool found = false; - if (dir) { - while (dirent *entry = readdir(dir)) { - const int l = strlen(entry->d_name) + 1; - switch (l - 1) { - case 1: - if (entry->d_name[0] == '.') - continue; - break; - case 2: - if (entry->d_name[0] == '.' && entry->d_name[1] == '.') - continue; - break; - } - assert(buf[slash] == '/'); - assert(l + slash + 1 < static_cast(sizeof(buf))); - memcpy(buf + slash + 1, entry->d_name, l); - if (!fnmatch(fn.constData(), buf, 0)) { - ret = buf; - ret.truncate(slash + 1); - found = true; - break; - } - } - closedir(dir); - } - if (found && flags & Shallow) - break; - } - } - - ret = ret.ensureTrailingSlash(); - if (cacheResult) { - *cacheResult = ret; - } - return ret; -} - -Map rtagsConfig(const Path &path, SourceCache *cache) -{ - Path dir = path.isDir() ? path : path.parentDir(); - Map ret; - char buf[1024]; - while (dir.size() > 1) { - assert(dir.endsWith('/')); - if (cache) { - auto it = cache->rtagsConfigCache.find(dir); - if (it != cache->rtagsConfigCache.end()) { - for (const auto &entry : it->second) { - auto &ref = ret[entry.first]; - if (ref.isEmpty()) - ref = entry.second; - } - dir = dir.parentDir(); - continue; - } - } - Map *cacheEntry = 0; - if (cache) { - cacheEntry = &cache->rtagsConfigCache[dir]; - // we want to cache empty entries - } - snprintf(buf, sizeof(buf), "%s.rtags-config", dir.constData()); - if (FILE *f = fopen(buf, "r")) { - while ((fgets(buf, sizeof(buf), f))) { - int len = strlen(buf); - while (len > 0 && isspace(buf[len - 1])) - --len; - if (len) { - buf[len] = '\0'; - String key; - char *colon = strchr(buf, ':'); - char *value = 0; - if (colon) { - key.assign(buf, colon - buf); - value = colon + 1; - while (isspace(*value)) - ++value; - } else { - key.assign(buf, len); - } - if (!key.isEmpty()) { - if (!ret.contains(key)) - ret[key] = value; - if (cacheEntry) - (*cacheEntry)[key] = value; - } - } - } - fclose(f); - } - dir = dir.parentDir(); - } - return ret; -} - -struct Entry { - const char *name; - const Flags flags; -}; - -static inline Path checkEntries(const Entry *entries, const Path &path, const Path &home, SourceCache *cache) -{ - Path best; - for (int i=0; entries[i].name; ++i) { - Path p = findAncestor(path, entries[i].name, entries[i].flags, cache); - if ((p.isEmpty() || p == home) && (entries[i].flags & Wildcard)) { - const int len = strlen(entries[i].name); - if (entries[i].name[len - 1] == '*') { - const String name(entries[i].name, len - 1); - p = findAncestor(path, name.constData(), entries[i].flags & ~Wildcard, cache); - } - } - if (p.isEmpty() || p == home) - continue; - if (entries[i].flags & Authoritative) { - best = p; - break; - } else if (best.isEmpty() || p.size() < best.size()) { - best = p; - } - } - return best; -} - - -Path findProjectRoot(const Path &path, ProjectRootMode mode, SourceCache *cache) -{ - if (path == "-") - return Path(); - if (!path.isAbsolute()) - error() << "GOT BAD PATH" << path; - assert(path.isAbsolute()); - const Map config = rtagsConfig(path, cache); - { - const Path project = config.value("project"); - if (!project.isEmpty() && project.isDir()) - return project.ensureTrailingSlash(); - } - - Path ret; - static const Path home = Path::home(); - if (mode == SourceRoot) { - const Entry before[] = { - { ".projectile", Authoritative }, - { ".git", Flags() }, - { ".hg", Flags() }, - { ".svn", Flags() }, - { ".fslckout", Flags() }, - { "_FOSSIL_", Flags() }, - { "_darcs_", Flags() }, - { ".bzr", Flags() }, - { ".tup", Flags() }, - { "GTAGS", Flags() }, - { "TAGS", Flags() }, - { "configure", Flags() }, - { "CMakeLists.txt", Flags() }, - { "*.pro", Wildcard }, - { "scons.1", Flags() }, - { "*.scons", Wildcard }, - { "SConstruct", Flags() }, - { "autogen.*", Wildcard }, - { "GNUMakefile*", Wildcard }, - { "INSTALL*", Wildcard }, - { "README*", Wildcard }, - { 0, Flags() } - }; - { - const Path e = checkEntries(before, path, home, cache); - if (!e.isEmpty() && (e.size() < ret.size() || ret.isEmpty())) - ret = e; - } - } - if (!ret.isEmpty()) - return ret; - { - const Path configStatus = findAncestor(path, "config.status", Flags(), cache); - if (!configStatus.isEmpty()) { - if (mode == BuildRoot) - return configStatus; - FILE *f = fopen((configStatus + "config.status").constData(), "r"); - if (f) { - char line[1024]; - enum { MaxLines = 10 }; - for (int i=0; i= line) { - Path conf(configure, end - configure); - if (!conf.isAbsolute()) - conf.resolve(); - if (conf.isFile()) { - ret = conf.parentDir(); - if (ret == home) - ret.clear(); - break; - } - } - } - if (!ret.isEmpty()) - break; - } - fclose(f); - if (!ret.isEmpty()) - return ret; - } - } - } - { - const Path cmakeCache = findAncestor(path, "CMakeCache.txt", Flags(), cache); - if (!cmakeCache.isEmpty()) { - if (mode == BuildRoot) - return cmakeCache; - FILE *f = fopen((cmakeCache + "Makefile").constData(), "r"); - bool makefile = true; - if (!f) { - f = fopen((cmakeCache + "build.ninja").constData(), "r"); - makefile = false; - } - if (f) { - char line[1024]; - enum { MaxLines = 256 }; - for (int i=0; i() }, - { "Makefile*", Wildcard }, - { "compile_commands.json", Flags() }, - { 0, Flags() } - }; - - { - const Path e = checkEntries(after, path, home, cache); - if (!e.isEmpty() && (e.size() < ret.size() || ret.isEmpty())) - ret = e; - } - - if (!ret.isEmpty()) - return ret; - - if (mode == BuildRoot) - return findProjectRoot(path, SourceRoot, cache); - - return Path(); -} - -void initMessages() -{ - Message::registerMessage(); - Message::registerMessage(); - Message::registerMessage(); - Message::registerMessage(); - Message::registerMessage(); - Message::registerMessage(); -} -String eatString(CXString str) -{ - const String ret(clang_getCString(str)); - clang_disposeString(str); - return ret; -} - -String cursorToString(CXCursor cursor, const Flags flags) -{ - const CXCursorKind kind = clang_getCursorKind(cursor); - String ret; - ret.reserve(256); - ret += eatString(clang_getCursorKindSpelling(kind)); - if (clang_isInvalid(kind)) - return ret; - - switch (RTags::cursorType(kind)) { - case Type_Reference: - ret += " ref"; - break; - case Type_Cursor: - ret += " cursor"; - break; - case Type_Other: - ret += " other"; - break; - case Type_Statement: - ret += " statement"; - break; - case Type_Include: - ret += " include"; - break; - case Type_Literal: - ret += " literal"; - break; - } - - const String name = eatString(clang_getCursorDisplayName(cursor)); - const String other = eatString(clang_getCursorSpelling(cursor)); - if (!name.isEmpty()) - ret += " " + name; - if (other != name && !other.isEmpty()) - ret += " " + other; - - if (clang_isCursorDefinition(cursor)) - ret += " def"; - - if (flags & IncludeUSR) { - const String usr = eatString(clang_getCursorUSR(clang_getCanonicalCursor(cursor))); - if (!usr.isEmpty()) { - ret += " " + usr; - } - } - - if (flags & IncludeSpecializedUsr) { - const CXCursor general = clang_getSpecializedCursorTemplate(cursor); - if (!clang_Cursor_isNull(general)) { - const String usr = eatString(clang_getCursorUSR(clang_getCanonicalCursor(general))); - if (!usr.isEmpty()) { - ret += " " + usr; - } - } - } - - if (flags & IncludeStructSizeof && Symbol::isClass(kind)) { - const long long size = clang_Type_getSizeOf(clang_getCursorType(cursor)); - switch (size) { - case CXTypeLayoutError_Invalid: - // ret += " (sizeof: invalid)"; - break; - case CXTypeLayoutError_Incomplete: - ret += " (sizeof: incomplete)"; - break; - case CXTypeLayoutError_Dependent: - ret += " (sizeof: dependent)"; - break; - default: - ret += String::format(" (sizeof: %lld)", size); - break; - } - } - - CXString file; - unsigned int line, col; - for (int pieceIndex = 0; true; ++pieceIndex) { - CXSourceRange range = clang_Cursor_getSpellingNameRange(cursor, pieceIndex, 0); - if (clang_Range_isNull(range)) - break; - CXSourceLocation rangeStart = clang_getRangeStart(range); - clang_getPresumedLocation(rangeStart, &file, &line, &col); - - const char *data = clang_getCString(file); - if (data && *data) { - ret += ' '; - ret += data; - ret += ':'; - ret += String::number(line); - ret += ':'; - ret += String::number(col); - } - clang_disposeString(file); - } - return ret; -} - -std::shared_ptr TranslationUnit::load(const Path &path) -{ - auto ret = std::make_shared(); - ret->index = clang_createIndex(0, false); -#if CINDEX_VERSION_MINOR >= 23 - CXErrorCode error = clang_createTranslationUnit2(ret->index, path.constData(), &ret->unit); - if (error != CXError_Success) { - ret.reset(); - ::error() << "Failed to load" << path << error << path.exists(); - } -#else - ret->unit = clang_createTranslationUnit(ret->index, path.constData()); - if (!ret->unit) { - ret.reset(); - ::error() << "Failed to load" << path << path.exists(); - } -#endif - return ret; -} - -std::shared_ptr TranslationUnit::create(const Path &sourceFile, const List &args, - CXUnsavedFile *unsaved, int unsavedCount, - Flags translationUnitFlags, - bool displayDiagnostics) - -{ - auto ret = std::make_shared(); - ret->clangLine = "clang "; - ret->index = clang_createIndex(0, displayDiagnostics); - - int idx = 0; - List clangArgs(args.size() + 2, 0); - - const int count = args.size(); - for (int j=0; jclangLine += '"' + arg + '"'; - ret->clangLine += ' '; - } - // clangArgs[idx++] = "-disable-free"; - // clangArgs[idx++] = "-disable-llvm-verifier"; - - ret->clangLine += sourceFile; - - // StopWatch sw; -#if CINDEX_VERSION_MINOR >= 23 - for (int i=0; i<3; ++i) { - auto error = clang_parseTranslationUnit2(ret->index, sourceFile.constData(), - clangArgs.data(), idx, unsaved, unsavedCount, - translationUnitFlags.cast(), &ret->unit); - if (error != CXError_Crashed) - break; - usleep(100000); - } -#else - ret->unit = clang_parseTranslationUnit(ret->index, sourceFile.constData(), - clangArgs.data(), idx, unsaved, unsavedCount, - translationUnitFlags.cast()); -#endif - // error() << sourceFile << sw.elapsed(); - return ret; -} - -bool TranslationUnit::reparse(CXUnsavedFile *unsaved, int unsavedCount) -{ - assert(unit); - const int ret = clang_reparseTranslationUnit(unit, unsavedCount, unsaved, clang_defaultReparseOptions(unit)); - if (ret) { - clang_disposeTranslationUnit(unit); - unit = 0; - return false; - } - return true; -} - -#if 1 -struct No -{ - template - No &operator<<(const T &) { return *this; } -}; -#define l() No() -#else -#define l() error() -#endif - -bool resolveAuto(const CXCursor &cursor, Auto *a) -{ - CXType type = clang_getCursorType(cursor); - while (type.kind == CXType_Pointer) - type = clang_getPointeeType(type); - - if ( -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 32) - type.kind != CXType_Auto -#else - type.kind != CXType_Unexposed || RTags::eatString(clang_getTypeSpelling(type)) != "auto" -#endif - ) { - return false; - } - - if (a) { - a->type = clang_getCanonicalType(type); - a->cursor = clang_getTypeDeclaration(a->type); - } - return true; -} - -#undef l - -static inline Diagnostic::Flag convertDiagnosticType(CXDiagnosticSeverity sev) -{ - Diagnostic::Flag type = Diagnostic::None; - switch (sev) { - case CXDiagnostic_Warning: - type = Diagnostic::Warning; - break; - case CXDiagnostic_Error: - case CXDiagnostic_Fatal: - type = Diagnostic::Error; - break; - case CXDiagnostic_Note: - type = Diagnostic::Note; - break; - default: - break; - } - return type; -} - -static inline bool compareFile(CXFile l, CXFile r) -{ - CXString fnl = clang_getFileName(l); - CXString fnr = clang_getFileName(r); - const char *cstrl = clang_getCString(fnl); - const char *cstrr = clang_getCString(fnr); - bool ret = false; - if (cstrl && cstrr && !strcmp(cstrl, cstrr)) { - ret = true; - } - - clang_disposeString(fnl); - clang_disposeString(fnr); - return ret; -} - -void DiagnosticsProvider::diagnose() -{ - const uint32_t sourceFile = sourceFileId(); - - std::function)> process; - process = [&](uint32_t u, CXDiagnostic d, Diagnostics &m, Flags flags) { - flags |= convertDiagnosticType(clang_getDiagnosticSeverity(d)); - if ((flags & Diagnostic::Type_Mask) != Diagnostic::None) { - const CXSourceLocation diagLoc = clang_getDiagnosticLocation(d); - Location location = createLocation(diagLoc, 0); - const uint32_t fileId = location.fileId(); - - int length = -1; - Map ranges; - - const unsigned int rangeCount = clang_getDiagnosticNumRanges(d); - bool first = true; - for (unsigned int rangePos = 0; rangePos < rangeCount; ++rangePos) { - const CXSourceRange range = clang_getDiagnosticRange(d, rangePos); - const CXSourceLocation start = clang_getRangeStart(range); - const CXSourceLocation end = clang_getRangeEnd(range); - - unsigned int startOffset, endOffset; - clang_getSpellingLocation(start, 0, 0, 0, &startOffset); - clang_getSpellingLocation(end, 0, 0, 0, &endOffset); - if (startOffset && endOffset) { - unsigned int line, column; - clang_getSpellingLocation(start, 0, &line, &column, 0); - const Location l(fileId, line, column); - if (first) { - first = false; - location = l; - length = endOffset - startOffset; - } else { - ranges[l] = endOffset - startOffset; - } - } - } - - String message; - if (flags & Diagnostic::DisplayCategory) - message << RTags::eatString(clang_getDiagnosticCategoryText(d)); - if (!message.isEmpty()) - message << ": "; - message << RTags::eatString(clang_getDiagnosticSpelling(d)); - - const String option = RTags::eatString(clang_getDiagnosticOption(d, 0)); - if (!option.isEmpty()) { - message << ": " << option; - } - - Diagnostic &diagnostic = m[location]; - diagnostic.flags = flags; - diagnostic.message = std::move(message); - diagnostic.ranges = std::move(ranges); - diagnostic.length = length; - diagnostic.sourceFileId = sourceFile; - - if (CXDiagnosticSet children = clang_getChildDiagnostics(d)) { - const unsigned int childCount = clang_getNumDiagnosticsInSet(children); - for (unsigned j=0; j= CINDEX_VERSION_ENCODE(0, 21) - List skipped; - if (numUnits > 1) - skipped.resize(numUnits); -#endif - - for (size_t u=0; u compilationErrors; - const size_t diagCount = diagnosticCount(u); - - for (size_t j=0; j &fileFlags = indexData.files()[fileId]; - if (fileId != sourceFile && !inclusionError && sev >= CXDiagnostic_Error && !(fileFlags & IndexDataMessage::HeaderError)) { - // We don't treat inclusions or code inside a macro expansion as a - // header error - CXFile expFile, spellingFile; - unsigned expLine, expColumn, spellingLine, spellingColumn; - clang_getExpansionLocation(diagLoc, &expFile, &expLine, &expColumn, 0); - clang_getSpellingLocation(diagLoc, &spellingFile, &spellingLine, &spellingColumn, 0); - if (expLine == spellingLine && expColumn == spellingColumn && compareFile(expFile, spellingFile)) - fileFlags |= IndexDataMessage::HeaderError; - } - bool templateOnly = false; - { - Flags f = Diagnostic::DisplayCategory; - if (!(fileFlags & IndexDataMessage::Visited)) { - templateOnly = true; - f |= Diagnostic::TemplateOnly; - } - process(u, diag, indexData.diagnostics(), f); - } - // logDirect(RTags::DiagnosticsLevel, message.constData()); - - const unsigned int fixItCount = clang_getDiagnosticNumFixIts(diag); - for (unsigned int f=0; f 1 ? "s" : ""); - } else if (endOffset == startOffset) { - error("Fixit for %s Insert \"%s\"", - loc.toString().constData(), string); - } else { - error("Fixit for %s Replace %d character%s with \"%s\"", - loc.toString().constData(), endOffset - startOffset, - endOffset - startOffset > 1 ? "s" : "", string); - } - Diagnostic &entry = indexData.diagnostics()[Location(loc.fileId(), line, column)]; - entry.flags = Diagnostic::Fixit; - if (templateOnly) - entry.flags |= Diagnostic::TemplateOnly; - entry.sourceFileId = sourceFile; - if (entry.message.isEmpty()) { - entry.message = String::format<64>("did you mean '%s'?", string); - } - entry.length = endOffset - startOffset; - indexData.fixIts()[loc.fileId()].insert(FixIt(line, column, endOffset - startOffset, string)); - } - } - clang_disposeDiagnostic(diag); - } - -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 21) - Diagnostics &diags = numUnits > 1 ? skipped[u] : indexData.diagnostics(); - for (const auto &it : indexData.files()) { - if (it.second & IndexDataMessage::Visited) { - const Location loc(it.first, 0, 0); - const Path path = loc.path(); - CXFile file = getFile(u, path.constData()); - if (file) { - CXSourceRangeList *s = clang_getSkippedRanges(unit(u), file); - if (s) { - const unsigned int count = s->count; - for (unsigned int j=0; jranges[j]); - - unsigned int line, column, startOffset, endOffset; - clang_getSpellingLocation(start, 0, &line, &column, &startOffset); - Diagnostic &entry = diags[Location(loc.fileId(), line, column)]; - entry.sourceFileId = sourceFile; - CXSourceLocation end = clang_getRangeEnd(s->ranges[j]); - clang_getSpellingLocation(end, 0, 0, 0, &endOffset); - entry.flags = Diagnostic::Skipped; - entry.length = endOffset - startOffset; - // error() << line << column << startOffset << endOffset; - } - - clang_disposeSourceRangeList(s); - } - } - } - } -#endif - } -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 21) - if (numUnits > 1) { - Diagnostics &target = indexData.diagnostics(); - for (auto it = skipped[0].begin(); it != skipped[0].end(); ++it) { - bool ok = true; - for (size_t u=1; ufirst) != it->second) { - ok = false; - break; - } - } - if (ok) { - Diagnostic &diag = target[it->first]; - if (diag.type() == Diagnostic::None) - diag = std::move(it->second); - } - } - } -#endif - - - -#if 0 - for (const auto &it : indexData.files()) { - if (it.second & IndexDataMessage::Visited) { - const Location loc(it.first, 0, 0); - const Map::const_iterator x = indexData.diagnostics().lower_bound(loc); - if (x == indexData.diagnostics().end() || x->first.fileId() != it.first) { - indexData.diagnostics()[loc] = Diagnostic(); - } - } - } -#endif -} - -Location DiagnosticsProvider::createLocation(const CXCursor &cursor, CXCursorKind kind, bool *blocked, unsigned *offset) -{ - if (kind == CXCursor_FirstInvalid) - kind = clang_getCursorKind(cursor); - CXSourceLocation location; - if (clang_isStatement(kind)) { - location = clang_getCursorLocation(cursor); - } else { - CXSourceRange range = clang_Cursor_getSpellingNameRange(cursor, 0, 0); - location = clang_getRangeStart(range); - } - if (!location) - return Location(); - return createLocation(location, blocked, offset); -} - -static CXChildVisitResult findFirstChildVisitor(CXCursor cursor, CXCursor, CXClientData data) -{ - *reinterpret_cast(data) = cursor; - return CXChildVisit_Break; -} - -CXCursor findFirstChild(CXCursor parent) -{ - CXCursor ret = clang_getNullCursor(); - if (!clang_isInvalid(clang_getCursorKind(parent))) - clang_visitChildren(parent, findFirstChildVisitor, &ret); - return ret; -} - -struct FindChildVisitor -{ - CXCursorKind kind; - String name; - CXCursor cursor; -}; - -static CXChildVisitResult findChildVisitor(CXCursor cursor, CXCursor, CXClientData data) -{ - FindChildVisitor *u = reinterpret_cast(data); - if (u->name.isEmpty()) { - if (clang_getCursorKind(cursor) == u->kind) { - u->cursor = cursor; - return CXChildVisit_Break; - } - } else { - CXStringScope str = clang_getCursorSpelling(cursor); - if (str.data() && u->name == str.data()) { - u->cursor = cursor; - return CXChildVisit_Break; - } - } - return CXChildVisit_Continue; -} - -CXCursor findChild(CXCursor parent, CXCursorKind kind) -{ - FindChildVisitor u = { kind, String(), clang_getNullCursor() }; - if (!clang_isInvalid(clang_getCursorKind(parent))) - clang_visitChildren(parent, findChildVisitor, &u); - return u.cursor; -} - -CXCursor findChild(CXCursor parent, const String &name) -{ - FindChildVisitor u = { CXCursor_FirstInvalid, name, clang_getNullCursor() }; - if (!clang_isInvalid(clang_getCursorKind(parent))) - clang_visitChildren(parent, findChildVisitor, &u); - return u.cursor; -} - -struct ChildrenVisitor -{ - const Filter ∈ - const Filter &out; - List children; -}; - -static CXChildVisitResult childrenVisitor(CXCursor cursor, CXCursor, CXClientData data) -{ - ChildrenVisitor *u = reinterpret_cast(data); - if ((u->out.isNull() || !u->out.match(cursor)) && (u->in.isNull() || u->in.match(cursor))) { - u->children.append(cursor); - } - return CXChildVisit_Continue; -} - -List children(CXCursor parent, const Filter &in, const Filter &out) -{ - ChildrenVisitor userData = { in, out, List() }; - if (!clang_isInvalid(clang_getCursorKind(parent))) - clang_visitChildren(parent, childrenVisitor, &userData); - return userData.children; -} - -struct FindChainVisitor -{ - const List &kinds; - List ret; -}; - -static CXChildVisitResult findChainVisitor(CXCursor cursor, CXCursor, CXClientData data) -{ - FindChainVisitor *u = reinterpret_cast(data); - if (clang_getCursorKind(cursor) == u->kinds.at(u->ret.size())) { - u->ret.append(cursor); - if (u->ret.size() < u->kinds.size()) - return CXChildVisit_Recurse; - - return CXChildVisit_Break; - } - return CXChildVisit_Break; -} - -List findChain(CXCursor parent, const List &kinds) -{ - assert(!kinds.isEmpty()); - FindChainVisitor userData = { kinds, List() }; - if (!clang_isInvalid(clang_getCursorKind(parent))) - clang_visitChildren(parent, findChainVisitor, &userData); - if (userData.ret.size() != kinds.size()) { - userData.ret.clear(); - } - return userData.ret; -} - -String typeName(const CXCursor &cursor) -{ - String ret; - switch (clang_getCursorKind(cursor)) { - case CXCursor_FunctionTemplate: - // ### If the return value is a template type we get an empty string here - case CXCursor_FunctionDecl: - case CXCursor_CXXMethod: - ret = typeString(clang_getResultType(clang_getCursorType(cursor))); - break; - case CXCursor_ClassTemplate: - case CXCursor_ClassDecl: - case CXCursor_StructDecl: - case CXCursor_UnionDecl: - case CXCursor_TypedefDecl: - case CXCursor_EnumDecl: - ret = RTags::eatString(clang_getCursorSpelling(cursor)); - break; - case CXCursor_VarDecl: { - const CXCursor initType = RTags::findFirstChild(cursor); - if (clang_getCursorKind(initType) == CXCursor_InitListExpr) { - ret = typeString(clang_getCursorType(initType)); - } else { - ret = typeString(clang_getCursorType(cursor)); - } - break; } - case CXCursor_FieldDecl: // ### If the return value is a template type we get an empty string here - case CXCursor_ParmDecl: - ret = typeString(clang_getCursorType(cursor)); - break; - default: - return String(); - } - if (!ret.isEmpty() && !ret.endsWith('*') && !ret.endsWith('&')) - ret.append(' '); - return ret; -} - -String typeString(const CXType &type) -{ - String ret; - if (clang_isConstQualifiedType(type)) - ret = "const "; - - const char *builtIn = builtinTypeName(type.kind); - if (builtIn) { - ret += builtIn; - return ret; - } - - if (char pointer = (type.kind == CXType_Pointer ? '*' : (type.kind == CXType_LValueReference ? '&' : 0))) { - const CXType pointee = clang_getPointeeType(type); - ret += typeString(pointee); - if (ret.endsWith('*') || ret.endsWith('&')) { - ret += pointer; - } else { - ret += ' '; - ret += pointer; - } - return ret; - } - - if (type.kind == CXType_ConstantArray) { - ret += typeString(clang_getArrayElementType(type)); - const int64_t count = clang_getNumElements(type); - ret += '['; - if (count >= 0) - ret += String::number(count); - ret += ']'; - return ret; - } - ret += typeName(clang_getTypeDeclaration(type)); - if (ret.endsWith(' ')) - ret.chop(1); - return ret; -} - -#define OUTPUT_LITERAL(string) \ - { \ - const char literal[] = string; \ - output(literal, sizeof(literal) - 1); \ - } -class ElispFormatter : public Value::Formatter -{ -public: - virtual void format(const Value &value, std::function output) const - { - switch (value.type()) { - case Value::Type_Invalid: - case Value::Type_Undefined: - OUTPUT_LITERAL("nil"); - break; - case Value::Type_Boolean: - if (value.toBool()) { - OUTPUT_LITERAL("t"); - } else { - OUTPUT_LITERAL("nil"); - } - break; - case Value::Type_Integer: { - char buf[128]; - const size_t w = snprintf(buf, sizeof(buf), "%d", value.toInteger()); - output(buf, w); - break; } - case Value::Type_Double: { - char buf[128]; - const size_t w = snprintf(buf, sizeof(buf), "%g", value.toDouble()); - output(buf, w); - break; } - case Value::Type_String: { - const String str = elispEscape(value.toString()); - OUTPUT_LITERAL("\""); - output(str.constData(), str.size()); - OUTPUT_LITERAL("\""); - break; } - case Value::Type_Custom: { - const String str = elispEscape(value.toCustom()->toString()); - OUTPUT_LITERAL("\""); - output(str.constData(), str.size()); - OUTPUT_LITERAL("\""); - break; } - case Value::Type_Map: { - const auto end = value.end(); - bool first = true; - output("(list ", 6); - for (auto it = value.begin(); it != end; ++it) { - if (!first) { - output(" ", 1); - } else { - first = false; - } - OUTPUT_LITERAL("(cons '"); - output(it->first.constData(), it->first.size()); - OUTPUT_LITERAL(" "); - format(it->second, output); - OUTPUT_LITERAL(")"); - } - output(")", 1); - break; } - case Value::Type_List: { - const auto end = value.listEnd(); - OUTPUT_LITERAL("(list "); - bool first = true; - for (auto it = value.listBegin(); it != end; ++it) { - if (!first) { - OUTPUT_LITERAL(" "); - } else { - first = false; - } - format(*it, output); - } - OUTPUT_LITERAL(")"); - break; } - case Value::Type_Date: - const String str = elispEscape(String::formatTime(value.toDate().time())); - OUTPUT_LITERAL("\""); - output(str.constData(), str.size()); - OUTPUT_LITERAL("\""); - break; - } - } -}; -String toElisp(const Value &value) -{ - return ElispFormatter().toString(value); -} - -struct CursorArgumentsVisitor { - int numArgs; - List *args; -}; -static CXChildVisitResult cursorArgumentsVisitor(CXCursor cursor, CXCursor, CXClientData data) -{ - if (clang_getCursorKind(cursor) == CXCursor_ParmDecl) { - CursorArgumentsVisitor *u = static_cast(data); - ++u->numArgs; - if (u->args) - u->args->push_back(cursor); - } - return CXChildVisit_Continue; -} -int cursorArguments(const CXCursor &cursor, List *args) -{ - int numArgs = 0; - // A workaround for the following issues: - // + clang_Cursor_getNumArguments() returns -1 with FunctionTemplate - // + clang_Cursor_getArgument() doesn't work with FunctionTemplate - // - if (clang_getCursorKind(cursor) == CXCursor_FunctionTemplate) { - CursorArgumentsVisitor u = {0, args}; - clang_visitChildren(cursor, cursorArgumentsVisitor, &u); - numArgs = u.numArgs; - } else { - numArgs = clang_Cursor_getNumArguments(cursor); - if (numArgs > 0 && args) { - args->resize(numArgs); - for (int i = 0; i < numArgs; i++) { - (*args)[i] = clang_Cursor_getArgument(cursor, i); - } - } - } - return numArgs; -} - -} diff --git a/rtags/src/RTags.h b/rtags/src/RTags.h deleted file mode 100644 index cc18193..0000000 --- a/rtags/src/RTags.h +++ /dev/null @@ -1,1225 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef RTags_h -#define RTags_h - -#if defined(__clang__) -#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) >= 30400 -#define HAS_JSON_H -#endif -#elif defined(__GNUC__) -#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900 -#define HAS_JSON_H -#endif -#else // other compiler, assume json.h is supported -#define HAS_JSON_H -#endif - -#include -#include -#include -#include -#include -#include - -#include - -#include "rct/rct-config.h" -#include "FixIt.h" -#include "Location.h" -#include "Source.h" -#include "Symbol.h" -#include "rct/Value.h" -#include "rct/Flags.h" -#include "rct/Log.h" -#include "rct/Path.h" -#include "rct/Set.h" -#include "rct/String.h" -#include "IndexMessage.h" -#include "Sandbox.h" - -class Database; -class Project; -struct Diagnostic; -struct DependencyNode; -class IndexDataMessage; -typedef List > Includes; -typedef Hash Dependencies; -typedef Hash Sources; -typedef Map > Files; -typedef Hash > FixIts; -typedef Hash UnsavedFiles; - -struct SourceCache; -inline bool operator==(const CXCursor &l, CXCursorKind r) -{ - return clang_getCursorKind(l) == r; -} -inline bool operator==(CXCursorKind l, const CXCursor &r) -{ - return l == clang_getCursorKind(r); -} - -inline bool operator!=(const CXCursor &l, CXCursorKind r) -{ - return clang_getCursorKind(l) != r; -} -inline bool operator!=(CXCursorKind l, const CXCursor &r) -{ - return l != clang_getCursorKind(r); -} - -inline bool operator==(const CXCursor &l, const CXCursor &r) -{ - return clang_equalCursors(l, r); -} -inline bool operator!=(const CXCursor &l, const CXCursor &r) -{ - return !clang_equalCursors(l, r); -} - -inline bool operator!(const CXCursor &cursor) -{ - return clang_Cursor_isNull(cursor); -} - -inline bool operator!(const CXSourceLocation &location) -{ - static const CXSourceLocation sNullLocation = clang_getNullLocation(); - return clang_equalLocations(location, sNullLocation); -} - -namespace RTags { - -String versionString(); - -const LogLevel DiagnosticsLevel(-2); -const LogLevel Statistics(-3); - -enum ExitCode { - Success = 0, - GeneralFailure = 32, - NetworkFailure = 33, - TimeoutFailure = 34, - NotIndexed = 35, - ConnectionFailure = 36, - ProtocolFailure = 37, - ArgumentParseError = 38, - UnexpectedMessageError = 39, - UnknownMessageError = 40 -}; -enum UnitType { - CompileC, - CompileCPlusPlus -}; -enum CursorType { - Type_Include, - Type_Cursor, - Type_Reference, - Type_Statement, - Type_Literal, - Type_Other -}; -void initMessages(); - -String eatString(CXString str); -enum CursorToStringFlags { - NoCursorToStringFlags = 0x0, - IncludeUSR = 0x1, - IncludeRange = 0x2, - DefaultCursorToStringFlags = IncludeRange, - IncludeSpecializedUsr = 0x4, - IncludeStructSizeof = 0x8, - AllCursorToStringFlags = IncludeUSR|IncludeRange|IncludeSpecializedUsr|IncludeStructSizeof -}; -RCT_FLAGS(CursorToStringFlags); -String cursorToString(CXCursor cursor, Flags = DefaultCursorToStringFlags); - -RCT_FLAGS(CXTranslationUnit_Flags); - -struct TranslationUnit { - TranslationUnit() - : index(0), unit(0) - {} - ~TranslationUnit() - { - if (unit) - clang_disposeTranslationUnit(unit); - if (index) - clang_disposeIndex(index); - } - static void visit(CXCursor c, std::function func) - { - clang_visitChildren(c, [](CXCursor cursor, CXCursor, CXClientData data) { - return (*reinterpret_cast *>(data))(cursor); - }, &func); - } - void visit(std::function func) - { - visit(cursor(), func); - } - - CXCursor cursor() const { return clang_getTranslationUnitCursor(unit); } - - bool reparse(CXUnsavedFile *unsaved, int unsavedCount); - static std::shared_ptr create(const Path &sourceFile, - const List &args, - CXUnsavedFile *unsaved, - int unsavedCount, - Flags translationUnitFlags = CXTranslationUnit_None, - bool displayDiagnostics = true); - - static std::shared_ptr load(const Path &path); - - CXIndex index; - CXTranslationUnit unit; - String clangLine; -}; - -struct CreateLocation -{ - virtual ~CreateLocation() {} - inline Location createLocation(const CXSourceLocation &location, bool *blocked = 0, unsigned *offset = 0) - { - CXString fileName; - unsigned int line, col; - CXFile file; - clang_getSpellingLocation(location, &file, &line, &col, offset); - if (file) { - fileName = clang_getFileName(file); - } else { - if (blocked) - *blocked = false; - return Location(); - } - const char *fn = clang_getCString(fileName); - assert(fn); - if (!*fn || !strcmp("", fn) || !strcmp("", fn)) { - if (blocked) - *blocked = false; - clang_disposeString(fileName); - return Location(); - } - const Path path = RTags::eatString(fileName); - const Location ret = createLocation(path, line, col, blocked); - return ret; - } - inline Location createLocation(CXFile file, unsigned int line, unsigned int col, bool *blocked = 0) - { - if (blocked) - *blocked = false; - if (!file) - return Location(); - - CXString fn = clang_getFileName(file); - const char *cstr = clang_getCString(fn); - if (!cstr) { - clang_disposeString(fn); - return Location(); - } - const Path p = Path::resolved(cstr); - clang_disposeString(fn); - return createLocation(p, line, col, blocked); - } - inline Location createLocation(const CXCursor &cursor, bool *blocked = 0, unsigned *offset = 0) - { - const CXSourceLocation location = clang_getCursorLocation(cursor); - if (!location) - return Location(); - return createLocation(location, blocked, offset); - } - - virtual Location createLocation(const Path &file, unsigned int line, unsigned int col, bool *blocked = 0) = 0; -}; - -struct DiagnosticsProvider -{ - virtual ~DiagnosticsProvider() {} - - inline CXFile getFile(size_t idx, const Path &path) const - { - return clang_getFile(unit(idx), path.constData()); - } - - inline CXCursor cursorAt(size_t idx, const CXSourceLocation &location) const - { - return clang_getCursor(unit(idx), location); - } - - inline Location createLocation(const CXSourceLocation &location, bool *blocked = 0, unsigned *offset = 0) - { - CXString fileName; - unsigned int line, col; - CXFile file; - clang_getSpellingLocation(location, &file, &line, &col, offset); - if (file) { - fileName = clang_getFileName(file); - } else { - if (blocked) - *blocked = false; - return Location(); - } - const char *fn = clang_getCString(fileName); - assert(fn); - if (!*fn || !strcmp("", fn) || !strcmp("", fn)) { - if (blocked) - *blocked = false; - clang_disposeString(fileName); - return Location(); - } - const Path path = RTags::eatString(fileName); - const Location ret = createLocation(path, line, col, blocked); - return ret; - } - inline Location createLocation(CXFile file, unsigned int line, unsigned int col, bool *blocked = 0) - { - if (blocked) - *blocked = false; - if (!file) - return Location(); - - CXString fn = clang_getFileName(file); - const char *cstr = clang_getCString(fn); - if (!cstr) { - clang_disposeString(fn); - return Location(); - } - const Path p = Path::resolved(cstr); - clang_disposeString(fn); - return createLocation(p, line, col, blocked); - } - Location createLocation(const CXCursor &cursor, CXCursorKind kind = CXCursor_FirstInvalid, bool *blocked = 0, unsigned *offset = 0); - virtual size_t unitCount() const = 0; - virtual size_t diagnosticCount(size_t unit) const = 0; - virtual CXDiagnostic diagnostic(size_t unit, size_t idx) const = 0; - virtual Location createLocation(const Path &file, unsigned int line, unsigned int col, bool *blocked = 0) = 0; - virtual uint32_t sourceFileId() const = 0; - virtual IndexDataMessage &indexDataMessage() = 0; - virtual CXTranslationUnit unit(size_t unit) const = 0; - - void diagnose(); -}; - -struct Auto { - CXCursor cursor; - CXType type; -}; -bool resolveAuto(const CXCursor &cursor, Auto *a = 0); - -int cursorArguments(const CXCursor &cursor, List *args = 0); - -struct Filter -{ - enum Mode { - And, - Or - }; - inline Filter(Mode m = Or) - : argumentCount(-1), mode(m) - {} - - inline bool isNull() const - { - return kinds.isEmpty() && names.isEmpty() && argumentCount == -1; - } - - inline bool isValid() const - { - return !kinds.isEmpty() || !names.isEmpty() || argumentCount != -1; - } - - inline bool match(const CXCursor &cursor) const - { - bool matched = false; - if (!kinds.isEmpty()) { - if (kinds.contains(clang_getCursorKind(cursor))) { - if (mode == Or) - return true; - matched = true; - } else if (mode == And) { - return false; - } - } - if (!names.isEmpty()) { - const String name = RTags::eatString(clang_getCursorSpelling(cursor)); - if (names.contains(name)) { - if (mode == Or) - return true; - matched = true; - } else if (mode == And) { - return false; - } - } - if (argumentCount != -1) { -#if CLANG_VERSION_MINOR > 1 - return RTags::getArguments(cursor) == argumentCount; -#else - return true; -#endif - } - return matched; - } - - Set kinds; - Set names; - int argumentCount; - Mode mode; -}; - -CXCursor findFirstChild(CXCursor parent); -CXCursor findChild(CXCursor parent, CXCursorKind kind); -CXCursor findChild(CXCursor parent, const String &name); -List findChain(CXCursor parent, const List &kinds); -List children(CXCursor parent, const Filter &in = Filter(), const Filter &out = Filter()); - -inline const char *tokenKindSpelling(CXTokenKind kind) -{ - switch (kind) { - case CXToken_Punctuation: return "Punctuation"; - case CXToken_Keyword: return "Keyword"; - case CXToken_Identifier: return "Identifier"; - case CXToken_Literal: return "Literal"; - case CXToken_Comment: return "Comment"; - } - return 0; -} - -template -inline bool startsWith(const List &list, const T &str) -{ - if (!list.isEmpty()) { - typename List::const_iterator it = std::upper_bound(list.begin(), list.end(), str); - if (it != list.end()) { - const int cmp = strncmp(str.constData(), (*it).constData(), (*it).size()); - if (cmp == 0) { - return true; - } else if (cmp < 0 && it != list.begin() && str.startsWith(*(it - 1))) { - return true; - } - } else if (str.startsWith(*(it - 1))) { - return true; - } - } - return false; -} - -inline bool isReference(CXCursorKind kind) -{ - if (clang_isReference(static_cast(kind))) - return true; - switch (kind) { - case CXCursor_DeclRefExpr: - case CXCursor_UnexposedDecl: - case CXCursor_MacroExpansion: - case CXCursor_MemberRefExpr: - case CXCursor_CallExpr: - case CXCursor_ObjCMessageExpr: - case CXCursor_CXXDeleteExpr: - return true; - default: - break; - } - return false; -} - -inline bool isFunction(CXCursorKind kind) -{ - switch (kind) { - case CXCursor_FunctionTemplate: - case CXCursor_FunctionDecl: - case CXCursor_Constructor: - case CXCursor_Destructor: - case CXCursor_CXXMethod: - case CXCursor_LambdaExpr: - case CXCursor_ObjCInstanceMethodDecl: - case CXCursor_ObjCClassMethodDecl: - return true; - default: - break; - } - return false; -} - -inline bool isCursor(CXCursorKind kind) -{ - switch (kind) { - case CXCursor_LabelStmt: - case CXCursor_MacroDefinition: - case CXCursor_FunctionTemplate: - return true; - case CXCursor_CXXAccessSpecifier: - return false; - default: - break; - } - return clang_isDeclaration(static_cast(kind)); -} - -inline CursorType cursorType(CXCursorKind kind) -{ - switch (kind) { - case CXCursor_IntegerLiteral: - case CXCursor_FloatingLiteral: - case CXCursor_ImaginaryLiteral: - case CXCursor_StringLiteral: - case CXCursor_CharacterLiteral: - case CXCursor_CompoundLiteralExpr: - case CXCursor_CXXBoolLiteralExpr: - case CXCursor_CXXNullPtrLiteralExpr: - case CXCursor_ObjCStringLiteral: - case CXCursor_ObjCBoolLiteralExpr: - return Type_Literal; - case CXCursor_InclusionDirective: - return Type_Include; - case CXCursor_LambdaExpr: - return Type_Cursor; - case CXCursor_BreakStmt: - case CXCursor_ContinueStmt: - case CXCursor_SwitchStmt: - case CXCursor_ForStmt: - case CXCursor_WhileStmt: - case CXCursor_DoStmt: - case CXCursor_CompoundStmt: - case CXCursor_ReturnStmt: - return Type_Statement; - default: - if (clang_isStatement(static_cast(kind))) { - return Type_Other; - } else if (RTags::isCursor(kind)) { - return Type_Cursor; - } else if (RTags::isReference(kind)) { - return Type_Reference; - } - } - return Type_Other; -} - -inline bool isContainer(CXCursorKind kind) -{ - switch (kind) { - case CXCursor_CXXMethod: - case CXCursor_Constructor: - case CXCursor_FunctionDecl: - case CXCursor_FunctionTemplate: - case CXCursor_Destructor: - case CXCursor_ClassTemplate: - case CXCursor_Namespace: - case CXCursor_ClassDecl: - case CXCursor_ObjCInterfaceDecl: - case CXCursor_ObjCImplementationDecl: - case CXCursor_ObjCInstanceMethodDecl: - case CXCursor_ObjCClassMethodDecl: - case CXCursor_StructDecl: - case CXCursor_LambdaExpr: - return true; - default: - break; - } - return false; -} - -inline bool needsQualifiers(CXCursorKind kind) -{ - switch (kind) { - case CXCursor_CXXMethod: - case CXCursor_Constructor: - case CXCursor_FunctionDecl: - case CXCursor_Destructor: - case CXCursor_VarDecl: - case CXCursor_ParmDecl: - case CXCursor_FieldDecl: - case CXCursor_ClassTemplate: - case CXCursor_Namespace: - case CXCursor_ClassDecl: - case CXCursor_StructDecl: - case CXCursor_EnumConstantDecl: - case CXCursor_EnumDecl: - case CXCursor_TypedefDecl: - return true; - default: - break; - } - return false; -} - -String typeName(const CXCursor &cursor); -inline const char *builtinTypeName(CXTypeKind kind) -{ - const char *ret = 0; - switch (kind) { - case CXType_Void: ret = "void"; break; - case CXType_Bool: ret = "bool"; break; - case CXType_Char_U: ret = "unsigned char"; break; - case CXType_UChar: ret = "unsigned char"; break; - case CXType_Char16: ret = "char16"; break; - case CXType_Char32: ret = "char32"; break; - case CXType_UShort: ret = "unsigned short"; break; - case CXType_UInt: ret = "unsigned int"; break; - case CXType_ULong: ret = "unsigned long"; break; - case CXType_ULongLong: ret = "unsigned long long"; break; - case CXType_UInt128: ret = "uint128"; break; - case CXType_Char_S: ret = "char"; break; - case CXType_SChar: ret = "schar"; break; - case CXType_WChar: ret = "wchar"; break; - case CXType_Short: ret = "short"; break; - case CXType_Int: ret = "int"; break; - case CXType_Long: ret = "long"; break; - case CXType_LongLong: ret = "long long"; break; - case CXType_Int128: ret = "int128"; break; - case CXType_Float: ret = "float"; break; - case CXType_Double: ret = "double"; break; - case CXType_LongDouble: ret = "long double"; break; - default: break; - } - return ret; -} - -inline const char *completionChunkKindSpelling(CXCompletionChunkKind kind) -{ - switch (kind) { - case CXCompletionChunk_Optional: return "Optional"; - case CXCompletionChunk_TypedText: return "TypedText"; - case CXCompletionChunk_Text: return "Text"; - case CXCompletionChunk_Placeholder: return "Placeholder"; - case CXCompletionChunk_Informative: return "Informative"; - case CXCompletionChunk_CurrentParameter: return "CurrentParameter"; - case CXCompletionChunk_LeftParen: return "LeftParen"; - case CXCompletionChunk_RightParen: return "RightParen"; - case CXCompletionChunk_LeftBracket: return "LeftBracket"; - case CXCompletionChunk_RightBracket: return "RightBracket"; - case CXCompletionChunk_LeftBrace: return "LeftBrace"; - case CXCompletionChunk_RightBrace: return "RightBrace"; - case CXCompletionChunk_LeftAngle: return "LeftAngle"; - case CXCompletionChunk_RightAngle: return "RightAngle"; - case CXCompletionChunk_Comma: return "Comma"; - case CXCompletionChunk_ResultType: return "ResultType"; - case CXCompletionChunk_Colon: return "Colon"; - case CXCompletionChunk_SemiColon: return "SemiColon"; - case CXCompletionChunk_Equal: return "Equal"; - case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; - case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; - } - return 0; -} - -String typeString(const CXType &type); - -struct SortedSymbol -{ - SortedSymbol(Location loc = Location(), - bool definition = false, - CXCursorKind k = CXCursor_FirstInvalid) - : location(loc), isDefinition(definition), kind(k) - {} - - Location location; - bool isDefinition; - CXCursorKind kind; - - int rank() const - { - int val = 0; - switch (kind) { - case CXCursor_VarDecl: - case CXCursor_FieldDecl: - val = 2; - break; - case CXCursor_FunctionDecl: - case CXCursor_CXXMethod: - case CXCursor_Constructor: - case CXCursor_FunctionTemplate: - val = 5; - break; - case CXCursor_ClassDecl: - case CXCursor_StructDecl: - case CXCursor_ClassTemplate: - val = 10; - break; - default: - val = 1; - break; - } - if (isDefinition) - val += 100; - return val; - } - - bool operator<(const SortedSymbol &other) const - { - const int me = rank(); - const int him = other.rank(); - // error() << "comparing<" << location << "and" << other.location - // << me << him << isDefinition << other.isDefinition - // << RTags::eatString(clang_getCursorKindSpelling(kind)) - // << RTags::eatString(clang_getCursorKindSpelling(other.kind)); - if (me != him) - return me > him; - return location < other.location; - } - bool operator>(const SortedSymbol &other) const - { - const int me = rank(); - const int him = other.rank(); - // error() << "comparing>" << location << "and" << other.location - // << me << him << isDefinition << other.isDefinition - // << RTags::eatString(clang_getCursorKindSpelling(kind)) - // << RTags::eatString(clang_getCursorKindSpelling(other.kind)); - if (me != him) - return me > him; - return location > other.location; - } -}; - -Path encodeSourceFilePath(const Path &dataDir, const Path &project, uint32_t fileId = 0); -String encodeUrlComponent(const String &string); -String decodeUrlComponent(const String &string); - -template -inline bool addTo(Container &container, const Value &value) -{ - const int oldSize = container.size(); - container += value; - return container.size() != oldSize; -} - -inline bool isSymbol(char ch) -{ - return (isalnum(ch) || ch == '_' || ch == '~'); -} - -inline bool isFunctionVariable(const String &entry) -{ - assert(entry.contains('(')); - const int endParen = entry.lastIndexOf(')'); - if (endParen != -1) { - const char *p = entry.constData() + endParen; - if (*++p == ':' && *++p == ':') { - while (*++p) { - if (!RTags::isSymbol(*p)) - return false; - } - return true; - } - } - return false; -} - -inline bool isOperator(char ch) -{ - switch (ch) { - case '!': - case '%': - case '&': - case '(': - case ')': - case '+': - case ',': - case '-': - case '.': - case '/': - case ':': - case '<': - case '=': - case '>': - case '?': - case '[': - case ']': - case '^': - case '|': - case '~': - return true; - default: - break; - } - return false; -} - -void encodePath(Path &path); -void decodePath(Path &path); -inline int digits(int len) -{ - int ret = 1; - while (len >= 10) { - len /= 10; - ++ret; - } - return ret; -} - -enum ProjectRootMode { - SourceRoot, - BuildRoot -}; -Path findProjectRoot(const Path &path, ProjectRootMode mode, SourceCache *cache = 0); -enum FindAncestorFlag { - Shallow = 0x1, - Wildcard = 0x2, - Authoritative = 0x4 -}; -RCT_FLAGS(FindAncestorFlag); -Path findAncestor(const Path& path, const String &fn, Flags flags, SourceCache *cache = 0); -Map rtagsConfig(const Path &path, SourceCache *cache = 0); - -enum { DefinitionBit = 0x1000 }; -inline CXCursorKind targetsValueKind(uint16_t val) -{ - return static_cast(val & ~DefinitionBit); -} -inline bool targetsValueIsDefinition(uint16_t val) -{ - return val & DefinitionBit; -} -inline uint16_t createTargetsValue(CXCursorKind kind, bool definition) -{ - return (kind | (definition ? DefinitionBit : 0)); -} -inline uint16_t createTargetsValue(const CXCursor &cursor) -{ - return createTargetsValue(clang_getCursorKind(cursor), clang_isCursorDefinition(cursor)); -} -inline int targetRank(CXCursorKind kind) -{ - switch (kind) { - case CXCursor_Constructor: // this one should be more than class/struct decl - return 3; - case CXCursor_ClassDecl: - case CXCursor_StructDecl: - case CXCursor_ClassTemplate: - return 0; - case CXCursor_FieldDecl: - case CXCursor_VarDecl: - case CXCursor_ParmDecl: - return 6; - case CXCursor_FunctionDecl: - case CXCursor_CXXMethod: - // functiondecl and cxx method must be more than cxx - // CXCursor_FunctionTemplate. Since constructors for templatized - // objects seem to come out as function templates - return 4; - case CXCursor_MacroDefinition: - return 5; - default: - return 2; - } -} -inline Symbol bestTarget(const Set &targets) -{ - Symbol ret; - int bestRank = -1; - for (auto t : targets) { - const int rank = targetRank(t.kind); - if (rank > bestRank || (rank == bestRank && t.isDefinition())) { - ret = t; - bestRank = rank; - } - } - return ret; -} - -inline void sortTargets(List &targets) -{ - targets.sort([](const Symbol &l, const Symbol &r) { - const int lrank = RTags::targetRank(l.kind); - const int rrank = RTags::targetRank(r.kind); - if (lrank != rrank) - return lrank > rrank; - if (l.isDefinition() != r.isDefinition()) - return l.isDefinition(); - return l.location < r.location; - }); -} - -inline List sortTargets(Set &&set) -{ - List targets; - targets.resize(set.size()); - size_t i=0; - for (auto &sym : set) { - targets[i++] = std::move(sym); - } - sortTargets(targets); - return targets; -} - -inline List sortTargets(const Set &set) -{ - return sortTargets(Set(set)); -} - -inline String xmlEscape(const String& xml) -{ - if (xml.isEmpty()) - return xml; - - String ret; - ret.reserve(xml.size() * 1.1); - const char* ch = xml.constData(); - while (*ch) { - switch (*ch) { - case '"': - ret << "\\\""; - break; - case '<': - ret << "<"; - break; - case '>': - ret << ">"; - break; - case '&': - ret << "&"; - break; - default: - ret << *ch; - break; - } - ++ch; - } - return ret; -} - -inline const String elispEscape(const String &data) -{ - String ret; - const int size = data.size(); - const char *ch = data.constData(); - bool copied = false; - for (int i=0; i", fn) || !strcmp("", fn)) { - clang_disposeString(fileName); - return Location(); - } - Path path = RTags::eatString(fileName); - uint32_t fileId = Location::fileId(path); - if (!fileId) { - path.resolve(); - fileId = Location::insertFile(path); - } - if (offsetPtr) - *offsetPtr = offset; - return Location(fileId, line, col); -} - -inline Location createLocation(const CXCursor &cursor, int *offsetPtr = 0) -{ - return createLocation(clang_getCursorLocation(cursor), offsetPtr); -} - -inline bool isValid(const CXCursor &cursor) -{ - return !!cursor; -} - -inline bool isValid(CXCursorKind kind) -{ - return !clang_isInvalid(kind); -} -inline bool isValid(const CXSourceLocation &location) -{ - return !!location; -} -} - -namespace std -{ -template <> struct hash : public unary_function -{ - size_t operator()(const CXCursor &value) const - { - return clang_hashCursor(value); - } -}; -} - -template -inline String dumpFileIds(const Container &container) -{ - String ret; - { - Log l(&ret); - for (uint32_t fileId : container) { - l << Location::path(fileId); - } - } - return ret; -} - -struct SourceCache -{ - Hash > rtagsConfigCache; - Hash > compilerCache; // bool signifies isCompiler, not just executable - struct AncestorCacheKey { - String string; - Flags flags; - - bool operator<(const AncestorCacheKey &other) const - { - const int cmp = string.compare(other.string); - if (cmp) - return cmp < 0; - return flags < other.flags; - } - }; - Hash > ancestorCache; -}; - -inline Log operator<<(Log dbg, CXCursor cursor); -inline Log operator<<(Log dbg, CXType type); -inline Log operator<<(Log dbg, CXCursorKind kind); -inline Log operator<<(Log dbg, CXTypeKind kind); -inline Log operator<<(Log dbg, CXLinkageKind kind); - -class CXStringScope -{ -public: - CXStringScope(CXString str) : string(str) - { - } - - ~CXStringScope() - { - clang_disposeString(string); - } - const char *data() const - { - return clang_getCString(string); - } - operator CXString () const { return string; } - bool operator==(const std::string &str) const { return !strcmp(clang_getCString(string), str.c_str()); } - bool operator!=(const std::string &str) const { return strcmp(clang_getCString(string), str.c_str()); } -private: - CXString string; -}; - -inline Log operator<<(Log dbg, CXCursor cursor) -{ - dbg << RTags::cursorToString(cursor, RTags::AllCursorToStringFlags); - return dbg; -} - -inline Log operator<<(Log dbg, CXType type) -{ - dbg << type.kind << RTags::eatString(clang_getTypeSpelling(type)); - return dbg; -} - -inline Log operator<<(Log dbg, CXCursorKind kind) -{ - dbg << RTags::eatString(clang_getCursorKindSpelling(kind)); - return dbg; -} - -inline Log operator<<(Log dbg, CXTypeKind kind) -{ - dbg << RTags::eatString(clang_getTypeKindSpelling(kind)); - return dbg; -} - -inline Log operator<<(Log dbg, CXLinkageKind kind) -{ - switch (kind) { - case CXLinkage_Invalid: - dbg << "Invalid"; - break; - case CXLinkage_NoLinkage: - dbg << "NoLinkage"; - break; - case CXLinkage_Internal: - dbg << "Internal"; - break; - case CXLinkage_UniqueExternal: - dbg << "UniqueExternal"; - break; - case CXLinkage_External: - dbg << "External"; - break; - } - return dbg; -} - -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 29) -inline Log operator<<(Log dbg, CXTemplateArgumentKind kind) -{ - switch (kind) { - case CXTemplateArgumentKind_Null: dbg << "Null"; break; - case CXTemplateArgumentKind_Type: dbg << "Type"; break; - case CXTemplateArgumentKind_Declaration: dbg << "Declaration"; break; - case CXTemplateArgumentKind_NullPtr: dbg << "NullPtr"; break; - case CXTemplateArgumentKind_Integral: dbg << "Integral"; break; - case CXTemplateArgumentKind_Template: dbg << "Template"; break; - case CXTemplateArgumentKind_TemplateExpansion: dbg << "TemplateExpansion"; break; - case CXTemplateArgumentKind_Expression: dbg << "Expression"; break; - case CXTemplateArgumentKind_Pack: dbg << "Pack"; break; - case CXTemplateArgumentKind_Invalid: dbg << "Invalid"; break; - } - return dbg; -} -#endif - -inline Log operator<<(Log dbg, CXAvailabilityKind kind) -{ - switch (kind) { - case CXAvailability_Available: dbg << "Available"; break; - case CXAvailability_Deprecated: dbg << "Deprecated"; break; - case CXAvailability_NotAvailable: dbg << "NotAvailable"; break; - case CXAvailability_NotAccessible: dbg << "NotAccessible"; break; - } - return dbg; -} - -inline Log operator<<(Log dbg, CXLanguageKind kind) -{ - switch (kind) { - case CXLanguage_Invalid: dbg << "Invalid"; break; - case CXLanguage_C: dbg << "C"; break; - case CXLanguage_ObjC: dbg << "ObjC"; break; - case CXLanguage_CPlusPlus: dbg << "CPlusPlus"; break; - } - return dbg; -} - -inline Log operator<<(Log dbg, CXDiagnosticSeverity severity) -{ - switch (severity) { - case CXDiagnostic_Ignored: dbg << "Ignored"; break; - case CXDiagnostic_Note: dbg << "Note"; break; - case CXDiagnostic_Warning: dbg << "Warning"; break; - case CXDiagnostic_Error: dbg << "Error"; break; - case CXDiagnostic_Fatal: dbg << "Fatal"; break; - } - return dbg; -} - -inline Log operator<<(Log dbg, CXCallingConv conv) -{ - switch (conv) { - case CXCallingConv_Default: dbg << "Default"; break; - case CXCallingConv_C: dbg << "C"; break; - case CXCallingConv_X86StdCall: dbg << "X86StdCall"; break; - case CXCallingConv_X86FastCall: dbg << "X86FastCall"; break; - case CXCallingConv_X86ThisCall: dbg << "X86ThisCall"; break; - case CXCallingConv_X86Pascal: dbg << "X86Pascal"; break; - case CXCallingConv_AAPCS: dbg << "AAPCS"; break; - case CXCallingConv_AAPCS_VFP: dbg << "AAPCS_VFP"; break; - /* case CXCallingConv_PnaclCall: dbg << "PnaclCall"; break; */ - case CXCallingConv_IntelOclBicc: dbg << "IntelOclBicc"; break; -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20) - case CXCallingConv_X86_64Win64: dbg << "X86_64Win64"; break; - case CXCallingConv_X86_64SysV: dbg << "X86_64SysV"; break; -#endif -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 30) - case CXCallingConv_X86VectorCall: dbg << "X86VectorCall"; break; -#endif - case CXCallingConv_Invalid: dbg << "Invalid"; break; - case CXCallingConv_Unexposed: dbg << "Unexposed"; break; - default: - break; - } - return dbg; -} - -#if CINDEX_VERSION >= CINDEX_VERSION_ENCODE(0, 20) -inline Log operator<<(Log dbg, CXRefQualifierKind kind) -{ - switch (kind) { - case CXRefQualifier_None: dbg << "None"; break; - case CXRefQualifier_LValue: dbg << "lvalue"; break; - case CXRefQualifier_RValue: dbg << "rvalue"; break; - } - return dbg; -} -#endif - -inline Log operator<<(Log dbg, CXTypeLayoutError err) -{ - switch (err) { - case CXTypeLayoutError_Invalid: dbg << "Invalid"; break; - case CXTypeLayoutError_Incomplete: dbg << "Incomplete"; break; - case CXTypeLayoutError_Dependent: dbg << "Dependent"; break; - case CXTypeLayoutError_NotConstantSize: dbg << "NotConstantSize"; break; - case CXTypeLayoutError_InvalidFieldName: dbg << "InvalidFieldName"; break; - } - return dbg; -} - -inline Log operator<<(Log dbg, CXTokenKind kind) -{ - dbg << RTags::tokenKindSpelling(kind); - return dbg; -} - -inline String &operator<<(String &str, CXString cxstr) -{ - if (const char *cstr = clang_getCString(cxstr)) - str.append(cstr); - clang_disposeString(cxstr); - return str; -} - -#endif diff --git a/rtags/src/RTagsLogOutput.h b/rtags/src/RTagsLogOutput.h deleted file mode 100644 index 5b8af38..0000000 --- a/rtags/src/RTagsLogOutput.h +++ /dev/null @@ -1,70 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef RTagsLogOutput_h -#define RTagsLogOutput_h - -#include "rct/Connection.h" -#include "rct/Log.h" -#include "rct/String.h" - -class RTagsLogOutput : public LogOutput -{ -public: - enum Flag { - None = 0x0, - Elisp = 0x1, - XML = 0x2, - JSON = 0x4, - NoSpellChecking = 0x8 - }; - RTagsLogOutput(LogLevel level, unsigned int flags, const std::shared_ptr &conn = std::shared_ptr()) - : LogOutput(level), mFlags(flags), mConnection(conn) - { - if (conn) { - conn->disconnected().connect(std::bind(&RTagsLogOutput::remove, this)); - conn->client()->setLogsEnabled(false); - } - } - - virtual unsigned int flags() const override { return mFlags; } - - virtual bool testLog(LogLevel level) const override - { - if (level == RTags::DiagnosticsLevel && mFlags & NoSpellChecking) - return false; - if (logLevel() < LogLevel::Error || level < LogLevel::Error) - return level == logLevel(); - return LogOutput::testLog(level); - } - virtual void log(Flags, const char *msg, int len) override - { - if (mConnection) { - std::shared_ptr main = EventLoop::mainEventLoop(); - if (EventLoop::eventLoop() == main) { - mConnection->write(String(msg, len)); - } else { - EventLoop::mainEventLoop()->callLaterMove(std::bind((bool(Connection::*)(Message&&))&Connection::send, mConnection, std::placeholders::_1), - ResponseMessage(String(msg, len))); - } - } - } - std::shared_ptr connection() const { return mConnection; } -private: - const unsigned int mFlags; - std::shared_ptr mConnection; -}; - -#endif diff --git a/rtags/src/RTagsMessage.h b/rtags/src/RTagsMessage.h deleted file mode 100644 index 841c9da..0000000 --- a/rtags/src/RTagsMessage.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef RTagsMessage_h -#define RTagsMessage_h - -#include "rct/Message.h" -#include "rct/String.h" -#include -#include - -class RTagsMessage : public Message -{ -public: - enum { - CompletionId = 32, - QueryId, - CompileId, - LogOutputId, - VisitFileResponseId, - VisitFileId, - IndexDataMessageId, - JobRequestId, - JobResponseId, - JobAnnouncementId, - ProxyJobAnnouncementId, - ClientMessageId, - ClientConnectedId, - ExitMessageId - }; - - RTagsMessage(uint8_t id) : Message(id) {} - - inline void setCommandLine(const String &cmd) { mCommandLine = cmd; } - inline String commandLine() const { return mCommandLine; } -protected: - String mCommandLine; -}; - -#endif diff --git a/rtags/src/RTagsVersion.h.in b/rtags/src/RTagsVersion.h.in deleted file mode 100644 index 5d260d2..0000000 --- a/rtags/src/RTagsVersion.h.in +++ /dev/null @@ -1,9 +0,0 @@ -namespace RTags { - -enum { - MajorVersion = @RTAGS_VERSION_MAJOR@, - MinorVersion = @RTAGS_VERSION_MINOR@, - DatabaseVersion = @RTAGS_VERSION_DATABASE@, - SourcesFileVersion = @RTAGS_VERSION_SOURCES_FILE@ -}; -} diff --git a/rtags/src/ReferencesJob.cpp b/rtags/src/ReferencesJob.cpp deleted file mode 100644 index b927561..0000000 --- a/rtags/src/ReferencesJob.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "ReferencesJob.h" - -#include "Project.h" -#include "RTags.h" -#include "Server.h" - -static inline Flags jobFlags(Flags queryFlags) -{ - return (queryFlags & QueryMessage::Elisp ? Flags(QueryJob::QuoteOutput) : Flags()); -} - -ReferencesJob::ReferencesJob(Location loc, const std::shared_ptr &query, const std::shared_ptr &proj) - : QueryJob(query, proj, ::jobFlags(query->flags())) -{ - mLocations.insert(loc); -} - -ReferencesJob::ReferencesJob(const String &sym, const std::shared_ptr &query, const std::shared_ptr &proj) - : QueryJob(query, proj, ::jobFlags(query->flags())), mSymbolName(sym) -{ -} - -int ReferencesJob::execute() -{ - const bool rename = queryFlags() & QueryMessage::Rename; - std::shared_ptr proj = project(); - if (!proj) - return 1; - Set refs; - Map > references; - if (!mSymbolName.isEmpty()) { - const bool hasFilter = QueryJob::hasFilter(); - auto inserter = [this, hasFilter](Project::SymbolMatchType type, const String &string, const Set &locs) { - if (type == Project::StartsWith) { - const size_t paren = string.indexOf('('); - if (paren == String::npos || paren != mSymbolName.size() || RTags::isFunctionVariable(string)) - return; - } - - for (const auto &l : locs) { - if (!hasFilter || filter(l.path())) { - mLocations.insert(l); - } - } - }; - proj->findSymbols(mSymbolName, inserter, queryFlags()); - } - const bool declarationOnly = queryFlags() & QueryMessage::DeclarationOnly; - const bool definitionOnly = queryFlags() & QueryMessage::DefinitionOnly; - Location startLocation; - bool first = true; - for (auto it = mLocations.begin(); it != mLocations.end(); ++it) { - const Location pos = *it; - Symbol sym = proj->findSymbol(pos); - if (sym.isNull()) - continue; - if (first && !(queryFlags() & QueryMessage::NoSortReferencesByInput)) { - first = false; - startLocation = sym.location; - } - - if (sym.isReference()) { - const Symbol target = proj->findTarget(sym); - if (!target.isNull() && target.kind != CXCursor_MacroExpansion) - sym = target; - } - if (sym.isNull()) - continue; - - if (rename && sym.isConstructorOrDestructor()) { - const Location loc = sym.location; - sym.clear(); - const Set usrs = proj->findTargetUsrs(loc); - for (const String &usr : usrs) { - for (const Symbol &s : proj->findByUsr(usr, loc.fileId(), Project::All)) { - if (s.isClass()) { - sym = s; - if (s.isDefinition()) - break; - } - } - } - - if (sym.isNull()) - continue; - } - if (queryFlags() & QueryMessage::AllReferences) { - const Set all = proj->findAllReferences(sym); - for (const auto &symbol : all) { - if (rename) { - if (symbol.kind == CXCursor_MacroExpansion && sym.kind != CXCursor_MacroDefinition) { - continue; - } - } else if (sym.isClass() && symbol.isConstructorOrDestructor()) { - continue; - } - const bool def = symbol.isDefinition(); - if (def) { - if (declarationOnly) - continue; - } else if (definitionOnly) { - continue; - } - references[symbol.location] = std::make_pair(def, symbol.kind); - } - } else if (queryFlags() & QueryMessage::FindVirtuals) { - const Set virtuals = proj->findVirtuals(sym); - for (const auto &symbol : virtuals) { - const bool def = symbol.isDefinition(); - if (def) { - if (declarationOnly) - continue; - } else if (definitionOnly) { - continue; - } - references[symbol.location] = std::make_pair(def, symbol.kind); - } - } else { - const Set symbols = proj->findCallers(sym); - for (const auto &symbol : symbols) { - const bool def = symbol.isDefinition(); - if (def) { - if (declarationOnly) - continue; - } else if (definitionOnly) { - continue; - } - references[symbol.location] = std::make_pair(false, CXCursor_FirstInvalid); - } - } - } - Flags writeFlags; - if (queryFlags() & QueryMessage::Elisp) { - write("(list ", DontQuote); - writeFlags |= QueryJob::NoContext; - } else if (queryFlags() & QueryMessage::NoContext) { - writeFlags |= QueryJob::NoContext; - } - - auto writeCons = [this](const String &car, const String &cdr) { - write("(cons ", DontQuote); - write(car, DontQuote); - write(cdr); - write(")", DontQuote); - }; - - Value json; - auto writeLoc = [this, writeCons, writeFlags, &json](Location loc) { - if (queryFlags() & QueryMessage::Elisp) { - if (!filterLocation(loc)) - return; - write("(list ", DontQuote); - locationToString(loc, [writeCons, this](LocationPiece piece, const String &string) { - switch (piece) { - case Piece_ContainingFunctionLocation: - if (queryFlags() & QueryMessage::ContainingFunctionLocation) - writeCons("'cfl", string); - break; - case Piece_ContainingFunctionName: - if (queryFlags() & QueryMessage::ContainingFunction) - writeCons("'cf", string); - break; - case Piece_Location: - writeCons("'loc", string); - break; - case Piece_Context: - if (!(queryFlags() & QueryMessage::NoContext)) - writeCons("'ctx", string); - break; - case Piece_SymbolName: - case Piece_Kind: - break; - } - }); - write(")", DontQuote); - } else if (queryFlags() & QueryMessage::JSON) { - if (!filterLocation(loc)) - return; - Value value; - locationToString(loc, [&value, this](LocationPiece piece, const String &string) { - switch (piece) { - case Piece_ContainingFunctionLocation: - if (queryFlags() & QueryMessage::ContainingFunctionLocation) - value["cfl"] = string; - break; - case Piece_ContainingFunctionName: - if (queryFlags() & QueryMessage::ContainingFunction) - value["cf"] = string; - break; - case Piece_Location: - value["loc"] = string; - break; - case Piece_Context: - if (!(queryFlags() & QueryMessage::NoContext)) - value["ctx"] = string; - break; - case Piece_SymbolName: - case Piece_Kind: - break; - } - }); - json.push_back(value); - } else { - write(loc, writeFlags); - } - }; - - if (rename) { - if (!references.isEmpty()) { - if (queryFlags() & QueryMessage::ReverseSort) { - Map >::const_iterator it = references.end(); - do { - --it; - writeLoc(it->first); - } while (it != references.begin()); - } else { - for (const auto &it : references) { - writeLoc(it.first); - } - } - } - } else { - List sorted; - sorted.reserve(references.size()); - for (Map >::const_iterator it = references.begin(); - it != references.end(); ++it) { - sorted.append(RTags::SortedSymbol(it->first, it->second.first, it->second.second)); - } - if (queryFlags() & QueryMessage::ReverseSort) { - std::sort(sorted.begin(), sorted.end(), std::greater()); - } else { - std::sort(sorted.begin(), sorted.end()); - } - int startIndex = 0; - const int count = sorted.size(); - if (!startLocation.isNull()) { - for (int i=0; i. */ - -#ifndef ReferencesJob_h -#define ReferencesJob_h - -#include "Location.h" -#include "QueryJob.h" -#include "rct/String.h" - -class SymbolInfo; -class ReferencesJob : public QueryJob -{ -public: - ReferencesJob(Location location, const std::shared_ptr &query, const std::shared_ptr &project); - ReferencesJob(const String &symbolName, const std::shared_ptr &query, const std::shared_ptr &project); -protected: - virtual int execute() override; -private: - Set mLocations; - const String mSymbolName; -}; - -#endif diff --git a/rtags/src/Sandbox.cpp b/rtags/src/Sandbox.cpp deleted file mode 100644 index 5758007..0000000 --- a/rtags/src/Sandbox.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "Sandbox.h" -#include "Server.h" -#include "ClangIndexer.h" - -namespace Sandbox { -const Path &root() -{ - if (Server::instance()) { - return Server::instance()->options().sandboxRoot; - } else { - return ClangIndexer::serverSandboxRoot(); - } -} -} diff --git a/rtags/src/Sandbox.h b/rtags/src/Sandbox.h deleted file mode 100644 index 507db64..0000000 --- a/rtags/src/Sandbox.h +++ /dev/null @@ -1,211 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef Sandbox_h -#define Sandbox_h - -#include -#include "rct/String.h" -#include "rct/Path.h" -#include "rct/Map.h" -#include "rct/Hash.h" -#include "rct/List.h" - -namespace Sandbox { -enum ReplaceMode { - StartsWith, - Everywhere -}; -static const String encodedRoot("[[SBROOT]]"); -const Path &root(); -inline bool hasRoot() { return !root().isEmpty(); } - -template ::value, T>::type * = nullptr> -bool encode(T &t, ReplaceMode mode = Everywhere) -{ - const Path &r = root(); - if (mode == Everywhere) { - return t.replace(r, encodedRoot); - } - - if (t.startsWith(r)) { - t.replace(0, r.size(), encodedRoot); - return true; - } - return false; -} - -template ::value>::type * = nullptr, - typename std::enable_if::value>::type * = nullptr> -bool encode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - for (auto &val : t) { - if (encode(val.second, mode)) - ret = true; - } - - return ret; -} - -template ::value>::type * = nullptr, - typename std::enable_if::value>::type * = nullptr> -bool encode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - typename T::iterator it = t.begin(); - while (it != t.end()) { - typename T::key_type key = it->first; - if (encode(key, mode)) { - t[key] = it->second; - t.erase(it++); - ret = true; - } else { - ++it; - } - } - return ret; -} - -template ::value>::type * = nullptr, - typename std::enable_if::value>::type * = nullptr> -bool encode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - for (auto &val : t) { - ret = encode(val.second, mode) || ret; - } - return ret; -} - -template ::value>::type * = nullptr> -bool encode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - for (auto &val : t) { - ret = encode(val, mode) || ret; - } - return ret; -} - -template -T encoded(const T &t, ReplaceMode mode = Everywhere) -{ - T copy = t; - encode(copy, mode); - return copy; -} - -template -T encoded(T &&t, ReplaceMode mode = Everywhere) -{ - encode(t, mode); - return t; -} - -template ::value, T>::type * = nullptr> -bool decode(T &t, ReplaceMode mode = Everywhere) -{ - const String &r = root(); - if (mode == Everywhere) { - return t.replace(encodedRoot, r); - } - - if (t.startsWith(encodedRoot)) { - t.replace(0, encodedRoot.size(), r); - return true; - } - return false; -} - -template ::value>::type * = nullptr, - typename std::enable_if::value>::type * = nullptr> -bool decode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - for (auto &val : t) { - if (decode(val.second, mode)) - ret = true; - } - - return ret; -} - -template ::value>::type * = nullptr, - typename std::enable_if::value>::type * = nullptr> -bool decode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - typename T::iterator it = t.begin(); - while (it != t.end()) { - typename T::key_type key = it->first; - if (decode(key, mode)) { - t[key] = it->second; - t.erase(it++); - ret = true; - } else { - ++it; - } - } - return ret; -} - -template ::value>::type * = nullptr, - typename std::enable_if::value>::type * = nullptr> -bool decode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - for (auto &val : t) { - ret = decode(val.second, mode) || ret; - } - return ret; -} - -template ::value>::type * = nullptr> -bool decode(T &t, ReplaceMode mode = Everywhere) -{ - bool ret = false; - for (auto &val : t) { - ret = decode(val, mode) || ret; - } - return ret; -} - -template -T decoded(const T &t, ReplaceMode mode = Everywhere) -{ - T copy = t; - decode(copy, mode); - return copy; -} - -template -T decoded(T &&t, ReplaceMode mode = Everywhere) -{ - decode(t, mode); - return t; -} - -} - -#endif diff --git a/rtags/src/ScanThread.cpp b/rtags/src/ScanThread.cpp deleted file mode 100644 index ad9eae9..0000000 --- a/rtags/src/ScanThread.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "ScanThread.h" - -#include "Filter.h" -#include "Project.h" -#include "Server.h" - -ScanThread::ScanThread(const Path &path) - : Thread(), mPath(path), mFilters(Server::instance()->options().excludeFilters) -{ -} - -Set ScanThread::paths(const Path &path, const List &filters) -{ - Set paths; - path.visit([&paths, filters](const Path &p) { - const Filter::Result result = Filter::filter(p, filters); - switch (result) { - case Filter::Filtered: - return Path::Continue; - case Filter::Directory: - if (Path::exists(p + "/.rtags-ignore")) - return Path::Continue; - return Path::Recurse; - case Filter::File: - case Filter::Source: - paths.insert(p); - break; - } - return Path::Continue; - }); - return paths; -} - -void ScanThread::run() -{ - mFinished(paths(mPath, mFilters)); -} diff --git a/rtags/src/ScanThread.h b/rtags/src/ScanThread.h deleted file mode 100644 index 2c08350..0000000 --- a/rtags/src/ScanThread.h +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#ifndef ScanThread_h -#define ScanThread_h - -#include "rct/Path.h" -#include "rct/SignalSlot.h" -#include "rct/Thread.h" - -class Project; -class ScanThread : public Thread -{ -public: - ScanThread(const Path &path); - virtual void run() override; - Signal)> > &finished() { return mFinished; } - static Set paths(const Path &path, const List &filters = List()); -private: - Path mPath; - const List &mFilters; - Signal)> > mFinished; -}; - -#endif diff --git a/rtags/src/Server.cpp b/rtags/src/Server.cpp deleted file mode 100644 index c296d6f..0000000 --- a/rtags/src/Server.cpp +++ /dev/null @@ -1,2518 +0,0 @@ -/* This file is part of RTags (http://rtags.net). - - RTags is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - RTags is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with RTags. If not, see . */ - -#include "Server.h" -#include -#include "TokensJob.h" - -#include -#include -#include -#include -#include -#include - -#include "ClassHierarchyJob.h" -#include "CompletionThread.h" -#include "DependenciesJob.h" -#include "ClangThread.h" -#include "FileManager.h" -#include "Filter.h" -#include "FindFileJob.h" -#include "FindSymbolsJob.h" -#include "FollowLocationJob.h" -#include "IncludeFileJob.h" -#include "IndexDataMessage.h" -#include "IndexerJob.h" -#include "IndexMessage.h" -#include "JobScheduler.h" -#include "ListSymbolsJob.h" -#include "LogOutputMessage.h" -#include "Match.h" -#include "Preprocessor.h" -#include "Project.h" -#include "QueryMessage.h" -#include "RClient.h" -#include "IndexParseData.h" -#include "rct/Connection.h" -#include "rct/DataFile.h" -#include "rct/EventLoop.h" -#include "rct/Log.h" -#include "rct/Message.h" -#include "rct/Path.h" -#include "rct/Process.h" -#include "rct/QuitMessage.h" -#include "rct/Rct.h" -#include "rct/SocketClient.h" -#include "rct/Value.h" -#include "ReferencesJob.h" -#include "RTags.h" -#include "RTagsLogOutput.h" -#include "Source.h" -#include "StatusJob.h" -#include "SymbolInfoJob.h" -#include "VisitFileMessage.h" -#include "VisitFileResponseMessage.h" -#include "RTagsVersion.h" - -#define TO_STR1(x) #x -#define TO_STR(x) TO_STR1(x) -#define CLANG_LIBDIR_STR TO_STR(CLANG_LIBDIR) -#ifdef CLANG_INCLUDE -#define CLANG_INCLUDE_STR TO_STR(CLANG_INCLUDE) -#endif -#ifdef CLANG_VERSION -#define CLANG_VERSION_STRING TO_STR(CLANG_VERSION) -#endif - - -// Absolute paths to search (under) for (clang) system include files -// Iterate until we find a dir at /clang//include. -// As of clang 4.0.0 we don't need (and can't have) these includes on Mac. -#if CINDEX_VERSION_ENCODE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR) >= CINDEX_VERSION_ENCODE(0, 37) && defined(OS_Darwin) -static const List sSystemIncludePaths; -#else -static const List sSystemIncludePaths = { - CLANG_LIBDIR_STR, // standard llvm build, debian/ubuntu - "/usr/lib" // fedora, arch -}; -#endif - -Server *Server::sInstance = 0; -Server::Server() - : mSuspended(false), mEnvironment(Rct::environment()), mPollTimer(-1), mExitCode(0), - mLastFileId(0), mCompletionThread(0), mHadActiveBuffers(false) -{ - assert(!sInstance); - sInstance = this; -} - -Server::~Server() -{ - if (mPollTimer >= 0) - EventLoop::eventLoop()->unregisterTimer(mPollTimer); - - if (mCompletionThread) { - mCompletionThread->stop(); - mCompletionThread->join(); - delete mCompletionThread; - mCompletionThread = 0; - } - - stopServers(); - mProjects.clear(); // need to be destroyed before sInstance is set to 0 - assert(sInstance == this); - sInstance = 0; - Message::cleanup(); -} - -bool Server::init(const Options &options) -{ - RTags::initMessages(); - - mOptions = options; - mSuspended = (options.options & StartSuspended); - mOptions.defaultArguments << String::format<32>("-ferror-limit=%d", mOptions.errorLimit); - if (options.options & Wall) - mOptions.defaultArguments << "-Wall"; - if (options.options & Weverything) - mOptions.defaultArguments << "-Weverything"; - if (options.options & SpellChecking) - mOptions.defaultArguments << "-fspell-checking"; - if (!(options.options & NoNoUnknownWarningsOption)) - mOptions.defaultArguments.append("-Wno-unknown-warning-option"); - - mOptions.defines << Source::Define("RTAGS"); - - if (mOptions.options & EnableCompilerManager) { -#ifndef OS_Darwin // this causes problems on MacOS+clang - // http://clang.llvm.org/compatibility.html#vector_builtins - const char *gccBuiltIntVectorFunctionDefines[] = { - "__builtin_ia32_rolhi", - "__builtin_ia32_pause", - "__builtin_ia32_addcarryx_u32", - "__builtin_ia32_bsrsi", - "__builtin_ia32_rdpmc", - "__builtin_ia32_rdtsc", - "__builtin_ia32_rdtscp", - "__builtin_ia32_rolqi", - "__builtin_ia32_rorqi", - "__builtin_ia32_rorhi", - "__builtin_ia32_rolhi", - "__builtin_ia32_rdseed_di_step", - "__builtin_ia32_xsaveopt", - "__builtin_ia32_xsaveopt64", - "__builtin_ia32_sbb_u32", - 0 - }; - for (int i=0; gccBuiltIntVectorFunctionDefines[i]; ++i) { - mOptions.defines << Source::Define(String::format<128>("%s(...)", gccBuiltIntVectorFunctionDefines[i])); - } -#endif - } -#ifdef CLANG_INCLUDE - mOptions.includePaths.append(Source::Include(Source::Include::Type_System, CLANG_INCLUDE_STR)); -#endif - - if (!(mOptions.options & NoLibClangIncludePath)) { - // Iterate until we find an existing directory - for (Path systemInclude : sSystemIncludePaths) { - systemInclude = systemInclude.ensureTrailingSlash(); - systemInclude << "clang/" << CLANG_VERSION_STRING << "/include/"; - if (systemInclude.isDir()) { - mOptions.includePaths.append(Source::Include(Source::Include::Type_System, systemInclude)); - break; - } - } - } - - if (!initServers()) { - error("Unable to listen on %s (errno: %d)", mOptions.socketFile.constData(), errno); - return false; - } - - { - Log l(LogLevel::Error, LogOutput::StdOut|LogOutput::TrailingNewLine); - l << "Running with" << mOptions.jobCount << "jobs, using args:" - << String::join(mOptions.defaultArguments, ' '); - if (!mOptions.includePaths.isEmpty()) { - l << "\nIncludepaths:"; - for (const auto &inc : mOptions.includePaths) - l << inc.toString(); - } - } - - if (mOptions.options & ClearProjects) { - clearProjects(Clear_All); - } - - mJobScheduler.reset(new JobScheduler); - - if (!load()) - return false; - if (!(mOptions.options & NoStartupCurrentProject)) { - Path current = Path(mOptions.dataDir + ".currentProject").readAll(1024); - RTags::decodePath(current); - if (current.size() > 1) { - current.chop(1); - const auto project = mProjects.value(current); - if (!project) { - error() << "Can't restore project" << current; - unlink((mOptions.dataDir + ".currentProject").constData()); - } else { - setCurrentProject(project); - } - } - } - - assert(mOptions.pollTimer >= 0); - if (mOptions.pollTimer) { - mPollTimer = EventLoop::eventLoop()->registerTimer([this](int) { - for (auto proj : mProjects) { - proj.second->validateAll(); - } - }, mOptions.pollTimer * 1000); - } - return true; -} - -bool Server::initServers() -{ - if (mOptions.tcpPort) { - for (int i=0; i<10; ++i) { - mTcpServer.reset(new SocketServer); - warning() << "listening" << mOptions.tcpPort; - if (mTcpServer->listen(mOptions.tcpPort)) { - break; - } - mTcpServer.reset(); - if (!i) { - enum { Timeout = 1000 }; - std::shared_ptr connection = Connection::create(RClient::NumOptions); - if (connection->connectTcp("127.0.0.1", mOptions.tcpPort, Timeout)) { - connection->send(QuitMessage()); - connection->disconnected().connect(std::bind([](){ EventLoop::eventLoop()->quit(); })); - connection->finished().connect(std::bind([](){ EventLoop::eventLoop()->quit(); })); - EventLoop::eventLoop()->exec(Timeout); - } - } else { - sleep(1); - } - } - if (!mTcpServer) - return false; - mTcpServer->newConnection().connect(std::bind(&Server::onNewConnection, this, std::placeholders::_1)); - } - -#ifdef RTAGS_HAS_LAUNCHD - // If Launchd, it goes into this bit and never comes out. - if (mOptions.options & Launchd) { - warning("initServers: launchd mode."); - - int *fds = 0; - size_t numFDs; - int ret = launch_activate_socket("Listener", &fds, &numFDs); - - if (ret != 0) { - error("Failed to retrieve launchd socket: %s", strerror(ret)); - } else if (numFDs != 1) { - error("Unexpected number of sockets from launch_activate_socket: %zu", numFDs); - } else { - warning() << "got fd from launchd: " << fds[0]; - mUnixServer.reset(new SocketServer); - if (!mUnixServer->listenFD(fds[0])) - mUnixServer.reset(); - } - - free(fds); - if (!mUnixServer) - return false; - mUnixServer->newConnection().connect(std::bind(&Server::onNewConnection, this, std::placeholders::_1)); - return true; - } -#endif - - char *listenFds = getenv("LISTEN_FDS"); - if (listenFds != NULL) { - auto numFDs = atoi(listenFds); - if (numFDs != 1) { - error("Unexpected number of sockets from systemd: %d", numFDs); - return false; - } - - mUnixServer.reset(new SocketServer); - - if (!mUnixServer->listenFD(3)) { - return false; - } - - mUnixServer->newConnection().connect(std::bind(&Server::onNewConnection, this, std::placeholders::_1)); - return true; - } - - for (int i=0; i<10; ++i) { - mUnixServer.reset(new SocketServer); - warning() << "listening" << mOptions.socketFile; - if (mUnixServer->listen(mOptions.socketFile)) { - break; - } - mUnixServer.reset(); - if (!i) { - enum { Timeout = 1000 }; - std::shared_ptr connection = Connection::create(RClient::NumOptions); - if (connection->connectUnix(mOptions.socketFile, Timeout)) { - connection->send(QuitMessage()); - connection->disconnected().connect(std::bind([](){ EventLoop::eventLoop()->quit(); })); - connection->finished().connect(std::bind([](){ EventLoop::eventLoop()->quit(); })); - EventLoop::eventLoop()->exec(Timeout); - } - } else { - sleep(1); - } - Path::rm(mOptions.socketFile); - } - if (!mUnixServer) - return false; - mUnixServer->newConnection().connect(std::bind(&Server::onNewConnection, this, std::placeholders::_1)); - - return true; -} - -std::shared_ptr Server::addProject(const Path &path) -{ - std::shared_ptr &project = mProjects[path]; - if (!project) { - project.reset(new Project(path)); - if (!project->init()) { - Path::rmdir(project->projectDataDir()); - } - } - return project; -} - -void Server::onNewConnection(SocketServer *server) -{ - while (true) { - SocketClient::SharedPtr client = server->nextConnection(); - if (!client) { - break; - } - std::shared_ptr conn = Connection::create(client, RClient::NumOptions); - if (mOptions.maxSocketWriteBufferSize) { - client->setMaxWriteBufferSize(mOptions.maxSocketWriteBufferSize); - } - conn->setErrorHandler([](const SocketClient::SharedPtr &, Message::MessageError &&error) { - if (error.type == Message::Message_VersionError) { - ::error("Wrong version marker. You're probably using mismatched versions of rc and rdm"); - } else { - logDirect(LogLevel::Error, error.text); - } - }); - conn->newMessage().connect(std::bind(&Server::onNewMessage, this, std::placeholders::_1, std::placeholders::_2)); - mConnections.insert(conn); - std::weak_ptr weak = conn; - conn->disconnected().connect(std::bind([this, weak]() { - if (std::shared_ptr c = weak.lock()) { - c->disconnected().disconnect(); - mConnections.remove(c); - } - })); - } -} - -void Server::onNewMessage(const std::shared_ptr &message, const std::shared_ptr &connection) -{ - switch (message->messageId()) { - case IndexMessage::MessageId: - handleIndexMessage(std::static_pointer_cast(message), connection); - break; - case QueryMessage::MessageId: - handleQueryMessage(std::static_pointer_cast(message), connection); - break; - case QuitMessage::MessageId: - mExitCode = std::static_pointer_cast(message)->exitCode(); - EventLoop::eventLoop()->quit(); - connection->finish("Shutting down"); - break; - case IndexDataMessage::MessageId: - handleIndexDataMessage(std::static_pointer_cast(message), connection); - break; - case LogOutputMessage::MessageId: { - auto msg = std::static_pointer_cast(message); - logDirect(LogLevel::Error, msg->commandLine(), LogOutput::StdOut|LogOutput::TrailingNewLine); - handleLogOutputMessage(msg, connection); - break; } - case VisitFileMessage::MessageId: - handleVisitFileMessage(std::static_pointer_cast(message), connection); - break; - case ResponseMessage::MessageId: - case FinishMessage::MessageId: - case VisitFileResponseMessage::MessageId: - error() << "Unexpected message" << static_cast(message->messageId()); - // assert(0); - connection->finish(RTags::UnexpectedMessageError); - break; - default: - error("Unknown message: %d", message->messageId()); - connection->finish(RTags::UnknownMessageError); - break; - } - if ((mOptions.options & (NoFileManagerWatch|NoFileManager)) == NoFileManagerWatch) { - std::shared_ptr project = currentProject(); - if (project && project->fileManager() && (Rct::monoMs() - project->fileManager()->lastReloadTime()) > 60000) - project->fileManager()->load(FileManager::Asynchronous); - } -} - -String Server::guessArguments(const String &args, const Path &pwd, const Path &projectRootOverride) const -{ - Set includePaths; - List ret; - bool hasInput = false; - Set roots; - if (!projectRootOverride.isEmpty()) - roots.insert(projectRootOverride.ensureTrailingSlash()); - ret << "/usr/bin/g++"; // this should be clang on mac - const List split = args.split(" "); - for (size_t i=0; i process = [&](const Path &root, const Path &path) { - for (const Path &maybeHeader : path.files(Path::File)) { - if (maybeHeader.isHeader()) { - Path p = path; - do { - assert(!p.isEmpty()); - if (!includePaths.insert(p) || p == root) - break; - p = p.parentDir(); - } while (!p.isEmpty()); - break; - } - } - for (const Path &dir : path.files(Path::Directory)) { - process(root, dir); - } - }; - - for (const Path &root : roots) - process(root, root); - for (const Path &p : includePaths) { - assert(!p.isEmpty()); - ret << ("-I" + p); - } - - return String::join(ret, ' '); -} - -bool Server::loadCompileCommands(IndexParseData &data, const Path &compileCommands, const List &environment, SourceCache *cache) const -{ - if (Sandbox::hasRoot() && !data.project.isEmpty() && !data.project.startsWith(Sandbox::root())) { - error("Invalid --project-root '%s', must be inside --sandbox-root '%s'", - data.project.constData(), Sandbox::root().constData()); - return false; - } - - CXCompilationDatabase_Error err; - CXCompilationDatabase db = clang_CompilationDatabase_fromDirectory(compileCommands.parentDir().constData(), &err); - if (err != CXCompilationDatabase_NoError) { - error("Can't load compilation database from %s", compileCommands.constData()); - return false; - } - const uint32_t fileId = Location::insertFile(compileCommands); - bool ret = false; - CXCompileCommands cmds = clang_CompilationDatabase_getAllCompileCommands(db); - const unsigned int sz = clang_CompileCommands_getSize(cmds); - auto &ref = data.compileCommands[fileId]; - ref.environment = environment; - ref.lastModifiedMs = compileCommands.lastModifiedMs(); - for (unsigned int i = 0; i < sz; ++i) { - CXCompileCommand cmd = clang_CompileCommands_getCommand(cmds, i); - String args; - CXString str = clang_CompileCommand_getDirectory(cmd); - Path compileDir = clang_getCString(str); - if (!compileDir.isAbsolute() || !compileDir.exists()) { - bool resolveOk = false; - debug() << "compileDir doesn't exist: " << compileDir; - Path resolvedCompileDir = compileDir.resolved(Path::MakeAbsolute, data.project, &resolveOk); - if (resolveOk) { - compileDir = resolvedCompileDir; - debug() << " resolved to: " << compileDir; - } - } - clang_disposeString(str); - const unsigned int num = clang_CompileCommand_getNumArgs(cmd); - for (unsigned int j = 0; j < num; ++j) { - str = clang_CompileCommand_getArg(cmd, j); - const char *ch = clang_getCString(str); - if (strchr(ch, ' ')) { - args += '"'; - args += ch; - args += '"'; - } else { - args += ch; - } - clang_disposeString(str); - if (j < num - 1) - args += ' '; - } - ret = parse(data, std::move(args), compileDir.ensureTrailingSlash(), fileId, cache) || ret; - } - clang_CompileCommands_dispose(cmds); - clang_CompilationDatabase_dispose(db); - if (!ret) { - data.compileCommands.remove(fileId); - } - return ret; -} - -bool Server::parse(IndexParseData &data, String &&arguments, const Path &pwd, uint32_t compileCommandsFileId, SourceCache *cache) const -{ - if (Sandbox::hasRoot() && !data.project.isEmpty() && !data.project.startsWith(Sandbox::root())) { - error("Invalid --project-root '%s', must be inside --sandbox-root '%s'", - data.project.constData(), Sandbox::root().constData()); - return false; - } - - assert(pwd.endsWith('/')); - List unresolvedPaths; - if (!mOptions.argTransform.isEmpty()) { - Process process; - if (process.exec(mOptions.argTransform, List() << arguments) == Process::Done) { - if (process.returnCode() != 0) { - warning() << "--arg-transform returned" << process.returnCode() << "for" << arguments; - return false; - } - String stdOut = process.readAllStdOut(); - if (!stdOut.isEmpty() && stdOut != arguments) { - warning() << "Changed\n" << arguments << "\nto\n" << stdOut; - arguments = std::move(stdOut); - } - } - } - - assert(!compileCommandsFileId || data.compileCommands.contains(compileCommandsFileId)); - const auto &env = compileCommandsFileId ? data.compileCommands[compileCommandsFileId].environment : data.environment; - SourceList sources = Source::parse(arguments, pwd, env, &unresolvedPaths, cache); - bool ret = (sources.isEmpty() && unresolvedPaths.size() == 1 && unresolvedPaths.front() == "-"); - size_t idx = 0; - for (Source &source : sources) { - const Path path = source.sourceFile(); - - std::shared_ptr current = currentProject(); - if (data.project.isEmpty()) { - const Path unresolvedPath = unresolvedPaths.at(idx++); - if (current && (current->match(unresolvedPath) || (path != unresolvedPath && current->match(path)))) { - data.project = current->path(); - } else { - for (const auto &proj : mProjects) { - if (proj.second->match(unresolvedPath) || (path != unresolvedPath && proj.second->match(path))) { - data.project = proj.first; - break; - } - } - } - - if (data.project.isEmpty()) { - data.project = RTags::findProjectRoot(unresolvedPath, RTags::SourceRoot, cache); - if (data.project.isEmpty() && path != unresolvedPath) { - data.project = RTags::findProjectRoot(path, RTags::SourceRoot, cache); - } - } - data.project.resolve(Path::RealPath, pwd); - } - - if (shouldIndex(source, data.project)) { - Sources &s = compileCommandsFileId ? data.compileCommands[compileCommandsFileId].sources : data.sources; - source.compileCommandsFileId = compileCommandsFileId; - auto &list = s[source.fileId]; - if (!list.contains(source)) - list.append(source); - ret = true; - } - } - return ret; -} - -void Server::handleIndexMessage(const std::shared_ptr &message, const std::shared_ptr &conn) -{ - const Path path = message->compileCommands(); - IndexParseData data; - data.project = message->projectRoot(); - bool ret = true; - if (!path.isEmpty()) { - SourceCache cache; - if (loadCompileCommands(data, path, message->environment(), &cache)) { - if (conn) - conn->write("[Server] Compilation database loading..."); - } else if (conn) { - ret = false; - conn->write("[Server] Compilation failed to load."); - } - } else { - data.environment = std::move(message->takeEnvironment()); - String arguments = std::move(message->takeArguments()); - if (message->flags() & IndexMessage::GuessFlags) { - arguments = guessArguments(arguments, message->workingDirectory(), data.project); - if (arguments.isEmpty()) { - conn->write("Can't guess args from arguments"); - ret = false; - } - } - if (ret) - ret = parse(data, std::move(arguments), message->workingDirectory()); - } - if (conn) - conn->finish(ret ? 0 : 1); - if (ret) { - auto proj = addProject(data.project); - if (proj) { - assert(proj); - proj->processParseData(std::move(data)); - if (!currentProject()) - setCurrentProject(proj); - } - } -} - -void Server::handleLogOutputMessage(const std::shared_ptr &message, const std::shared_ptr &conn) -{ - auto log = std::make_shared(message->level(), message->flags(), conn); - log->add(); -} - -void Server::handleIndexDataMessage(const std::shared_ptr &message, const std::shared_ptr &conn) -{ - mJobScheduler->handleIndexDataMessage(message); - conn->finish(); - mIndexDataMessageReceived(); -} - -void Server::handleQueryMessage(const std::shared_ptr &message, const std::shared_ptr &conn) -{ - Log(message->flags() & QueryMessage::SilentQuery ? LogLevel::Warning : LogLevel::Error, - LogOutput::StdOut|LogOutput::TrailingNewLine) << message->commandLine(); - conn->setSilent(message->flags() & QueryMessage::Silent); - - switch (message->type()) { - case QueryMessage::Invalid: - assert(0); - break; - case QueryMessage::Sources: - sources(message, conn); - break; - case QueryMessage::IncludeFile: - includeFile(message, conn); - break; - case QueryMessage::GenerateTest: - generateTest(message, conn); - break; - case QueryMessage::DumpCompletions: - dumpCompletions(message, conn); - break; - case QueryMessage::DumpCompileCommands: - dumpCompileCommands(message, conn); - break; - case QueryMessage::SendDiagnostics: - sendDiagnostics(message, conn); - break; - case QueryMessage::CodeCompleteAt: - codeCompleteAt(message, conn); - break; - case QueryMessage::Suspend: - suspend(message, conn); - break; - case QueryMessage::IsIndexing: - isIndexing(message, conn); - break; - case QueryMessage::LastIndexed: - lastIndexed(message, conn); - break; - case QueryMessage::RemoveFile: - removeFile(message, conn); - break; - case QueryMessage::JobCount: - jobCount(message, conn); - break; - case QueryMessage::FixIts: - fixIts(message, conn); - break; - case QueryMessage::FindFile: - findFile(message, conn); - break; - case QueryMessage::DumpFile: -#ifdef RTAGS_HAS_LUA - case QueryMessage::VisitAST: -#endif - startClangThread(message, conn); - break; - case QueryMessage::Validate: - validate(message, conn); - break; - case QueryMessage::DumpFileMaps: - dumpFileMaps(message, conn); - break; - case QueryMessage::Diagnose: - diagnose(message, conn); - break; - case QueryMessage::Dependencies: - dependencies(message, conn); - break; - case QueryMessage::DeleteProject: - removeProject(message, conn); - break; - case QueryMessage::Project: - project(message, conn); - break; - case QueryMessage::Reindex: - case QueryMessage::CheckReindex: - reindex(message, conn); - break; - case QueryMessage::ClearProjects: - clearProjects(message, conn); - break; - case QueryMessage::SymbolInfo: - symbolInfo(message, conn); - break; - case QueryMessage::FollowLocation: - followLocation(message, conn); - break; - case QueryMessage::ReferencesLocation: - referencesForLocation(message, conn); - break; - case QueryMessage::ReferencesName: - referencesForName(message, conn); - break; - case QueryMessage::ListSymbols: - listSymbols(message, conn); - break; - case QueryMessage::FindSymbols: - findSymbols(message, conn); - break; - case QueryMessage::Status: - status(message, conn); - break; - case QueryMessage::IsIndexed: - isIndexed(message, conn); - break; - case QueryMessage::HasFileManager: - hasFileManager(message, conn); - break; - case QueryMessage::PreprocessFile: - preprocessFile(message, conn); - break; - case QueryMessage::ReloadFileManager: - reloadFileManager(message, conn); - break; - case QueryMessage::SetBuffers: - setBuffers(message, conn); - break; - case QueryMessage::ClassHierarchy: - classHierarchy(message, conn); - break; - case QueryMessage::DebugLocations: - debugLocations(message, conn); - break; - case QueryMessage::Tokens: - tokens(message, conn); - break; - } -} - -void Server::followLocation(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Location loc = query->location(); - if (loc.isNull()) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - std::shared_ptr project = projectForQuery(query); - if (!project) { - error("No project"); - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - prepareCompletion(query, loc.fileId(), project); - - { - FollowLocationJob job(loc, query, project); - if (!job.run(conn)) { - conn->finish(); - return; - } - } - - /* We will try with another project under the following circumstances: - - - We didn't find anything with the current project - - The path in question (likely a header) does not start with the current - project's path (there's room for mistakes here with symlinks). - - The file in question does start with another project's path - */ - - const Path path = loc.path(); - if (!path.startsWith(project->path())) { - for (const auto &proj : mProjects) { - if (proj.second != project) { - Path paths[] = { proj.first, proj.first }; - paths[1].resolve(); - for (const Path &projectPath : paths) { - if (path.startsWith(projectPath)) { - FollowLocationJob job(loc, query, proj.second); - if (job.run(conn)) { - conn->finish(); - return; - } - } - } - } - } - } - if (!project->dependencies().contains(loc.fileId())) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - } else { - conn->finish(RTags::GeneralFailure); - } -} - -void Server::lastIndexed(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - // Path path = query->path(); - const Match match = query->match(); - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - - if (!project) { - error("No project"); - conn->finish(); - return; - } - - conn->write<128>("%ld", project->lastIdleTime()); - conn->finish(); -} - -void Server::isIndexing(const std::shared_ptr &, const std::shared_ptr &conn) -{ - for (const auto &it : mProjects) { - if (it.second->isIndexing()) { - conn->write("1"); - conn->finish(); - return; - } - } - conn->write("0"); - conn->finish(); -} - -void Server::removeFile(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - // Path path = query->path(); - const Match match = query->match(); - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - - if (!project) { - error("No project"); - conn->finish(); - return; - } - - const int count = project->remove(match); - // error() << count << query->query(); - if (count) { - conn->write<128>("Removed %d files", count); - } else { - conn->write("No matches"); - } - conn->finish(); -} - -void Server::findFile(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = currentProject(); - if (!project) { - error("No project"); - conn->finish(); - return; - } - - FindFileJob job(query, project); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::startClangThread(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const uint32_t fileId = Location::fileId(query->query()); - if (!fileId) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - std::shared_ptr project = projectForQuery(query); - if (!project) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - if (!project->dependencies().contains(fileId)) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - const Source source = project->source(fileId, query->buildIndex()); - if (!source.isNull()) { - ClangThread *thread = new ClangThread(query, source, conn); - thread->start(Thread::Normal, 8 * 1024 * 1024); // 8MiB stack size - } else { - conn->write<256>("%s build: %d not found", query->query().constData(), query->buildIndex()); - conn->finish(); - } -} - -void Server::dumpFileMaps(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - Path path; - Deserializer deserializer(query->query()); - deserializer >> path; - const uint32_t fileId = Location::fileId(path); - if (!fileId) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - std::shared_ptr project; - if (currentProject() && currentProject()->isIndexed(fileId)) { - project = currentProject(); - } else { - for (const auto &p : mProjects) { - if (p.second->isIndexed(fileId)) { - project = p.second; - setCurrentProject(project); - break; - } - } - } - if (!project) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - project->dumpFileMaps(query, conn); - conn->finish(); -} - -void Server::diagnose(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - uint32_t fileId = 0; - if (!query->query().isEmpty()) { - fileId = Location::fileId(query->query()); - if (!fileId) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - } - - std::shared_ptr project = projectForQuery(query); - if (!project) { - if (!fileId) - project = mCurrentProject.lock(); - if (!project) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - } - - if (fileId) - prepareCompletion(query, fileId, project); - - if (query->flags() & QueryMessage::SynchronousDiagnostics) { - conn->write(project->diagnosticsToString(query->flags(), fileId)); - } else { - project->diagnose(fileId); - } - conn->finish(); -} - -void Server::generateTest(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - auto formatLocation = [](Location location) { - return String::format<1024>("{0}/%s:%d:%d:", - location.path().fileName(), - location.line(), - location.column()); - }; - const uint32_t fileId = Location::fileId(query->query()); - if (!fileId) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - std::shared_ptr project = projectForQuery(query); - if (!project) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - Project::FileMapScopeScope scope(project); - - const Source source = project->source(fileId, query->buildIndex()); - if (!source.isNull()) { - const Flags flags = (Source::Default - | Source::ExcludeDefaultDefines - | Source::ExcludeDefaultIncludePaths - | Source::ExcludeDefaultArguments); - - const Path root = source.sourceFile().parentDir().ensureTrailingSlash(); - List compile = source.toCommandLine(flags); - for (auto &ref : compile) { - const int idx = ref.indexOf(root); - if (idx != -1) - ref.remove(idx, root.size()); - } - compile.append(source.sourceFile().fileName()); - - Value tests; - - for (const auto &dep : project->dependencies()) { - auto symbols = project->openSymbols(dep.first); - if (!symbols) - continue; - const int count = symbols->count(); - for (int i=0; ikeyAt(i); - const Symbol target = project->findTarget(loc); - if (!target.isNull()) { - Map test; - test["name"] = "follow_symbol"; - List rcCommand; - rcCommand << "--follow-location" << formatLocation(loc); - test["rc-command"] = rcCommand; - List expectation; - expectation << formatLocation(target.location); - test["expectation"] = expectation; - tests.push_back(test); - } - } - } - if (tests.isNull()) { - conn->finish("No tests generated"); - } else { - conn->finish(tests.toJSON(true)); - } - } else { - conn->write<256>("%s build: %d not found", query->query().constData(), query->buildIndex()); - conn->finish(); - } -} - -void Server::symbolInfo(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const String data = query->query(); - Deserializer deserializer(data); - Path path; - uint32_t line, column, line2, column2; - Set kinds; // This is serialized as a of List - deserializer >> path >> line >> column >> line2 >> column2 >> kinds; - uint32_t fileId = Location::fileId(path); - if (!fileId) { - path.resolve(); - fileId = Location::fileId(path); - if (!fileId) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - } - - std::shared_ptr project = projectForQuery(query); - if (!project) { - List matches; - matches << path; - project = projectForMatches(matches); - } - if (!project || !project->dependencies().contains(fileId)) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - prepareCompletion(query, fileId, project); - - const Location start(fileId, line, column); - const Location end = line2 ? Location(fileId, line2, column2) : Location(); - - SymbolInfoJob job(start, end, std::move(kinds), query, project); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::dependencies(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - Path path; - Deserializer deserializer(query->query()); - deserializer >> path; - const uint32_t fileId = Location::fileId(path); - if (!fileId && !path.isEmpty()) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - std::shared_ptr project; - if (fileId) { - if (currentProject() && currentProject()->isIndexed(fileId)) { - project = currentProject(); - } else { - for (const auto &p : mProjects) { - if (p.second->isIndexed(fileId)) { - project = p.second; - setCurrentProject(project); - break; - } - } - } - } else { - project = currentProject(); - } - if (!project) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - DependenciesJob job(query, project); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::fixIts(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - String out; - if (project) { - uint32_t fileId = Location::fileId(query->query()); - if (fileId) { - prepareCompletion(query, fileId, project); - out = project->fixIts(fileId); - if (!out.isEmpty()) - conn->write(out); - } - } - conn->finish(); -} - -void Server::referencesForLocation(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Location loc = query->location(); - if (loc.isNull()) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - std::shared_ptr project = projectForQuery(query); - - if (!project) { - error("No project"); - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - prepareCompletion(query, loc.fileId(), project); - - if (!project->dependencies().contains(loc.fileId())) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - ReferencesJob job(loc, query, project); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::referencesForName(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const String name = query->query(); - - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - - if (!project) { - error("No project"); - conn->finish(); - return; - } - - ReferencesJob job(name, query, project); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::findSymbols(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const String partial = query->query(); - - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - - int ret = 0; - if (!project) { - ret = 1; - error("No project"); - } else { - FindSymbolsJob job(query, project); - ret = job.run(conn); - } - conn->finish(ret); -} - -void Server::listSymbols(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const String partial = query->query(); - - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - - if (!project) { - error("No project"); - conn->finish(); - return; - } - - ListSymbolsJob job(query, project); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::status(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - conn->client()->setWriteMode(SocketClient::Synchronous); - - StatusJob job(query, currentProject()); - const int ret = job.run(conn); - conn->finish(ret); -} - -void Server::isIndexed(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - String ret = "unknown"; - const Match match = query->match(); - std::shared_ptr project = projectForQuery(query); - if (project) { - bool indexed = false; - if (project->match(match, &indexed)) { - if (indexed) { - project->prepare(match.fileId()); - prepareCompletion(query, match.fileId(), project); - } - ret = indexed ? "indexed" : "managed"; - } - } - - if (!(query->flags() & QueryMessage::SilentQuery)) - warning("=> %s", ret.constData()); - conn->write(ret); - conn->finish(); -} - -void Server::reloadFileManager(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - - if (project) { - if (mOptions.options & NoFileManager) { - conn->write<512>("Not watching files"); - conn->finish(RTags::GeneralFailure); - } else { - conn->write<512>("Reloading files for %s", project->path().constData()); - conn->finish(); - project->fileManager()->load(FileManager::Asynchronous); - } - } else { - conn->write("No current project"); - conn->finish(); - } -} - -void Server::hasFileManager(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Path path = query->query(); - std::shared_ptr project = projectForQuery(query); - if (project && (project->fileManager() ? project->fileManager()->contains(path) : project->match(query->match()))) { - if (!(query->flags() & QueryMessage::SilentQuery)) - warning("=> 1"); - conn->write("1"); - } else { - if (!(query->flags() & QueryMessage::SilentQuery)) - warning("=> 0"); - conn->write("0"); - } - conn->finish(); -} - -void Server::includeFile(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - if (!project) { - conn->write("No project"); - conn->finish(); - return; - } - - IncludeFileJob job(query, project); - conn->finish(job.run(conn)); -} - -void Server::preprocessFile(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - if (!project) { - conn->write("No project"); - conn->finish(); - return; - } - - Path path = query->query(); - uint32_t fileId = Location::fileId(path); - if (!fileId) { - path.resolve(); - fileId = Location::fileId(path); - } - if (fileId) - prepareCompletion(query, fileId, project); - const Source source = project->source(fileId, query->buildIndex()); - if (!source.isValid()) { - conn->write<256>("%s build: %d not found", query->query().constData(), query->buildIndex()); - conn->finish(); - } else { - Preprocessor *pre = new Preprocessor(source, conn); - pre->preprocess(); - } -} - -void Server::clearProjects(ClearMode mode) -{ - Path::rmdir(mOptions.dataDir); - setCurrentProject(std::shared_ptr()); - for (auto p : mProjects) { - p.second->destroy(); - } - mProjects.clear(); - if (mode == Clear_All) - Location::init(Hash()); -} - -void Server::reindex(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - Match match = query->match(); - std::shared_ptr project = projectForQuery(query); - if (!project) { - project = currentProject(); - if (!project) { - error("No project"); - conn->finish(); - return; - } - } - - std::shared_ptr wait; - if (query->flags() & QueryMessage::Wait) - wait = conn; - - const int count = project->reindex(match, query, wait); - // error() << count << query->query(); - if (count) { - conn->write<128>("Dirtied %d files", count); - } else { - conn->write("No matches"); - } - if (!wait) - conn->finish(); -} - -bool Server::shouldIndex(const Source &source, const Path &srcRoot) const -{ - if (srcRoot.isEmpty()) { - warning() << "Shouldn't index" << source.sourceFile() << "because of missing srcRoot"; - return false; - } - assert(source.isIndexable()); - if (mOptions.ignoredCompilers.contains(source.compiler())) { - warning() << "Shouldn't index" << source.sourceFile() << "because of ignored compiler"; - return false; - } - - const Path sourceFile = source.sourceFile(); - - if (Filter::filter(sourceFile, mOptions.excludeFilters) == Filter::Filtered) { - error() << "Shouldn't index" << source.sourceFile() << "because of exclude filter"; - return false; - } - - if (Sandbox::hasRoot() && !srcRoot.isEmpty() && !srcRoot.startsWith(Sandbox::root())) { - error("Invalid project root for %s '%s', must be inside --sandbox-root '%s'", - sourceFile.constData(), srcRoot.constData(), Sandbox::root().constData()); - return false; - } - - return true; -} - -void Server::setCurrentProject(const std::shared_ptr &project) -{ - std::shared_ptr old = currentProject(); - if (project != old) { - if (old && old->fileManager()) - old->fileManager()->clearFileSystemWatcher(); - mCurrentProject = project; - if (project) { - Path::mkdir(mOptions.dataDir); - FILE *f = fopen((mOptions.dataDir + ".currentProject").constData(), "w"); - if (f) { - Path p = project->path(); - RTags::encodePath(p); - if (!fwrite(p.constData(), p.size(), 1, f) || !fwrite("\n", 1, 1, f)) { - error() << "error writing to" << (mOptions.dataDir + ".currentProject"); - fclose(f); - unlink((mOptions.dataDir + ".currentProject").constData()); - } else { - fclose(f); - } - } else { - error() << "error opening" << (mOptions.dataDir + ".currentProject") << "for write"; - } - if (!(mOptions.options & NoFileManager)) - project->fileManager()->load(FileManager::Asynchronous); - mJobScheduler->sort(); - // project->diagnoseAll(); - } else { - Path::rm(mOptions.dataDir + ".currentProject"); - } - } -} - -std::shared_ptr Server::projectForQuery(const std::shared_ptr &query) -{ - List matches; - if (query->flags() & QueryMessage::HasLocation) - matches << query->location().path(); - if (!query->currentFile().isEmpty()) - matches << query->currentFile(); - if (!(query->flags() & QueryMessage::HasLocation)) - matches << query->match(); - - return projectForMatches(matches); -} - -std::shared_ptr Server::projectForMatches(const List &matches) -{ - std::shared_ptr cur = currentProject(); - // give current a chance first to avoid switching project when using system headers etc - for (const Match &match : matches) { - if (cur && cur->match(match)) - return cur; - - for (const auto &it : mProjects) { - if (it.second != cur && it.second->match(match)) { - setCurrentProject(it.second); - return it.second; - } - } - } - return std::shared_ptr(); -} - -void Server::removeProject(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Match match = query->match(); - auto it = mProjects.begin(); - bool found = false; - while (it != mProjects.end()) { - auto cur = it++; - if (cur->second->match(match)) { - found = true; - if (currentProject() == cur->second) { - setCurrentProject(std::shared_ptr()); - } - Path path = cur->first; - conn->write<128>("Deleted project: %s", path.constData()); - RTags::encodePath(path); - Path::rmdir(mOptions.dataDir + path); - warning() << "Deleted" << (mOptions.dataDir + path); - cur->second->destroy(); - mProjects.erase(cur); - } - } - if (!found) { - conn->write<128>("No projects matching %s", match.pattern().constData()); - } - conn->finish(); -} - -void Server::project(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - if (project) { - setCurrentProject(project); - } - - if (project || query->flags() & QueryMessage::CurrentProjectOnly) { - if (std::shared_ptr current = currentProject()) { - conn->write(current->path()); - } - } else if (query->query().isEmpty()) { - const std::shared_ptr current = currentProject(); - for (const auto &it : mProjects) { - conn->write<128>("%s%s", it.first.constData(), it.second == current ? " <=" : ""); - } - } else { - std::shared_ptr selected; - bool error = false; - const Match match = query->match(); - const auto it = mProjects.find(match.pattern()); - bool ok = false; - unsigned long long index = query->query().toULongLong(&ok); - if (it != mProjects.end()) { - selected = it->second; - } else { - if (ok) { - if (index < mProjects.size()) { - selected = std::next(mProjects.cbegin(), index)->second; - assert(selected); - } - } - if (!selected) { - for (const auto &pit : mProjects) { - assert(pit.second); - if (pit.second->match(match)) { - if (error) { - conn->write(pit.first); - } else if (selected) { - error = true; - conn->write<128>("Multiple matches for %s", match.pattern().constData()); - conn->write(selected->path()); - conn->write(pit.first); - selected.reset(); - } else { - selected = pit.second; - } - } - } - } - } - if (selected) { - if (selected == currentProject()) { - conn->write<128>("%s is already the active project", selected->path().constData()); - } else { - setCurrentProject(selected); - conn->write<128>("Selected project: %s for %s", - selected->path().constData(), - match.pattern().constData()); - } - } else if (!error) { - conn->write<128>("No matches for %s", match.pattern().constData()); - } - } - conn->finish(); -} - -void Server::jobCount(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - String q = query->query(); - if (q.isEmpty()) { - conn->write<128>("Running with %zu/%zu jobs", mOptions.jobCount, mOptions.headerErrorJobCount); - } else { - const bool header = q.startsWith('h'); - if (header) - q.remove(0, 1); - size_t &jobs = header ? mOptions.headerErrorJobCount : mOptions.jobCount; - int jobCount; - bool ok; - if (q == "default") { - ok = true; - jobCount = header ? mOptions.jobCount : std::max(2, ThreadPool::idealThreadCount()); - } else { - jobCount = q.toLongLong(&ok); - } - if (!ok || jobCount < 0 || jobCount > 100) { - conn->write<128>("Invalid job count %s (%d)", query->query().constData(), jobCount); - } else { - if (mOptions.headerErrorJobCount == mOptions.jobCount) { - mOptions.headerErrorJobCount = mOptions.jobCount = jobCount; - } else { - jobs = jobCount; - mOptions.headerErrorJobCount = std::min(mOptions.headerErrorJobCount, mOptions.jobCount); - } - conn->write<128>("Changed jobs to %zu/%zu", mOptions.jobCount, mOptions.headerErrorJobCount); - } - } - conn->finish(); -} - -void Server::sendDiagnostics(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - if (testLog(RTags::DiagnosticsLevel)) - logDirect(RTags::DiagnosticsLevel, query->query()); - conn->finish(); -} - -void Server::clearProjects(const std::shared_ptr &/*query*/, const std::shared_ptr &conn) -{ - clearProjects(Clear_All); - conn->write("Cleared projects"); - conn->finish(); -} - -void Server::sources(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Path path = query->query(); - const bool flagsOnly = query->flags() & QueryMessage::CompilationFlagsOnly; - const bool splitLine = query->flags() & QueryMessage::CompilationFlagsSplitLine; - const bool pwd = query->flags() & QueryMessage::CompilationFlagsPwd; - auto format = [flagsOnly, splitLine, pwd](const Source &source) { - String ret; - if (pwd) - ret += "pwd: " + source.directory + "\n"; - if (flagsOnly) { - const Flags flags = (Source::Default - |Source::ExcludeDefaultArguments - |Source::IncludeCompiler - |Source::IncludeSourceFile - |Source::ExcludeDefaultIncludePaths); - ret += String::join(source.toCommandLine(flags), splitLine ? '\n' : ' '); - } else if (splitLine) { - ret += String::join(source.toString().split(' '), '\n'); - } else { - ret += source.toString(); - } - return ret; - }; - if (path.isFile()) { - std::shared_ptr project = projectForQuery(query); - if (project) { - const uint32_t fileId = Location::fileId(path); - if (fileId) { - prepareCompletion(query, fileId, project); - SourceList sources = project->sources(fileId); - if (sources.isEmpty() && path.isHeader()) { - Set seen; - std::function findSourceFileId = [&findSourceFileId, &project, &seen](uint32_t file) { - DependencyNode *node = project->dependencyNode(file); - uint32_t ret = 0; - if (node) { - for (const auto &dep : node->dependents) { - if (!seen.insert(dep.first)) - continue; - - if (Location::path(dep.first).isSource()) { - ret = dep.first; - break; - } else { - ret = findSourceFileId(dep.first); - if (ret) - break; - } - } - } - return ret; - }; - - const uint32_t source = findSourceFileId(fileId); - sources = project->sources(source); - if (sources.size() > 1) { - auto it = sources.begin(); - ++it; - while (it != sources.end()) { - sources.erase(it++); - } - } - } - int idx = 0; - for (const auto &src : sources) { - String out; - if (sources.size() > 1) - out = String::format<4>("%d: ", idx); - conn->write(format(src)); - } - } - conn->finish(); - return; - } - } - - if (std::shared_ptr project = currentProject()) { - if (query->flags() & (QueryMessage::CompilationFlagsOnly|QueryMessage::CompilationFlagsSplitLine|QueryMessage::CompilationFlagsPwd)) { - project->forEachSource([&conn, &format](const Source &source) { return conn->write(format(source)) ? Project::Continue : Project::Stop; }); - } else { - project->indexParseData().write([&conn](const String &str) { return conn->write(str); }); - } - } else { - conn->write("No project"); - } - conn->finish(); -} - -void Server::dumpCompletions(const std::shared_ptr &/*query*/, const std::shared_ptr &conn) -{ - if (mCompletionThread) { - conn->write(mCompletionThread->dump()); - } else { - conn->write("No completions"); - } - conn->finish(); -} - -void Server::dumpCompileCommands(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - if (!project) - project = currentProject(); - if (!project) { - conn->write("No current project"); - conn->finish(RTags::GeneralFailure); - return; - } - - conn->write(project->toCompileCommands()); - conn->finish(); -} - -void Server::suspend(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - Path p; - String modeString; - const String pattern = query->match().pattern(); - Deserializer deserializer(pattern); - deserializer >> p >> modeString; - enum Mode { - ListFiles, - All, - Clear, - FileToggle, - FileOn, - FileOff - } mode = ListFiles; - if (p == "clear") { - mode = Clear; - assert(modeString.isEmpty()); - } else if (p == "all") { - mode = All; - assert(modeString.isEmpty()); - } else if (!p.isEmpty()) { - if (modeString == "on") { - mode = FileOn; - } else if (modeString == "off") { - mode = FileOff; - } else { - mode = FileToggle; - } - } - - List matches; - if (!query->currentFile().isEmpty()) - matches.push_back(query->currentFile()); - if (mode == FileOn || mode == FileOff || mode == FileToggle) - matches.push_back(p); - std::shared_ptr project; - if (matches.isEmpty()) { - project = currentProject(); - } else { - project = projectForMatches(matches); - } - - const bool old = mSuspended; - switch (mode) { - case All: - mSuspended = true; - conn->write("All files are suspended."); - break; - case Clear: - mSuspended = false; - if (project) - project->clearSuspendedFiles(); - conn->write("No files suspended."); - break; - case ListFiles: - if (mSuspended) - conn->write("All files are suspended."); - if (project) { - const Set suspendedFiles = project->suspendedFiles(); - if (suspendedFiles.isEmpty()) { - conn->write<512>("No files suspended for project %s", project->path().constData()); - } else { - for (const auto &it : suspendedFiles) - conn->write<512>("%s is suspended", Location::path(it).constData()); - } - } - break; - case FileOn: - case FileOff: - case FileToggle: - if (!project) { - conn->write("No project"); - } else if (!p.isFile()) { - conn->write<512>("%s doesn't seem to exist", p.constData()); - } else { - const uint32_t fileId = Location::fileId(p); - if (fileId) { - bool suspended = false; - switch (mode) { - case FileToggle: suspended = project->toggleSuspendFile(fileId); break; - case FileOff: suspended = false; project->setSuspended(fileId, false); break; - case FileOn: suspended = true; project->setSuspended(fileId, true); break; - default: assert(0); - } - conn->write<512>("%s is no%s suspended", p.constData(), - suspended ? "w" : " longer"); - } else { - conn->write<512>("%s is not indexed", p.constData()); - } - } - break; - } - conn->finish(); - - if (old && !mSuspended) - mJobScheduler->startJobs(); -} - -void Server::setBuffers(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const String encoded = query->query(); - if (encoded.isEmpty()) { - for (uint32_t fileId : mActiveBuffers) { - conn->write(Location::path(fileId)); - } - } else { - mHadActiveBuffers = true; - Deserializer deserializer(encoded); - int mode; - deserializer >> mode; - List paths; - deserializer >> paths; - const size_t oldCount = mActiveBuffers.size(); - if (mode == 0 || mode == 1) { - if (mode == 0) - mActiveBuffers.clear(); - for (const Path &path : paths) { - if (uint32_t fileId = Location::insertFile(path)) - mActiveBuffers.insert(fileId); - } - } else { - assert(mode == -1); - for (const Path &path : paths) { - mActiveBuffers.remove(Location::insertFile(path)); - } - } - if (oldCount < mActiveBuffers.size()) { - conn->write<32>("Added %zu buffers", mActiveBuffers.size() - oldCount); - } else if (oldCount > mActiveBuffers.size()) { - conn->write<32>("Removed %zu buffers", oldCount - mActiveBuffers.size()); - } else { - conn->write<32>("We still have %zu buffers", oldCount); - } - - if (mOptions.options & TranslationUnitCache && mode <= 0) { - const Path cacheDir = mOptions.dataDir + "tucache"; - cacheDir.visit([this](const Path &path) -> Path::VisitResult { - if (path.isFile() && !mActiveBuffers.contains(std::stol(path.fileName()))) { - error() << "Don't want" << path << "no more" << Location::path(std::stol(path.fileName())); - Path::rm(path); - } - return Path::Continue; - }); - } - } - mJobScheduler->sort(); - conn->finish(); -} - -void Server::classHierarchy(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Location loc = query->location(); - if (loc.isNull()) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - std::shared_ptr project = projectForQuery(query); - if (!project) { - error("No project"); - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - if (!project->dependencies().contains(loc.fileId())) { - conn->write("Not indexed"); - conn->finish(RTags::NotIndexed); - return; - } - - ClassHierarchyJob job(loc, query, project); - conn->finish(job.run(conn)); -} - -void Server::debugLocations(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const String str = query->query(); - if (str == "clear" || str == "none") { - mOptions.debugLocations.clear(); - } else if (str == "all" || str == "*") { - mOptions.debugLocations.clear(); - mOptions.debugLocations << "all"; - } else if (!str.isEmpty()) { - mOptions.debugLocations << str; - } - if (mOptions.debugLocations.isEmpty()) { - conn->write("No debug locations"); - } else { - conn->write<1024>("Debug locations:\n%s", String::join(mOptions.debugLocations, '\n').constData()); - } - conn->finish(); -} - - -void Server::tokens(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - Path path; - uint32_t from, to; - Deserializer deserializer(query->query()); - deserializer >> path >> from >> to; - const uint32_t fileId = Location::fileId(path); - if (!fileId) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - std::shared_ptr project; - if (currentProject() && currentProject()->isIndexed(fileId)) { - project = currentProject(); - } else { - for (const auto &p : mProjects) { - if (p.second->isIndexed(fileId)) { - project = p.second; - setCurrentProject(project); - break; - } - } - } - if (!project) { - conn->write<256>("%s is not indexed", query->query().constData()); - conn->finish(); - return; - } - - TokensJob job(query, fileId, from, to, project); - conn->finish(job.run(conn)); -} - -void Server::validate(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - std::shared_ptr project = projectForQuery(query); - if (!project) - project = mCurrentProject.lock(); - if (!project) { - error("No project"); - conn->write("No current project"); - conn->finish(RTags::GeneralFailure); - return; - } - - project->validateAll(); - conn->finish(); -} - -void Server::handleVisitFileMessage(const std::shared_ptr &message, const std::shared_ptr &conn) -{ - uint32_t fileId = 0; - bool visit = false; - - std::shared_ptr project = mProjects.value(message->project()); - const uint32_t id = message->sourceFileId(); - if (project && project->isActiveJob(id)) { - assert(message->file() == message->file().resolved()); - fileId = Location::insertFile(message->file()); - visit = project->visitFile(fileId, message->file(), id); - } - VisitFileResponseMessage msg(fileId, visit); - conn->send(msg); -} - -bool Server::load() -{ - DataFile fileIdsFile(mOptions.dataDir + "fileids", RTags::DatabaseVersion); - if (fileIdsFile.open(DataFile::Read)) { - Flags flags; - fileIdsFile >> flags; - if (flags & HasSandboxRoot && !Sandbox::hasRoot()) { - error() << ("This database was produced with --sandbox-root option using relative path. " - "You have to specify a sandbox-root argument or wipe the db by running with -C"); - return false; - } else if (Sandbox::hasRoot() && !(flags & HasSandboxRoot)) { - error() << ("This database was produced without --sandbox-root option using relative path. " - "You can't specify a sandbox-root argument for this db unless you start the db over by passing -C"); - return false; - } - - // SBROOT - Hash pathsToIds; - fileIdsFile >> pathsToIds; - - Sandbox::decode(pathsToIds); - - if (!Location::init(pathsToIds)) { - error() << "Corrupted file ids. You have to start over"; - clearProjects(Clear_All); - return true; - } - List projects = mOptions.dataDir.files(Path::Directory); - for (size_t i=0; i> version; - - if (version == RTags::DatabaseVersion) { - int fs; - in >> fs; - if (fs != Rct::fileSize(f)) { - error("%s seems to be corrupted, refusing to restore. Removing.", - file.constData()); - remove = true; - } else { - addProject(filePath.ensureTrailingSlash()); - } - } else { - remove = true; - error() << file << "has wrong format. Got" << version << "expected" << RTags::DatabaseVersion << "Removing"; - } - fclose(f); - } - if (remove) { - Path::rm(file); - } - } - } - } else { - if (!fileIdsFile.error().isEmpty()) { - error("Can't restore file ids: %s", fileIdsFile.error().constData()); - } - Hash projects; - mOptions.dataDir.visit([&projects](const Path &path) { - if (path.isDir()) { - Path sources = path + "sources"; - if (sources.exists()) { - Path filePath = path.fileName(); - if (filePath.endsWith("/")) - filePath.chop(1); - RTags::decodePath(filePath); - if (!filePath.isEmpty()) { - String err; - IndexParseData data; - if (!Project::readSources(sources, data, &err)) { - error("Sources restore error %s: %s", path.constData(), err.constData()); - } else { - data.project = filePath; - projects[filePath] = std::move(data); - } - } - } - } - return Path::Continue; - }); - - clearProjects(Clear_KeepFileIds); - if (!projects.isEmpty()) { - error() << "Recovering sources" << projects.size(); - } - for (auto &s : projects) { - auto p = addProject(s.first); - if (p) { - p->processParseData(std::move(s.second)); - p->save(); - } - } - saveFileIds(); - } - return true; -} - -bool Server::saveFileIds() -{ - const uint32_t lastId = Location::lastId(); - if (mLastFileId == lastId) - return true; - DataFile fileIdsFile(mOptions.dataDir + "fileids", RTags::DatabaseVersion); - if (!fileIdsFile.open(DataFile::Write)) { - error("Can't save file ids: %s", fileIdsFile.error().constData()); - return false; - } - Flags flags; - if (Sandbox::hasRoot()) - flags |= HasSandboxRoot; - - fileIdsFile << flags << Sandbox::encoded(Location::pathsToIds()); - - if (!fileIdsFile.flush()) { - error("Can't save file ids: %s", fileIdsFile.error().constData()); - return false; - } - - mLastFileId = lastId; - return true; -} - -void Server::removeSocketFile() -{ -#ifdef RTAGS_HAS_LAUNCHD - if (mOptions.options & Launchd) { - return; - } -#endif - - if (getenv("LISTEN_FDS")) { - return; - } - - Path::rm(mOptions.socketFile); -} - -void Server::stopServers() -{ - removeSocketFile(); - - mUnixServer.reset(); -} - -void Server::codeCompleteAt(const std::shared_ptr &query, const std::shared_ptr &conn) -{ - const Location loc = query->location(Location::CreateLocation); - std::shared_ptr project = projectForQuery(query); - if (!project) { - error("No project found for %s", loc.path().constData()); - conn->finish(); - return; - } - const uint32_t fileId = loc.fileId(); - Source source = project->source(fileId, query->buildIndex()); - if (source.isNull()) { - const Set deps = project->dependencies(fileId, Project::DependsOnArg); - if (mCompletionThread) - source = mCompletionThread->findSource(deps); - - if (source.isNull()) { - for (uint32_t dep : deps) { - source = project->source(dep, query->buildIndex()); - if (!source.isNull()) - break; - } - } - - if (source.isNull()) { - error("No source found for %s", loc.path().constData()); - conn->finish(); - return; - } - } - - if (query->flags() & QueryMessage::CodeCompleteIncludes) { - project->includeCompletions(query->flags(), conn, std::move(source)); - conn->finish(); - return; - } - - if (!mCompletionThread) { - mCompletionThread = new CompletionThread(mOptions.completionCacheSize); - mCompletionThread->start(); - } - - std::shared_ptr c = conn; - if (!(query->flags() & QueryMessage::SynchronousCompletions)) { - c->finish(); - c.reset(); - } - Flags flags; - if (query->flags() & QueryMessage::Elisp) - flags |= CompletionThread::Elisp; - if (query->flags() & QueryMessage::JSON) - flags |= CompletionThread::JSON; - if (query->flags() & QueryMessage::XML) - flags |= CompletionThread::XML; - if (query->flags() & QueryMessage::CodeCompleteIncludeMacros) - flags |= CompletionThread::IncludeMacros; - if (query->flags() & QueryMessage::CodeCompleteNoWait) - flags |= CompletionThread::NoWait; - mCompletionThread->completeAt(std::move(source), loc, flags, query->unsavedFiles().value(loc.path()), query->codeCompletePrefix(), c); -} - -void Server::dumpJobs(const std::shared_ptr &conn) -{ - mJobScheduler->dump(conn); -} - -class TestConnection -{ -public: - TestConnection(const Path &workingDirectory) - : mConnection(Connection::create(RClient::NumOptions)), - mIsFinished(false), mWorkingDirectory(workingDirectory) - { - mConnection->aboutToSend().connect([this](const std::shared_ptr &, const Message *message) { - if (message->messageId() == Message::FinishMessageId) { - mIsFinished = true; - } else if (message->messageId() == Message::ResponseId) { - String response = reinterpret_cast(message)->data(); - if (response.startsWith(mWorkingDirectory)) { - response.remove(0, mWorkingDirectory.size()); - } - mOutput.append(response); - } - }); - } - List output() const { return mOutput; } - bool isFinished() const { return mIsFinished; } - std::shared_ptr connection() const { return mConnection; } -private: - std::shared_ptr mConnection; - bool mIsFinished; - List mOutput; - const Path mWorkingDirectory; -}; - -bool Server::runTests() -{ - assert(!mOptions.tests.isEmpty()); - bool ret = true; - int sourceCount = 0; - mIndexDataMessageReceived.connect([&sourceCount]() { - // error() << "Got a finish" << sourceCount; - assert(sourceCount > 0); - if (!--sourceCount) { - EventLoop::eventLoop()->quit(); - } - }); - for (const auto &file : mOptions.tests) { - const String fileContents = file.readAll(); - if (fileContents.isEmpty()) { - error() << "Failed to open file" << file; - ret = false; - continue; - } - bool ok = true; - const Value value = Value::fromJSON(fileContents, &ok); - warning() << "parsed json" << value.type() << fileContents.size(); - if (!ok || !value.isMap()) { - error() << "Failed to parse json" << file << ok << value.type() << value; - ret = false; - continue; - } - const List tests = value.operator[] >("tests"); - if (tests.isEmpty()) { - error() << "Invalid test" << file; - ret = false; - continue; - } - const List sources = value.operator[] >("sources"); - if (sources.isEmpty()) { - error() << "Invalid test" << file; - ret = false; - continue; - } - warning() << sources.size() << "sources and" << tests.size() << "tests"; - const Path workingDirectory = file.parentDir(); - const Path projectRoot = RTags::findProjectRoot(workingDirectory, RTags::SourceRoot); - if (projectRoot.isEmpty()) { - error() << "Can't find project root" << workingDirectory; - ret = false; - continue; - } - IndexParseData data; - data.environment = mEnvironment; - for (const auto &source : sources) { - if (!source.isString()) { - error() << "Invalid source" << source; - ret = false; - continue; - } - data.project = workingDirectory; - String commands = "clang " + source.convert(); - if (!parse(data, std::move(commands), workingDirectory)) { - error() << "Failed to index" << ("clang " + source.convert()) << workingDirectory; - ret = false; - continue; - } - ++sourceCount; - } - EventLoop::eventLoop()->exec(mOptions.testTimeout); - if (sourceCount) { - error() << "Timed out waiting for sources to compile"; - sourceCount = 0; - ret = false; - continue; - } - - int passes = 0; - int failures = 0; - int idx = -1; - for (const auto &test : tests) { - ++idx; - if (!test.isMap()) { - error() << "Invalid test" << test.type(); - ret = false; - continue; - } - const String type = test.operator[]("type"); - if (type.isEmpty()) { - error() << "Invalid test. No type"; - ret = false; - continue; - } - std::shared_ptr query; - if (type == "follow-location") { - String location = Location::encode(test.operator[]("location"), workingDirectory); - if (location.isEmpty()) { - error() << "Invalid test. Invalid location"; - ret = false; - continue; - } - query.reset(new QueryMessage(QueryMessage::FollowLocation)); - query->setQuery(std::move(location)); - } else if (type == "references") { - String location = Location::encode(test.operator[]("location"), workingDirectory); - if (location.isEmpty()) { - error() << "Invalid test. Invalid location"; - ret = false; - continue; - } - query.reset(new QueryMessage(QueryMessage::ReferencesLocation)); - query->setQuery(std::move(location)); - } else if (type == "references-name") { - String name = test.operator[]("name"); - if (name.isEmpty()) { - error() << "Invalid test. Invalid name"; - ret = false; - continue; - } - query.reset(new QueryMessage(QueryMessage::ReferencesLocation)); - query->setQuery(std::move(name)); - } else { - error() << "Unknown test" << type; - ret = false; - continue; - } - const List flags = test.operator[] >("flags"); - for (const auto &flag : flags) { - if (!flag.isString()) { - error() << "Invalid flag"; - ret = false; - } else { - const QueryMessage::Flag f = QueryMessage::flagFromString(flag.convert()); - if (f == QueryMessage::NoFlag) { - error() << "Invalid flag"; - ret = false; - continue; - } - query->setFlag(f); - } - } - - TestConnection conn(workingDirectory); - query->setFlag(QueryMessage::SilentQuery); - handleQueryMessage(query, conn.connection()); - if (!conn.isFinished()) { - error() << "Query failed"; - ret = false; - continue; - } - - const Value out = test["output"]; - if (!out.isList()) { - error() << "Invalid output"; - ret = false; - continue; - } - List output; - for (auto it=out.listBegin(); it != out.listEnd(); ++it) { - if (!it->isString()) { - error() << "Invalid output"; - ret = false; - continue; - } - output.append(it->convert()); - } - if (output != conn.output()) { - error() << "Test" << idx << "failed. Expected:"; - error() << output; - error() << "Got:"; - error() << conn.output(); - ret = false; - ++failures; - } else { - warning() << "Test passed"; - ++passes; - } - } - error() << passes << "passes" << failures << "failures" << (tests.size() - failures - passes) << "invalid"; - } - - return ret; -} - -void Server::prepareCompletion(const std::shared_ptr &query, uint32_t fileId, const std::shared_ptr &project) -{ - if (query->flags() & QueryMessage::CodeCompletionEnabled && !mCompletionThread) { - mCompletionThread = new CompletionThread(mOptions.completionCacheSize); - mCompletionThread->start(); - } - - if (mCompletionThread && fileId) { - if (!mCompletionThread->isCached(fileId, project)) { - Source source = project->source(fileId, query->buildIndex()); - if (source.isNull()) { - for (const uint32_t dep : project->dependencies(fileId, Project::DependsOnArg)) { - source = project->source(dep, query->buildIndex()); - if (!source.isNull()) - break; - } - } - - if (!source.isNull()) - mCompletionThread->prepare(std::move(source), query->unsavedFiles().value(Location::path(fileId))); - } - } -} - -void Server::filterBlockedArguments(Source &source) -{ - for (const String &blocked : mOptions.blockedArguments) { - if (blocked.endsWith("=")) { - size_t i = 0; - while (i. */ - -#ifndef Server_h -#define Server_h - -#include "IndexMessage.h" -#include "rct/Flags.h" -#include "rct/Hash.h" -#include "rct/List.h" -#include "rct/SocketServer.h" -#include "rct/String.h" -#include "rct/Thread.h" -#include "Source.h" -#include "RTags.h" -#ifdef OS_Darwin -#include -#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 -#include -#define RTAGS_HAS_LAUNCHD -#endif -#endif - -class Match; -class CompletionThread; -class Connection; -class ErrorMessage; -class IndexDataMessage; -class QueryJob; -class LogOutputMessage; -class Message; -class OutputMessage; -class Project; -class QueryMessage; -class VisitFileMessage; -class JobScheduler; -class IndexParseData; -class Server -{ -public: - Server(); - ~Server(); - static Server *instance() { return sInstance; } - enum Option { - NoOptions = 0x0, - ClearProjects = (1ull << 1), - Wall = (1ull << 2), - IgnorePrintfFixits = (1ull << 3), - SpellChecking = (1ull << 4), - AllowMultipleSources = (1ull << 5), - NoStartupCurrentProject = (1ull << 6), - WatchSystemPaths = (1ull << 7), - NoFileManagerWatch = (1ull << 8), - NoFileSystemWatch = (1ull << 9), - NoNoUnknownWarningsOption = (1ull << 10), - SuspendRPOnCrash = (1ull << 11), - SeparateDebugAndRelease = (1ull << 12), - AllowPedantic = (1ull << 13), - StartSuspended = (1ull << 14), - EnableCompilerManager = (1ull << 15), - EnableNDEBUG = (1ull << 16), - Progress = (1ull << 17), - Weverything = (1ull << 18), - NoComments = (1ull << 19), - Launchd = (1ull << 20), - RPLogToSyslog = (1ull << 21), - CompletionsNoFilter = (1ull << 22), - WatchSourcesOnly = (1ull << 23), - NoFileLock = (1ull << 24), - PCHEnabled = (1ull << 25), - NoFileManager = (1ull << 26), - ValidateFileMaps = (1ull << 27), - CompletionLogs = (1ull << 28), - AllowWErrorAndWFatalErrors = (1ull << 29), - NoRealPath = (1ull << 30), - Separate32BitAnd64Bit = (1ull << 31), - SourceIgnoreIncludePathDifferencesInUsr = (1ull << 32), - NoLibClangIncludePath = (1ull << 33), - TranslationUnitCache = (1ull << 34) - }; - struct Options { - Options() - : jobCount(0), headerErrorJobCount(0), maxIncludeCompletionDepth(0), - rpVisitFileTimeout(0), rpIndexDataMessageTimeout(0), rpConnectTimeout(0), - rpConnectAttempts(0), rpNiceValue(0), maxCrashCount(0), - completionCacheSize(0), testTimeout(60 * 1000 * 5), - maxFileMapScopeCacheSize(512), pollTimer(0), maxSocketWriteBufferSize(0), - tcpPort(0) - { - } - - Path socketFile, dataDir, argTransform, rp, sandboxRoot; - Flags